Buffalo WSR-1166DHP に OpenWrt をインストールしたときのメモ

![00_OpenWRT_LogoLuci.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3699150/229a77b3-1b4f-4f78-b32f-66ecd5703daa.png)

:::note alert
**【警告】**
このページで紹介している代替ファームウェア OpenWrt はよくわかっていない素人がおいそれと手を出していいものではない。生半可な理解ではデバイスをダメにしてしまう危険があるばかりか、法律に抵触してしまう恐れもある。このページで紹介している内容だけを鵜呑みにせず、 OpenWrt 公式サイトを始め、あちこちのサイトで学ぶ時間が必要になる。こういった努力を惜しまず、完全に理解できた方のみ着手してほしい。でなければ行うべきではない。
万一、本記事によって不具合・不利益が生じた場合も当方は一切責任を負わない。すべて自己責任でお願いする。
:::



**🕒 この記事を読むのに必要な時間 🕒**
全文：おおよそ60分

**📜 必要な知識 📜**
Linuxコマンドライン操作: 中級以上
Linuxに関する知識： 中級以上
フラッシュメモリに関する知識： 中級以上
組み込み開発に関する知識： 初級以上

**💻 実行環境 💻**
OS: Arch Linux x86_64
Kernel: 6.13.6-arch1-1
Shell: bash 5.2.37
DE: Xfce 4.20
WM: Xfwm4
Terminal: xfce4-terminal
Package: firefox 136.0-1, iputils 20240905-1, iproute2 6.13.0-1, tftp-hpa 5.2-10, wireshark-qt 4.4.5-1, openssh 9.9p2-1, bc 1.08.1-1


🔶 概要
=======

Buffalo WSR-1166DHP は 2015〜2024 まで実家で使っていた Wi-Fi ルーター。
地元のケーブルテレビ会社提供のインターネット・モデムとの接続に使っていたもので、ケーブルテレビ会社からセット販売されたものだ。
2024冬に LED ランプの一番下 ROUTER がなぜかオレンジ色になってしまう（それまでは常時緑色に点灯）という故障の仕方をしたため、大事を取って引き上げてきた。他の機能的には別段問題はなかった。

今回は これをいじって OpenWrt を入れてみたい。

なお、本記事は失敗記録も載せ、俺ちゃんのエモーショナルな独り言を含むので非常に冗長になっている。これからインストールする際に参考にするには少々ヘビーなので覚悟せよ。読むのが面倒なら、別のサイトを見てうまくいかなかったときなどに参考としてほしい。

当ページの制作方針は **「<font color=red>どこよりも詳しく。</font>しかし <font color=red>どこよりも面倒くさく。</font>」** とする。
$\tiny{一応 初心者向けには書いている。...つもり。}$

🔶 HW仕様
=========

メーカー公式ホームページは以下。

:::note info
**【参考】**[WSR-1166DHP _ Wi-Fiルーター _ AirStation _ バッファロー](https://www.buffalo.jp/product/detail/wsr-1166dhp.html)
:::

当然だが、ここには表向きのことしか書いていない。

以下のサイトに内部仕様的な詳細なスペックが書いてあった。
最後の OpenWrt Wiki が公式なのでおすすめだ。

:::note info
**【参考】**[WSR-1166DHP - DD-WRT OpenWrt 適材適所で両方使いたい人向け @ ウィキ - atwiki（アットウィキ）](https://w.atwiki.jp/ddwrt_openwrt/pages/102.html)

**【参考】**[Buffalo WSR-1166DHP - WikiDevi.Wi-Cat.RU](https://wikidevi.wi-cat.ru/Buffalo_WSR-1166DHP)

**【参考】**[Buffalo WSR-1166DHP - TechInfoDepot](https://en.techinfodepot.shoutwiki.com/wiki/Buffalo_WSR-1166DHP)

**【参考】**[\[OpenWrt Wiki\] Techdata_ Buffalo WSR-1166DHP](https://openwrt.org/toh/hwdata/buffalo/buffalo_wsr-1166dhp)
:::

要点のみ抜粋して、俺ちゃんが分かりやすいフォーマットに変形する。

	=========== =========================================
	SPEC		VALUE
	=========== =========================================
	SoC:		MediaTek MT7621AT(?)
	CPU:		MediaTek MT7621A
	Frequency:	880 MHz, Dual-Core
	RAM:		128 MB, DDR3-1600
	Flash:		16 MB, SPI
	Ethernet:	4x LAN, 1x WAN
	Wireless:	MT7612E a/n/ac 866Mbps, MT7603E b/g/n 300 Mbps
	USB:		-NONE-
	Serial:		yes, internal, 4-pin header
	JTAG:		yes, internal, 14-pin header
	Bootloader:	U-Boot
	PowerSup.:	12 VDC, 1.5 A
    On-Sale:	2014-09
	=========== =========================================

CPU は MIPS 1004Kc アーキテクチャ。SoC 内蔵。2 コア。
USBポート は無い。

128MB とまあまあの容量の RAM を持つ。それに対して フラッシュメモリの容量が少ないのが玉に瑕か。CPU も速度はともかく Dual Core である。悪くはない。
ブートローダーは U-Boot 。
2014発売と、古い。


🔶 参考資料
===========

WSR-1166DHP は OpenWrt が比較的すんなり入る機種らしい。
公式でもサポートされているし、販売数が多いので中古にも出回りやすく、いろいろな人がインストールに成功している。
これらの方々が書いた記事を参考にさせてもらった。先人たちに<INS>最大限の謝辞を表明</INS>。感謝。

以下、俺ちゃんの解説コメント付きでリンクを紹介しておこう。


:::note info
**【参考】**[WSR-1166DHP2にOpenWrtを入れる方法_ okoyaの私的メモ](https://okoya.seesaa.net/article/460490117.html)

基本的にこのサイトが一番古いが、詳しい。ただし、「わかっている人」向け。 OpenWrt のフォーラムから転載してきたことと、この Okoya氏が達人級の代替ファームウェア使いなので専門用語等が多く、予備知識がない素人には多少難しいかな。まあ OpenWrt を入れようと思う時点で一般人ではないからなんともだが…。
:::


:::note info
**【参考】**[WSR-1166DHPにDD-WRTを適用する_ okoyaの私的メモ](https://okoya.seesaa.net/article/442415205.html)

上記は OpenWrt ではなくて同系の代替ファームウェア DD-WRT の特殊なメーカーカスタム・バージョン nxt をインストールする記事だが、基板の写真があるため 分解[^1] してシリアル接続する際には参考になることだろう。今回はやらないけども。
:::

[^1]: 本体ケースのみを取り外し基板をあらわにすること。俗に "殻割り" という。分解ではあるが、全部バラすわけではないためこう呼ばれる。多くは基板へ シリアルケーブル(e.g. USB2TTL, USB2UART) を接続して、ファーウェア書き換えや復旧などを行う目的で利用される。

:::note info
**【参考】**[WSR-1166DHP2 Openwrt導入方法_ タブレット](https://kobahiro10.seesaa.net/article/481333175.html)

Windows ユーザーなら上記がスクリーンショット付きで詳しい。
綺麗にまとまっている。やっていることは Okoya氏の内容＋αであるが。初心者向け。 MTDバックアップも紹介しているのは良いが、復旧方法までは載せていないのはちょっと残念ではある。今回の記事で試すにあたり、一番基本として参考にさせていただいたのはこの記事だった。読みやすいから！…俺ちゃんは Windoze 使いじゃないけどネ。
:::

:::note info
**【参考】**[WSR-1166DHS2へのOpenWrt導入①（インストール編） _ 子育てパパのワークライフバランス](https://rmwlbpapa.com/it/openwrt/)

上記の似たような記事。 ...と思っていたけど、嘘でした。
実は ver.17.01.04 じゃないと動かないと各所で書かれていた initramfs を最新版でも動くと報告してくれていた貴重な情報源だった。ありがとう。このログの後の方で それに気づいて役に立ちましたよ。
タイトル含め、誤字がちょっと気になるが。s/DHS/DHP/g だゾ。
②と題した追いかけ記事でリカバリ手順を記載しているのでそっちも役に立ちそう。
:::


最後に、最も参考にすべきなのは公式サイトだ。当然英語だが、各種の貴重な情報が詰まっている。むしろ技術屋としては、このサイトを見て勉強したいがために OpenWrt をインストールして試す価値がある！とも言えるくらい、重要。汝、知を探求せよ。

例えばルーターのストレージである、フラッシュメモリに関する知識は以下で詳しく解説されている。

:::note info
**【参考】**[\[OpenWrt Wiki\] Flash memory](https://openwrt.org/docs/techref/flash)
:::

MTDバックアップの際には以下のページが参考になる。

:::note info
**【参考】**[\[OpenWrt Wiki\] Generic NOR backup](https://openwrt.org/docs/guide-user/installation/generic.backup)
:::

メーカー純正ファームウェアに戻す方法は以下。

:::note info
**【参考】**[\[OpenWrt Wiki\] Back to original firmware](https://openwrt.org/docs/guide-user/installation/generic.uninstall)
:::

他にも このサイトのページ＆フォーラムは宝の山だ！
DD-WRT を別の機種に入れたときにも大変お世話になった。


🔶 ダウンロード
===============

### 🔵 メモリ上に展開する initramfs をダウンロード

OpenWrt のファームウェアにはいくつかタイプがある。その内、ストレージ（というより、ルータ等のファームウェアの場合にはフラッシュ・メモリ）に **インストールせずに RAM 上に展開する** のが **`initramfs`** と呼ばれる種類のイメージ・ファイルである。

これは Linux に於いて、ブートローダーの次に最初にカーネル・イメージをロードする最小構成の Linux システムのこと。大抵の Linux ディストリビューションではこの initramfs をはじめにロードしてから、いろいろと下準備をして initd や systemd などの本格的なシステムの起動をするという二段階の手順を踏んで起動する。（ブートローダーも含めれば 3段階だが… いや、それを言ったら BIOS/UEFI も含めて 4段階か。 PC では）

OpenWrt でもこの仕組みは便利なので使われる。
なぜなら、正攻法ではメーカー謹製ファームウェア以外は書き込めないように暗号化や検査の仕組みが施されていてフラッシュ・メモリに書き込めなかったりするためだ。メーカーの提供している方法でいきなり OpenWrt を書き込もうとすると、うまくいかないことが多い。だが、一時的にメモリ上に展開して動作できる initramfs ならばこのような制限を迂回して動作させることができ、そこから本来使いたい代替ファームウェアをフラッシュ・メモリに書き込むことができる。このような行為を日本では「**踏み台**」と称する事が多い。なんとも Hack チックな呼び方で、素敵だな。うむ。

なお `initramfs` はメインメモリ(RAM)上に展開されるのみなので、当然ながら **再起動すると消えてしまう**。フラッシュメモリに入っているファームウェア… つまり元のメーカー製ファームウェアが起動してくるだろう。

</br></br>
…前置きが長くなったが、 WSR-1166DHP で使用可能な `initramfs` は ver.17.01.4 だけのようだ。理由はよくわからないが、達人 Okoya氏のサイトによれば最新の版で試すと失敗したひとが居たらしい。
殻割り[^1] してシリアル接続し、 U-Boot コンソール上からログを見れば、失敗時に何が起きているかわかるだろうが…。まあ、今回はいいや。めんどいから。
ってことで、素直に使えるバージョンをダウンロードする。以下。

:::note info
**【参考】**[Index of _releases_17.01.4_targets_ramips_mt7621_](http://downloads.openwrt.org/releases/17.01.4/targets/ramips/mt7621/)
:::

"wsr-1166-initramfs-kernel.bin" をクリックしてダウンロードを開始すると、 `lede-17.01.4-ramips-mt7621-wsr-1166-initramfs-kernel.bin` がダウンロードされる。


### 🔵 最新版の OpenWrt をダウンロード

公式でサポートされている機種ならば最新版は OpenWrt Wiki にある機種の紹介ページからたどるのが簡単だ。
以下のページにアクセスして "Sysupgrade image" の方をダウンロードする。

:::note info
**【参考】**[\[OpenWrt Wiki\] Buffalo WSR-1166DHP](https://openwrt.org/toh/buffalo/wsr-1166dhp)
:::

`openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-squashfs-sysupgrade.bin` のような長い名前のファイルがダウンロードされるはずだ。
このページからたどれば常に最新版のリンクになっているので、きっと君がダウンロードするときにはバージョンは上がっているだろう。以降その部分は読み替えてほしい。

因みに "Sysupgrade image" とは「アップグレード用のファームウェア・イメージ」という意味である。OpenWrt でのアップグレードに使うコマンド名が sysupgrade なのでこのような名前が付いている。

一方、 "Factory image"[^2] の方は使えないという噂の最新版の initramfs である。 `openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-initramfs-kernel.bin` というようなファイル名になっている。
一応、使わない予定だけど、こちらもダウンロードしておいた。

[^2]: 本来はこの "Factory" の意味は "工場出荷時" のこと。言い換えると「メーカー純正ファームウェアからアップグレード時に使うバージョン」という意味。対応機種によっては Webインターフェイス からアップグレードできるものもあるし、今回のように TFTP 等でしかアップできないものもある。また、今回は initramfs だったが、必ずしもそうとも限らない。直接フラッシュメモリに書き換え可能なイメージファイルの場合もある。(e.g. <機種名>-squashfs-factory.bin みたいなファイル名のやつ)

:::note info
**【後日追記】**
これが役に立った。というか、普通に使えた。以下のログを読んでもらえば分かるが、 ver.17.01.4 よりこちらでトライする方がいい。
:::


🔶 まずは純正FWをダウングレードしてデバッグモードに入れないか試す→失敗
=======================================================================

### 🔵 おや？純正FWの昔のバージョンがダウンロードできるよ？

Buffalo の公式ページを見ると、ファームウェア(※以降たびたび FW と省略) の旧バージョンで 2016 以前のものがダウンロードできるようになっていた。

:::note info
**【参考】**[WSR-1166DHPシリーズ ファームウェア \(Windows\) _ ダウンロード _ バッファロー](https://www.buffalo.jp/support/download/detail/?dl_contents_id=61688)
:::

Buffalo ファームウェアの古いバージョンには Webインターフェイス で *ゴニョゴニョ* すると、隠された **デバッグモード** に入れたりするものがある。他の機種では確かそれが 2016 くらいに出たファームウェアまでだった気がする。
2016-01-07 に出た ver.1.09 にダウングレードできれば、もしかするとこのデバッグモードが使えるかもしれない。通常、できない telnet 接続ができるようになり、普通はファームウェア・バイナリファイルの正当性検査が入る Webインターフェイスの機構をすり抜けて直にアップロードして上書きができる、みたいなモード。これができれば苦労はない。
（バックドア… とか言ってはいけない。*ええい！言うなってば！*）

…既に誰かが試しているだろうし、成功報告がないので期待薄だが。
まあ、そんな手間でもないのでやってみるか。


### 🔵 純正FWのWebインターフェイスへログイン

LANケーブルを PC と WSR-1166DHP の LAN1 端子に接続する。他の端子には何も繋がないこと。Wi-Fi も OFFにしておくほうが無難。Webインターフェイスを Webブラウザ Firefox で開く。
デフォルトでは以下のURL。

[http://192.168.11.1/](http://192.168.11.1/)

Windows/Mac や Avahi デーモンが動いている Linux などなら代わりに以下の URL でも起動するはずだ。

[http://web.setup/](http://web.setup/)

デフォルトでは以下の認証情報になっている。

	ユーザー名: admin
	パスワード: password

変えている場合は思い出そう。中古で入手して、パスワード がわからない場合などは一度 WSR-1166DHP 本体の電源を切ってから、本体底面のリセットボタンを爪楊枝などの細い棒を突っ込んで押しながら電源を入れ直せば初期化されるはずだ。詳しくは Buffalo サイトから説明書をダウンロードして参照すること。


### 🔵 ダウングレード実行

ログインできたら、 **[詳細設定] ＞ [管理] ＞ [ファームウェア更新]** とボタンを押していって目的のファームウェアを解凍したものを選択してダウングレードする。今回の場合は `wsr1166dhp_jp_109` という名前の 7.6MB のファイルだ。
実行には 3分弱かかる。
待ったあと、Webブラウザは一度再起動しておくこと。

ファームウェアが更新されたら、以下の URI と認証情報を使ってログインする。

	URI: http://192.168.11.1/cgi-bin/cgi?req=frm&frm=py-db/55debug.html
	ユーザー名: bufpy
	パスワード: otdpopypassword
    （※ デフォルトでは。パスワードを変えている場合は otdpopy + <YOUR_PASSWORD> ）

…だが、うまくいかなかった。
**「パスワードが間違っています。」** と怒られてしまう。。

この後 ユーザー名, パスワード を変えたり、 ver.1.03 にダウングレードしてみたり、PC 側のIPアドレスを 192.168.11.10 に変更してみたりもしたが、いずれもダメだった。
bufpy ユーザー自体が無いか、パスワードが違うか、無効化されているようだ。…残念。

ってことでこの方法は諦めた。


🔶 AOSS回復法で initramfs を入れてみる
======================================

### 🔵 AOSS回復法とはなんぞや？

Buffalo 社製のブロードバンド・ルーターには `AOSSボタン` を長押ししながら電源を投入すると、直後に1回だけ `192.168.11.2` の固定IPアドレスに対して TFTP 接続を試みてリカバリー用のファームウェアが無いか見に行くという素敵な隠し仕様が存在する。俗に「**AOSS回復法**」[^3] などと呼ばれている方法だ。

![AOSS_Button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3699150/e0a2d960-a30c-4417-86a6-94796440c0bf.png)

こういう隠し仕様やらデバッグモードやら仕込むから好きなんだよ、Buffalo♡
お願いだから、そのままの君でいてくれ。

[^3]: 英語では "`TFTP recovery flash`"。 `AOSSボタン` は Buffalo 独自のボタンなので他の機種では WPS ボタンだったり他のボタンだったりするが、似たような手順でファームウェアを TFTP で流し込む手段が実装されていることが多い。

これを使ってダウンロードしておいた OpenWrt の initramfs ファイルを入れる。いわゆる踏み台の作成だ。

ちなみに、
素人は TFTP のことを「 **FTP と同じじゃね？**」と思いがちだが、<font color=red>**違う**</font>。
"Trivial File Transfer Protocol" の略で、一般的な FTP との間に互換性はない。 TFTP が使えるサーバー・ソフトウェアを用意しなければダメだ。


### 🔵 TFTPサーバーのインストールと起動 on Linux

以下の作業は俺ちゃんは PC にインストールしてある `Arch Linux` 上で行った。もし他のディストリビューションや OS を使っている場合は適宜読み替えること。

<dl>
<dt>(1) まず tftp-hpa パッケージを pacman でインストール。</dt>
<dd>ターミナルで以下のようにする。

    $ sudo pacman -S tftp-hpa

`/srv/tftp` ディレクトリができているので、上記で予めダウンロードしておいた `initramfs` ファイルを置く。

	$ mv lede-17.01.4-ramips-mt7621-wsr-1166-initramfs-kernel.bin /srv/tftp/

これは **`linux.trx-recovery`** にリネームしておく。リネームの代わりにシンボリックリンクで指し示すようにしてもいい。以下にその例を示す。

	$ ln -s lede-17.01.4-ramips-mt7621-wsr-1166-initramfs-kernel.bin  linux.trx-recovery
	$ ls -l
	-rw-r--r-- 1 9hnder deadpool 3698273  3月  9 23:07 lede-17.01.4-ramips-mt7621-wsr-1166-initramfs-kernel.bin
	lrwxrwxrwx 1 9hnder deadpool      56  3月 11 00:02 linux.trx-recovery -> lede-17.01.4-ramips-mt7621-wsr-1166-initramfs-kernel.bin
	$ 
</dd>

<dt>(2) TFTP サーバーを起動する。</dt>
<dd>これには、

    $ sudo systemctl start tftpd.service

とすれば OK。

    $ systemctl status tftpd.service

で動作を確認できる。
</dd>
<dt>(3) ファイアウォールを OFF にする。</dt>
<dd>例えば ufw を使っているなら、

    $ sudo ufw disable

とする。
「OFF にしたくねーよ！」というセキュリティ *意識高い系の人* は、 LAN側の TFTP ポート(Default: 69)と SSH のポート(Default: 22)の接続を解放しておくこと。そこまでは解説しないので、自分の環境に合わせて好きにやってくれ。
</dd>
<dt>(4) ip コマンドで空きの LANポート(e.g. eth0) に静的IPアドレスを設定しておく。</dt>
<dd>以下のようにする。
    
	$ sudo ip link set eth0 down
	$ sudo ip address add 192.168.11.2/24 broadcast 192.168.11.255 dev eth0
	$ sudo ip address add 192.168.1.2/24  broadcast 192.168.1.255  dev eth0
	$ ip address show dev eth0
	$ sudo ip link set eth0 up

eth0 は筆者の環境のデバイス名なので、適宜読み替えること。
Linux では静的IPアドレスを 2 つ割り当てることができる。`192.168.11.2/24` は `AOSSボタン` を押した際に、ルーターが TFTP でアクセスするアドレス。（つまり Buffalo の仕様による IPv4アドレス）
`192.168.1.2/24` は TFTP で転送が正常に完了して `initramfs` が起動した後に繋がるようになるアドレス。（つまり OpenWrt の仕様による IPv4アドレス）
</dd>
<dt>(5) LAN ケーブルで PC と WSR-1166DHP を接続する。</dt>
<dd>WSR-1166DHP 側の LAN ポートはどこでもいいと思う。ただし、青色の WANポートはやめておくこと。俺ちゃんはいつも LAN 1 にしている。

なお、古いサイトではスイッチング HUB を間にかますように書いてあったりするが必要ない。これは昔 PC 同士を接続するためには HUB で接続するか、LAN のクロスケーブルが必要であったためなのだが、最近の LAN機器 には使用中の LANケーブル 自動判別機能（AutoMDI/MDI-X）が搭載されており、クロスでもストレートでも、どちらのケーブルを使っても上手く判別して機能してくれるためである。便利だ。

また、Wi-Fi は OFF にしておくのが無難だし、別のイーサネット・ケーブルなどが繋がっている場合も外しておくのが無難。特に同じ Buffalo 製の別のルーターを使っていたりすると、IPv4 アドレスの範囲が被っているのでうまくいかない原因となる。
</dd>
<dt>(6) もし Wireshark をインストールしている場合は管理者権限(sudo)で起動する</dt>
<dd>イーサネット・デバイスの監視を開始する。(e.g. eth0)
Wireshark は奥が深い。解説しだすと長くなってしまうのでここでは解説しない。基本成功していたら使う必要はないので、失敗した時だけ調べて試すようにするだけでよいだろう。
</dd>
<br>
<dt>(7) ルーターの AOSSボタン を押しっぱなしにしたまま、電源ボタンを押す。</dt>
<dd>5 秒程度したら転送が開始されるので、そうしたら離していい。 Wireshark を入れているならパケットキャプチャで以下のようになるので転送開始されたか確認が可能。入れていない人も 10秒も押しておけば充分転送は開始されるので問題ないだろう。
うまくいった場合は 12 秒くらい経ってから [POWER] LEDランプがしばらく点滅した後に常時点灯状態に移行する。他のランプは消えたまま。これで起動完了。2分くらいかな。うまくいかない場合はファイル名やパスなどに間違いがないか、 tfpd.service がちゃんと動作しているかを確認すること。
    
![01_TftpWiresharkCapture1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3699150/defe16d2-c12f-4bcc-844f-c52d22bde856.png)

</dd>
<dt>(8) ターミナルで ping を打ってみる。</dt>
<dd>応答があればまず間違いなく起動している。

    $ ping 192.168.1.1

また、Webブラウザで  http://192.168.1.1/  を開いてみると以下のようなログイン画面が表示されるはずだ。

![05_InitramfsOpenWrt_Firefox2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3699150/54e76f46-e0fa-496d-a98d-b1e6ea178706.png)

</dd>
</dl>


### 🔵 SSH で initramfs にログインする

:::note info
以下では SSH で CLI を使ってやっているが、 **めんどい** って人は Web管理画面(WebUI) からでも MTDバックアップが可能だそうだ。以下のコメント欄で Bacalhau さんが教えてくださっている通りに行えば良い。
[報告 2. mtd3-のバックアップと sysupgrade の書き込みについて](https://qiita.com/9hnder/items/35e0cbfb3dc9828d8852#報告-2-mtd3-のバックアップと-sysupgrade-の書き込みについて)
:::

`initramfs` の `踏み台OpenWrt` が無事に起動したら、SSH で接続する。
ターミナルを起動して以下のコマンドでログインする。

```console
	$ ssh root@192.168.1.1
```

このとき、Arch Linux では以下のようなエラーメッセージが表示された。

	Unable to negotiate with 192.168.1.1 port 22: no matching host key type found. Their offer: ssh-rsa

これは initramfs の OpenWrt バージョンが 17.01.4 と古いが故に起きる。要求されているのは `ssh-rsa` という方式。これは公開鍵暗号における署名なのだが、`SHA-1` という 2025年現在では既に古く問題のあるハッシュ・アルゴリズムが使用されてしまっており、**2020年以降は非推奨となっている** のだ。 `Arch Linux` でも当然これはデフォルトで使えなくしてある。
古いホストに SSH するには、これを有効化してやる必要がある。もちろん、その古いホストのみで一時的に。SSH コマンドを次のように変更する。

```console
	$ ssh -oHostKeyAlgorithms=+ssh-rsa  root@192.168.1.1
```

これは `HostKeyAlgorithms` というオプションに `ssh-rsa` を追加してやって SSH するように指定している。一時的に鍵のアルゴリズム `ssh-rsa` を追加するという意味。

`SHA-1` や `ssh-rsa` 非推奨あたりの詳細は以下で知ることができる。

:::note info
**【参考】**[OpenSSH Release Note ver.8.8](https://www.openssh.com/txt/release-8.8)
:::


### 🔵 SSH でログインしたら色々調査しておく。MTD バックアップも作る

![07_ssh2Initramfs.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3699150/5f701b6b-49c1-4ad1-81ef-d9720ad31cf2.png)

組み込みIOT界隈で人気のある、 **よく利用する基本コマンドを一つに集め容量を節約したプログラム `busybox`** が入っているので一通りの基本コマンド類は使える。dmesg, mount, df, ps, ls などのコマンドを使って色々調査しておくとよいだろう。その時のターミナル出力はログとして保存しておくと後から見直すことができて便利だ。

あとは **メーカー純正ファームウェアのバックアップ** である。
読者の中には「ファームウェア・イメージだけなら Buffalo からいつでもダウンロードできるんじゃないの？」と思われる方もおられるだろう。が、それを展開してフラッシュメモリに転送する方法が、今度はメーカー純正FWの環境ではなくて OpenWrt な環境になる。このため方式が異なり、フォーマットも異なるのだ。

よってバックアップはあったほうがいい。また、ブートローダー(この機種に入っているのは `U-Boot` という名のブートローダー)も保存して **完全バックアップ** にしておきたい。

ルーターのストレージに当たる保存領域は MTD と呼ばれる。
HDD におけるパーティション的な存在が、フラッシュメモリでは MTD である。これは "Memory Technology Device" の略で、簡潔に言えば『**使えば使うほど確実に寿命が縮んでゆく**』厄介な特性を持つフラッシュメモリをうまく使えるようにする **Linux 特有の技術基盤** である。

この MTD の領域分割状況を `MTDレイアウト` と呼ぶ。(a.k.a. MTD list, Flash Layout)
簡易的な `MTDレイアウト` は `/proc/mtd` を見ることで表示可能。以下のようになっていた。

```console
	root@LEDE:~# cat /proc/mtd
	dev:    size   erasesize  name
	mtd0: 00030000 00010000 "u-boot"
	mtd1: 00010000 00010000 "u-boot-env"
	mtd2: 00010000 00010000 "factory"
	mtd3: 00f90000 00010000 "firmware"
	mtd4: 00020000 00010000 "board_data"
	root@LEDE:~#
```

先頭から *{ dev=デバイス名, size=領域のサイズ(16進数), erasesize=消去の際の最小サイズ, name=名前、パーティションでいうところのラベル }* となっている。

ここで `erasesize` に注目。
通常の HDD などであれば決まったブロックサイズ（4096 など）があって、特に何も気にしなくても良い場合が多い。しかし、組み込みの世界で使うフラッシュメモリは少々毛色が異なり、ブロックサイズもモノによって異なっているのだ。

MTD の場合はこの `erasesize` がブロックサイズと似た意味合いになっている。つまり、これから最適なブロックサイズを計算できる。やってみよう。
まず 16進数なので 10進数に直す。

```console
	$ echo 'obase=10; ibase=16; 00010000' | bc
	65536
	$ 
```

65536 バイトだ。
次に KiB(キビバイト) に変更したいので 1024 で割る。

```console
	$ echo 'scale=2; 65536 / 1024' | bc
	64.00
	$ 
```

64 KiB だな。
これを何に使うのかと言うと、 dd コマンドで MTD をバックアップする際に使う。 bs オプションに指定してやるのだ。 /tmp 上で行う。次のように。

```console
	root@OpenWrt:~# cd /tmp
	root@OpenWrt:/tmp# for i in 0 1 2 3 4; do dd bs=64K if=/dev/mtdblock$i of=mtd$i.dd; gzip mtd$i.dd; done
```

MTD領域 0 〜 4 をそれぞれファイルに保存して gzip 圧縮している。
dd コマンドを使う際はブロックサイズが結構重要だ。めんどいからってシカトこくと後でえらい目に合うことがある。…他のサイトでは気にしていないことが多いが。意外にも、俺ちゃんは石橋を叩いて渡る派なので、このあたりは神経質にやる。

あとはこれを手元の PC に転送しておく。
PC 側で以下の scp コマンドを使う。

```console
	$ scp -O -oHostKeyAlgorithms=+ssh-rsa  root@192.168.1.1:/tmp/mtd?.dd.gz ./
```

万一の場合はこれを使って **メーカー純正ファームウェアに復旧** させることができる。これは [本稿の最後の項目](#-おまけmtdバックアップ-を使って-メーカー純正fw-に戻すには) で解説する。ただし、俺ちゃん自身は実際には戻していないので、 **ちゃんと動くかは未検証である**。

:::note info
**【後日追記】**
動いたとの報告あり。詳しくは [コメント欄](https://qiita.com/9hnder/items/35e0cbfb3dc9828d8852#報告-1-buffalo-firmware-の書き込みについて) にて。
:::


🔶 最新の OpenWrt にアップグレードする
=================================

:::note info
以下では引き続き SSH で CLI を使ってやっているが、 **めんどい** って人は WebUI からでもアップグレードが可能だそうだ。以下のコメント欄で Bacalhau さんが教えてくださっている通りに行えば良い。
[報告 2. mtd3-のバックアップと sysupgrade の書き込みについて](https://qiita.com/9hnder/items/35e0cbfb3dc9828d8852#報告-2-mtd3-のバックアップと-sysupgrade-の書き込みについて)
:::

### 🔵 sysupgrade を実行→失敗

MTDバックアップ が終わったら、続けてアップグレードに移る。
バックアップ時とは逆に PC → ルーターへ `sysupgrade.bin` を転送する。

```console
	$ scp -O -oHostKeyAlgorithms=+ssh-rsa  openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-squashfs-sysupgrade.bin  root@192.168.1.1:/tmp/
```
そして `sysupgrade` コマンドでファームウェアを最新版の OpenWrt へアップグレードする。

```console
sysupgrade -n -v openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-squashfs-sysupgrade.bin
```

が、
以下のように怒られる。

```console
	root@LEDE:/tmp# sysupgrade -n -v openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-squashfs-sysupgrade.bin 
	Device wsr-1166 not supported by this image
	Supported devices: buffalo,wsr-1166dhp wsr-1166 - Image version mismatch: image 1.1, device 1.0. Please wipe config during upgrade (force required) or reinstall. Reason: Config cannot be migrated from swconfig to DSA
	Image check 'fwtool_check_image' failed.
	root@LEDE:/tmp#
```

むう。ミスマッチらしい。
Google翻訳で日本語訳してみると以下のようになる。（一部意訳）

>    サポートされたデバイス: buffalo,wsr-1166dhp wsr-1166 - イメージのバージョンの不一致: 1.1, デバイス 1.0. アップグレード中に設定内容(config)を一掃してください（--force オプションが必要です）
>    もしくは、再インストールします。
>	理由：設定内容を SWConfig から DSA に移行することができないため。
>	イメージ検査 'fwtool_check_image' が失敗しました。

なんか翻訳してもよく意味がわからない。。

イメージファイルとデバイスのバージョンが違っていて、 fwtool_check_image という関数なのかコマンドなのか分からないが、それが失敗しているみたい。たぶん `--force` オプションを使えばいいような気もするが、この手の強制オプションは場合によっては**凶悪**な効果を及ぼすので、よく意味がわかってないのに使うべきではない気がする。 sysupgrade コマンドを `--help` オプション付きで実行して Usage を見ると以下のように書いてあるし…。

	-F | --force
	            Flash image even if image checks fail, this is dangerous!

危険だ…。
そこで Web で調べてみたところ、以下に行き当たった。

:::note info
**【参考】**[\[OpenWrt Wiki\] Upgrading to OpenWrt 21.02.0](https://openwrt.org/docs/guide-user/network/dsa/upgrading-to-2102)
:::

こちらも要点だけ、以下に翻訳。

>	18.06 (またはそれ以前) から 21.02 への直接の sysupgrade はサポートされていません。
>    アップグレードするには、設定をバックアップし、21.02.0 をインストールしてから、手動で構成を再作成する必要があります。


ああ、なるほど。設定内容(config ファイルか何か)の互換性が 18.06 以前と 21.02 で失われているから、自動で設定内容をアップグレードできないってことね。やるんなら、設定内容をバックアップしておいてから、復元は手動でやってくださいよ。という事みたい。
しかし今回は initramfs は踏み台として起動しただけであり、何も設定していないんだから、 `--force` を使って設定内容を消し飛ばしてしまっても何ら問題ないと思う。…おそらく。たぶん。


### 🔵 最新版の initramfs に差し替えてリトライ

`--force` を使ってもいい。が、ちょっと怖い。
過去にこの手のオプションを安直に使用して失敗したことがあるからだ。

俺ちゃんの脳内に住んでるズッ友スパイディの有名な あの言葉が脳裏をよぎる。
    「 **大いなる力には、大いなる責任が伴う** 」
そう。それだ！
大いなる力はなるべく使いたくない。俺ちゃんは責任をなるべく負いたくないからだ。
<br>

なので。別のアプローチを探したところ…
下記のページを見ると、最新版の `initramfs` を直接入れることができたような記載になっている。こちらを試してみたい。

:::note info
**【参考】**[WSR-1166DHS2へのOpenWrt導入①（インストール編） _ 子育てパパのワークライフバランス](https://rmwlbpapa.com/it/openwrt/)
:::

まず一度 `poweroff` コマンドでルーターの電源を切る。物理な電源ボタンもペコッと押して電源 OFF 状態にしておく。

次に、シンボリックリンクを削除して、指し示す先を変更する。

```console
	$ cd /srv/tftp
	$ rm linux-trx-recovery
	$ ln -s  openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-initramfs-kernel.bin  linux.trx-recovery
```

これでもう一度 `AOSSボタン` を押しながら電源投入！
今度はめんどくさいので Wireshark は起動しないでやった。だが、うまくいった！ **…なんだ、ver.17.01.4 じゃなくても できるんじゃん！**

例によって 2, 3分程度待つと *[POWER]* の LEDランプのみが点灯した状態となり、疎通が取れるようになった。すかさず SSH でログインする。
今回は最新版の OpenWrt なので `-oHostKeyAlgorithms=+ssh-rsa` オプションは必要ないはずだ。

ただし、 `~/.ssh/known_hosts` に先ほどの古い `initramfs` のフィンガープリントが登録されてしまっているので、先にそれを削除する。
ちなみに削除せずにやると、以下のような警告が出て SSH できないだろう。

```console
	$ ssh root@192.168.1.1
	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
	@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
	@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
	IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
	Someone could be eavesdropping on you right now (man-in-the-middle attack)!
	It is also possible that a host key has just been changed.
	The fingerprint for the RSA key sent by the remote host is
	SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
	Please contact your system administrator.
	Add correct host key in /home/9hnder/.ssh/known_hosts to get rid of this message.
	Offending RSA key in /home/9hnder/.ssh/known_hosts:20
	Host key for 192.168.1.1 has changed and you have requested strict checking.
	Host key verification failed.
	exit 255
	$
```

いつものあれだ。
まあ、このページを見ている皆さんに、こんな初歩的な説明はいらんだろうが…。いらんよね？ よね？ 当然だよね〜〜。知らないわけ無いもんね〜。(煽り)

```console
	$ sed --in-place -e '/^192.168.1.1 /d' ~/.ssh/known_hosts
```

で `known_hosts` の該当行を削除できる。
そして再び SSH する。

```console
	$ ssh root@192.168.1.1
```

![09_ssh2Initramfs_v24.10.0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3699150/a3716fd5-8935-4a45-bae1-e5ff0a59dc1d.png)

ログインできたら、 /tmp に移動しておく。

```console
    root@OpenWrt:# cd /tmp
	root@OpenWrt:/tmp#
```

PC 側でもう一つターミナルを開いて `scp` コマンドで `Sysupgrade` イメージファイルをルーター側の /tmp に転送する。

```console
	$ scp -O  openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-squashfs-sysupgrade.bin  root@192.168.1.1:/tmp/
```

ルータ側で /tmp に転送されたファイルを確認して、 `sysupgrade` コマンドを実行する。

```console
	root@OpenWrt:/tmp# ll openwrt*
	-rw-r--r--    1 root     root       7209580 Mar  9  2025 openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-squashfs-sysupgrade.bin
	root@OpenWrt:/tmp#
	root@OpenWrt:/tmp#
	root@OpenWrt:/tmp# sysupgrade -v openwrt-24.10.0-ramips-mt7621-buffalo_wsr-1166dhp-squashfs-sysupgrade.bin
	Cannot save config while running from ramdisk.
	Thu Jan  1 00:20:53 UTC 1970 upgrade: Commencing upgrade. Closing all shell sessions.
	Command failed: Connection failed
	root@OpenWrt:/tmp# Connection to 192.168.1.1 closed by remote host.
	Connection to 192.168.1.1 closed.
    exit 255
	$
```

あらら？
また失敗した？？

"Cannot save config" と出てるから -n オプションも付けたほうが良かったのかな？でも "Commencing upgrade. Closing all shell sessions." と出てるよ？ 意味は「**アップグレードを開始します。すべてのシェルセッションを閉じます。**」だ。

十数秒すると、*[POWER]* LEDランプが点滅し始めた！
`initramfs` のときと同じで、ファームウェア更新処理が走っているときの挙動だ。そして 2, 3分待っていると [POWER] のみが常時点灯している状態に落ち着いた。

起動したらしい。



### 🔵 三たび SSH してみる

前回同様に SSH してみよう。

```console
	$ sed --in-place -e '/^192.168.1.1 /d' ~/.ssh/known_hosts
	$ ssh root@192.168.1.1
```

見た目は何も変わっていない。
…同じバージョンなので当然だが。

しかし df コマンドを打ってみると、 マウントされているパーティションが異なる。

```console:🔹 initramfs から起動した場合
	root@OpenWrt:~# df
	Filesystem           1K-blocks      Used Available Use% Mounted on
	tmpfs                    59636     18800     40836  32% /
	tmpfs                    59636       212     59424   0% /tmp
	tmpfs                      512         0       512   0% /dev
	root@OpenWrt:~#
```
```console:🔹 sysupgrade イメージで起動した場合
	root@OpenWrt:~# df
	Filesystem           1K-blocks      Used Available Use% Mounted on
	/dev/root                 4096      4096         0 100% /rom
	tmpfs                    59636       212     59424   0% /tmp
	tmpfs                    59636        56     59580   0% /tmp/root
	tmpfs                      512         0       512   0% /dev
	/dev/mtdblock6            8896       360      8536   4% /overlay
	overlayfs:/overlay        8896       360      8536   4% /
	root@OpenWrt:~#
```

`initramfs` の場合はメモリ上に展開した、揮発性のイメージなので `tmpfs` が使われているのみ、となっている。
一方、 `Sysupgrade` イメージの方はフラッシュメモリに書き込んだ内容が読み込まれるので `/dev/mtdblock*` が使用される。これは `Overlayファイルシステム` が用いられる事で多層的なファイルシステムを利用できるようになっている。

要するに "overlay" があれば `sysupgrade` コマンドは成功している。
initramfs とは違い、再起動しても消えないはずだ。

**$\huge{おめでとう。 OpenWrt のインストールは完了である！}$**



🔶 後処理：使ったゴミは綺麗にしよう。お兄さんとの約束だゾ☆
===========================================================

あとは OpenWrt を使い始めれば良い。
Webインターフェイスからセットアップしていっても良いし、SSH でこのままいじくり倒すのもよいだろう。好きにすればいい。
Web管理画面は以下からアクセスできる。

[http://openwrt.lan/](http://openwrt.lan/)

または、

[http://192.168.1.1/](http://192.168.1.1/)

ユーザー名はデフォルトでは root だ。
**初期パスワードは設定されていない**。
空のまま「Log in」ボタンを押せばログインできるだろう。この状態では非常に危険なので、無線LAN 機能はすべて OFF にされている。一通り、設定が終わってセキュリティ面を確保してから ON とするようにしよう。

特に初期パスワード空っぽは大変危険なので、そこは絶対初めに設定すること！詳細な解説は以下の公式サイトを見よ。

:::note info
**【参考】**[\[OpenWrt Wiki\] OpenWrt Starter FAQ](https://openwrt.org/docs/guide-quick-start/starterfaq)
:::

ここからリンクされている OpenWrt Wiki内のページは全て重要なので一読しておく事を お薦めしておく。

----

…だが、その前に後片付けをしておこう。
ちらかしたゴミを片付けるのは **人として当然のこと** だ。うむ。

tftp.service は停止しておく。

```console
	$ systemctl stop tftpd.service
	$ 
	$ systemctl status tftpd.service
	○ tftpd.service - hpa's original TFTP daemon
		 Loaded: loaded (/usr/lib/systemd/system/tftpd.service; disabled; preset: disabled)
		 Active: inactive (dead)

	 3月 11 01:03:28 localhost systemd[1]: Starting hpa's original TFTP daemon...
	 3月 11 01:03:28 localhost systemd[1]: Started hpa's original TFTP daemon.
	 3月 11 17:54:16 localhost systemd[1]: Stopping hpa's original TFTP daemon...
	 3月 11 17:54:16 localhost systemd[1]: tftpd.service: Deactivated successfully.
	 3月 11 17:54:16 localhost systemd[1]: Stopped hpa's original TFTP daemon.
	$ 
```
:::note info
「二度と使うことはない！」というなら disable にしたり、 tftp-hpa パッケージ自体をアンインストールしてしまってもいい。TFTP 自体これ以外にはあんまり使い道がないので、その方がいいかも。
:::

ファームウェア・イメージ類のファイル `/srv/tftp/*` は削除しておく。

```console
	$ rm /srv/tftp/*.*
	$ 
```

ファイアウォール（俺ちゃん家では ufw ）は有効に戻しておく。

```console
	$ sudo ufw status
	Status: inactive
	$ 
	$ sudo ufw enable
	Firewall is active and enabled on system startup
	$ 
```

イーサネットに設定した静的IPアドレスも削除しておく。

```console
	$ sudo ip address del 192.168.1.2/24  broadcast 192.168.1.255  dev eth0
	$ sudo ip address del 192.168.11.2/24  broadcast 192.168.1.255  dev eth0
	$ 
	$ ip address show  dev eth0
	2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
		link/ether XX:XX:XX:XX:XX:XX brd ff:ff:ff:ff:ff:ff
		altname enx000000000000
	$
```

OK。
綺麗になった！

あとは好きにするがいい！！



<br><br><br>
🔶 おまけ：MTDバックアップ を使って メーカー純正FW に戻すには？
===============================================================

:::note warn
**【注意】**
この項目は、もしもの時のために調べた手順であり、実際には俺ちゃんは戻していないので **未検証である** 。もしかしたら重大な間違いがあるかもしれないので、これをそのまま **「えいやぁ！」** と勢いで実行せず、ちゃんと自分で調べ間違いないか裏を取ってから実行してほしい。俺ちゃんは何があっても保証しないゾ。
でも、「成功したよ！☆」とか「失敗したお(TдT)」っていう報告は大歓迎である。
:::
:::note info
**【後日追記】**
動いたとの報告あり。詳しくは [コメント欄](https://qiita.com/9hnder/items/35e0cbfb3dc9828d8852#報告-1-buffalo-firmware-の書き込みについて) にて。
:::

### 🔵 AOSS で再び initramfs を使って復旧準備

まずは `initramfs` を使って起動する。
本稿「[🔶 AOSS回復法で initramfs を入れてみる](#-aoss回復法で-initramfs-を入れてみる) 」の項目を参照のこと。

:::note info
**【補足】**
なお、俺ちゃんが途中までやってみたときは ver.24.10.0 の initramfs イメージを使うと何故かインストール済みの OpenWrt の方が起動してきてしまってダメだったので ver.17.01.4 の initramfs を使ってやった。おそらく、設定内容が NVRAM[^4] に残ってしまっているためではないかと思われる。…が、詳しく調べてはいないのでなんとも言えん。
:::

[^4]: NVRAM とは設定内容を保持しておく保存領域のこと。

起動できたら SSH でログインする。
ログインできたら次のコマンドを実行する。

```console
	$ cat /proc/mtd
```

すると、MTDレイアウトが表示される。
WSR-1166DHP に OpenWrt を正常に書き込んでいる場合なら、以下のような MTDレイアウトが出力されるだろう。

```console:🔹 MTDレイアウト ＠OpenWrt
	root@OpenWrt:~# cat /proc/mtd
	dev:    size   erasesize  name
	mtd0: 00030000 00010000 "u-boot"
	mtd1: 00010000 00010000 "u-boot-env"
	mtd2: 00010000 00010000 "factory"
	mtd3: 00f90000 00010000 "firmware"
	mtd4: 00308994 00010000 "linux"
	mtd5: 00c87650 00010000 "rootfs"
	mtd6: 008b0000 00010000 "rootfs_data"
	mtd7: 00020000 00010000 "board_data"
	root@OpenWrt:~#
```

OpenWrt インストール前に踏み台として `initramfs` を初めて起動したときに MTDバックアップを取ったと思うが、これのレイアウトと異なっているのにお気づきだろうか。その時のレイアウトは以下のようになっていた。

```console:🔹 MTDレイアウト ＠initramfs
	root@LEDE:~# cat /proc/mtd
	dev:    size   erasesize  name
	mtd0: 00030000 00010000 "u-boot"
	mtd1: 00010000 00010000 "u-boot-env"
	mtd2: 00010000 00010000 "factory"
	mtd3: 00f90000 00010000 "firmware"
	mtd4: 00020000 00010000 "board_data"
	root@LEDE:~#
```

mtd0 〜 mtd3 までは変わらない。名前もサイズも同じだ。
しかし、mtd4 は元々の "board_data" が mtd7 に移動しており、mtd4 は "linux" に変更されている。また、mtd5 "rootfs", mtd6 "rootfs_data" も追加されている。

HDD などで fdisk や parted を使ってパーティションを切っていた感覚だと、まずは mtd4 〜 7 を消去して メーカー純正FW の構成と同じに変更しないと... と思うだろうが、**これは間違い**。


### 🔵 MTD はパーティションであってパーティションではない(哲学風)

MTD の場合、HDD と違って物理的なセクターやアライメントに沿ってパーティションが分割されているわけではない。これにはフラッシュメモリ独特の『**同じ領域に書き込み続けるとそこの劣化が顕著に進んでしまう**』性質が関係している。内部ではこれをウェアレベリングなどの平滑化技術によって補っているのだが、その関係で MTD は分割領域をより仮想的に扱う仕組みとなっている。

では、具体的に MTD の領域とはどういう形になっているのだろうか？
実際の例と図を見ていただくほうがわかりやすいだろう。以下を見てほしい。

:::note info
**【参考】**[Example 2: Hoo Too HT-TM02 :: \[OpenWrt Wiki\] OpenWrt フラッシュレイアウト](https://openwrt.org/docs/techref/flash.layout#example_2hoo_too_ht-tm02)
:::

ここで紹介されている機種は WSR-1166DHP とは違うが、MTDレイアウトは非常に近い。真似して WSR-1166DHP 版を作ってみると以下のアスキーアート図のようになる。

![20_MTD_LayoutAsciiArtDiagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3699150/4450de4e-9f64-44a1-bb68-c9e60e418aa1.png)

mtd0 〜 3 までは全く一緒だ。ただし、mtd3 のサイズだけは 00f90000 = 15936 KiB と異なっている。これは WSR-1166DHP のフラッシュメモリのサイズが 16 MiBであり、このページで紹介されている機種 Hoo Too HT-TM02 は 8 MiB だからだ。

次に mtd3 の中に mtd4 〜 6 が含まれているのがわかるだろうか。
そう。**入れ子にできるのだ。** それも何層もの。
これはパーティションで言えば拡張パーティションの構造…もっと言えば LVMパーティション に近い。仮想的、というのはこういうことだ。

ちなみに、 mtd0, 1, 2, および 7 は mtd3 の中に含まれない。
これらを考慮して合計サイズを計算してみると以下のようになる。

```console
	$ echo 'obase=10; ibase=16; 00F90000' | bc
	16318464
	$ echo '192 + 64 + 64 + 128' | bc
	448
	$ echo 'scale=2; ( (16318464 / 1024) + 448) / 1024' | bc
	16.00
	$ 
```

16 MiB だ。
つまり、本書「[🔶 HW仕様](#-hw仕様)」で紹介したフラッシュ・メモリのサイズ 16 MB にちゃんとピッタリ一致するとわかる。


### 🔵 MTD の階層構造を把握する汎用的な手段は？

しかし、入れ子構造がいつもこのようになっているとは限らない。
典型的な例ではあるが、これは機種や OpenWrt のバージョン等によって違ってくる。先程の参考ページにもいくつか他のバリエーションが紹介されているので見るとよい。

階層構造も含めて調べる方法はないのか？というと… dmesg コマンドの出力から解析することで把握できる。WSR-1166DHP の場合、以下に抜粋したようなログが含まれるはずだ。

```console
	root@OpenWrt:~# dmesg
	-- snip --
	[    2.015809] spi-nor spi0.0: mx25l12805d (16384 Kbytes)
	[    2.026336] 5 fixed-partitions partitions found on MTD device spi0.0
	[    2.039062] OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
	[    2.053657] OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
	[    2.068541] Creating 5 MTD partitions on "spi0.0":
	[    2.078128] 0x000000000000-0x000000030000 : "u-boot"
	[    2.089743] 0x000000030000-0x000000040000 : "u-boot-env"
	[    2.101652] 0x000000040000-0x000000050000 : "factory"
	[    2.113167] OF: Bad cell count for /palmbus@1e000000/spi@b00/flash@0/partitions
	[    2.128191] 0x000000050000-0x000000fe0000 : "firmware"
	[    2.139756] 2 trx partitions found on MTD device firmware
	[    2.150555] Creating 2 MTD partitions on "firmware":
	[    2.160451] 0x00000000001c-0x0000003089b0 : "linux"
	[    2.170179] mtd: partition "linux" doesn't start on an erase/write block boundary -- force read-only
	[    2.189910] 0x0000003089b0-0x000000f90000 : "rootfs"
	[    2.199872] mtd: partition "rootfs" doesn't start on an erase/write block boundary -- force read-only
	[    2.219307] mtd: setting mtd5 (rootfs) as root device
	[    2.229536] 1 squashfs-split partitions found on MTD device rootfs
	[    2.241861] 0x0000006e0000-0x000000f90000 : "rootfs_data"
	[    2.253844] 0x000000fe0000-0x000001000000 : "board_data"
	-- snip --
	root@OpenWrt:~#
```

こちらでは MTDパーティション のアドレスの開始位置と終了位置が示されている。（もちろん、これも物理的な連続領域ではない。フラッシュメモリ・デバイスのハードウェアがカーネルとデバイスドライバによって抽象化された後の仮想的なアドレスに過ぎない）
感のいい読者なら、このアドレスを見て なんとなくおわかりだろうが…

"2 trx partitions found on MTD device firmware" の部分に注目してもらいたい。次の行には 'Creating 2 MTD partitions on "firmware"' となっていて、`firmware` と名付けられた領域内にさらに 2 つの領域が作られていることがわかる。
この 2 つとはその次に現れる行 `linux`, `rootfs` のことだ。

さらに、"1 squashfs-split partitions found on MTD device rootfs" に注目。この行はつまり、 Squashファイルシステム の `rootfs` 内を更に分割して 1 つの領域が作られているという意味。
そして次の行が `rootfs_data` なので、この名前の領域がそれだとわかる。よく見ればアドレスも `rootfs` 領域の途中から最後までとなっているのが分かるはず。

最後の行の "board_data" だが、これは入れ子の外にある。
'Creating 5 MTD partitions on "spi0.0":' という行が最初の方にあるが、そこで 5 つのパーティションがあると分かり、それは `u-boot`, `u-boot-env`, `factory`, `firmware` の 4 つと、 `board_data` だということだ。
<br>

本当は lsblk コマンドや mtdinfo コマンドを使えばもっと簡単に解析が可能なのだが、 OpenWrt ではそれは叶わない。ルーターという、限られたリソースしか無いデバイスで動作させるために、容量節約のため削減されてしまっているため、それらの機能がないのだ。残念。


### 🔵 MTD のことはわかった。で？実際に復旧させるにはどうしたらいいの？

答えは簡単。
WSR-1166DHP の場合は、**mtd3 "firmware" 領域だけを書き戻せば良い**。

なぜなら `firmware` がいらない `linux`, `rootfs`, `rootfs_data` を含んでおり、元のメーカ純正FW＠initramfs の`MTDレイアウト`におけるサイズと全く一緒だからだ。
WSR-1166DHP においては。

mtd0 〜 2 と mtd7 については mtd3 に含まれないのだが、これらは元の メーカー純正FW の `MTDレイアウト` と全く変わらない。サイズも内容も同じだ。
疑うなら、もう一度同じ方法でバックアップを取ってみてバイナリのハッシュ値を比較してみるといい。俺ちゃんが嘘つきでないとわかるはずだ。

mtd7 の番号が違ってるのはダメじゃね？と思われがちだが… この番号自体、`dmesg` コマンドの出力で見た通り、起動時に識別した順で割り振られているだけなので心配ない。
<br>

…ってことで、バックアップの復旧作業に移ろう。
まずは firmware 領域(mtd3) のバックアップファイルを PC からルータへ転送する。

```console
	$ scp -O -oHostKeyAlgorithms=+ssh-rsa  ./mtd3.dd.gz  root@192.168.1.1:/tmp/
```

そしてルーター側で以下のように mtd コマンドを使う。

```console
	root@OpenWrt:~# cd /tmp
	root@OpenWrt:/tmp# zcat mtd3.dd.gz | mtd -e firmware -r write - firmware
```

一応解説すると、
`gzip` 圧縮された `mtd3` のバックアップ・ファイルを `zcat` コマンドで展開してパイプ経由で mtd コマンドに渡す。
`mtd` コマンドは `-e` オプションの指定によってパーティション名 `firmware` 領域内のデータを消去しつつ、パイプラインから受け取ったバックアップデータを同じく `firmware` 領域へと書き込む。
`-r` オプションは書き込みが完了したら、再起動する指定。

<br>


なお、`mtd` コマンドの代わりに `dd` を使って `/dev/mtdblock3` へと書き戻すこともできなくはないと思われるが、フラッシュメモリへの書き込みは `mtd` コマンドの方が専門なのであえてこちらを選択する意味はない。リスクなだけ。
~~もし、何らかの理由で dd を使わざるを得ないなら、その際にはまた bs オプションで 64K を指定するのを忘れないようにすること。おそらく、以下のようになるだろう。~~

```console
	root@OpenWrt:/tmp# zcat mtd3.dd.gz | dd bs=64K of=/dev/mtdblock3
```

~~ウェアレベリングなどのフラッシュメモリ独特の問題があるので微妙だが... たぶん、デバイスドライバによってブロックデバイスになる際に抽象化されているから dd でも問題ないと思われるが。たぶん... おそらく...~~

:::note warn
**【注意】**
この dd の方法はよろしくなかったので訂正線で削除しました。
詳細は 本書「[🔶 おまけの補足：MTD周りの仕様。特に mtdblock について](#-おまけの補足mtd周りの仕様特に-mtdblock-について) 」を参照。
:::
<br>

どちらにしても実行前に くれぐれも **間違えていないか確認すること！**
失敗するとルーターが 文鎮化[^5] するよ！！

[^5]: 二度と動かなくなるという意味の俗語。書道の際の "文鎮" としては使える。

:::note info
**【余談】**
なお、賢い読者なら「mtd3 だけでよいなら何故他の mtd までバックアップさせた？」とお思いだろう。そう。普通は他は必要ない。
だが、愚かなことをしてブートローダー U-Boot が入っている mtd0 "u-boot" や mtd1 "u-boot-env" 、工場出荷時のデータ？ブートローダーの設定値？が入った mtd2 "factory" を消してしまったとしたらどうだろうか。その場合は最悪起動すらしなくなる。当然 AOSS回復法 も使えないので 踏み台initramfs すら起ち上がらない。まさに文鎮化だ。
だが、ルーターを分解して特殊な方法で流し込めば復活できる可能性もわずかにある。なくはない。おそらく…。きっと…。理論的には。そんなレアなときのために、バックアップしておいたのだ。やり方は説明しないが。というか、俺ちゃんもよく知らん。あと、劣化が原因でそれらが損傷している疑いがあるときに、比較することで本当に損傷しているのかが分かるというメリットもある。…たぶんな。
:::

以上。
チミ・チャンガ！！





<br><br><br><br>

🔶 おまけの補足：MTD周りの仕様。特に mtdblock について
======================================================

**「MTD 周りの仕様でアヤフヤなところはフワっとさせずにちゃんと調べて！」** とあるお方に怒られたので、後日調べました。**はい。ごめんなさい。**
以下が参考サイト。

:::note info
**【参考】**[How To Use MTD _ Timesys LinuxLink](https://linuxlink.timesys.com/docs/wiki/engineering/HOWTO_Use_MTD)
:::

:::note info
**【参考】**[Memory Technology Device \(MTD\) Subsystem for Linux](http://www.linux-mtd.infradead.org/doc/general.html)
:::

後者は `mtd` コマンドなどを含む `mtd-utils` パッケージを制作しているメンテナーの方のページで公式と言っていいページ。

この文章を読むと、`/dev/mtdblock` を普通のブロックデバイス的なものとして使用するような行為はよろしくないようだ。特に書き込みは。
以下に関連部分の日本語訳を抜粋する。

まずは前者のサイト。

>	Linux カーネルでは、 MTD はキャラクタ デバイスまたはブロック デバイスとしてア
	クセスできます。ただし、デバイスを通常のブロック デバイスとして使用することは
	非常に危険であり、完全に実装されていません。ほとんどの場合、キャラクタ デバイ
	ス インターフェイスを常に使用する必要があります。

次に後者のサイト。

>	MTD で利用できるドライバー mtdblock は、 MTD デバイス上で ブロック デバイス を
	エミュレートする古いツールです。消去ブロック処理も不十分なので NAND フラッシュ
	では使用できません。また、フラッシュ消去ブロック全体を RAM にキャッシュし要求
	に応じて変更してからブロック全体を消去し、変更内容を書き戻すことで動作します。
>	つまり、最適化は行われず、電源が切れると大量のデータが失われます。
>	最後に、ウェアレベリング や ビット反転 処理も行われません。
>	
>	多くの場合、人々はこれを一般的な FTLレイヤー と見なし、生のフラッシュを使用し
	てブロックベースのファイルシステムを使用できるだろうと考えます。
>	これはほとんどの場合間違っています。言い換えると、自分が何をしているのかを正確
    に理解していない限り、 mtdblock を使用しないでください。


これを読む限りでは `/dev/mtdblock0` のようなブロックデバイスとしてのアクセスではウェアレベリングなどのフラッシュメモリ・デバイスの特性に合わせた技術的な恩恵が一切受けられない模様だ。単にブロックへの書き込みを RAM にキャッシュして、実際に書き込む際には *消去→ブロック単位での書き込み* を実行するだけのように見える。恩恵を受けるには、替わりに `/dev/mtd0` のようなキャラクターデバイスを使ってアクセスすべきだということらしい。

ということは、やはり dd を使ってブロック単位で書き戻すようなことは、やらない方が良さそうだ。
`/dev/mtd0` などキャラクターデバイスを使用して、1 バイト単位で書き込むなら可かもしれないが、そちらも試したわけではないので、なんとも言えない。やはり素直に mtd コマンドにお任せするのが良いだろう。餅は餅屋、ということだ。


<br><br><br><br>