hostapdを使って2つのNICに別々のAPを立ち上げる

#はじめに

5GHzと2.4GHzの２つの無線ネットワークを構成したく、Raspberry PiにWiFiドングルを差して、１つのマシンで２つのアクセスポイント(AP)を立ち上げることにした。AP用デーモンとしてhostapdを使っているのだが、2つ別々にAPを立ち上げる方法についてリサーチすると、
- `/etc/default/hostapd`の中に設定ファイルを２つ列挙する
- `/etc/hostapd/hostapd.conf`内に設定を２つ書く
という情報を見つけたが、いずれもうまくいかなかった。

どうするかと悩んでいたら、偶然にも非常に簡単な方法を発見したので紹介する。


#必要なソフトウェア
- hostapd (version 2.6)
- systemd

systemdはRasbian Jessie以降はデフォルトで動いているはずなので、新しいRasbian使っているなら特に何もしなくていいはず。hostapdはaptコマンド等でインストールする。

hostpadのインストールが終わったら、以下のファイルを確認。

```shell-session
# ls /lib/systemd/system/hostapd*
hostapd.service  hostapd@.service  hostname.service
```
この`hostapd@.service`が**今回の肝となるファイル**。これが存在していればOK（自分では作ってないので、systemdが走っているマシンにhostapdをインストールしたら自動的に作られるはず）。

#設定
以下、wlan0でmyap0 (5GHz)、wlan1でmyap1 (2.4GHz)を立ち上げると仮定して説明する。

hostapdは`/etc/default/hostapd`内の`DAEMON_CONF`パラメーターに則って`/etc/hostapd/hostapd.conf`から設定を読み込むことになっている。

この`hostapd.conf`を`/etc/hostapd/wlan0.conf`と`/etc/hostapd/wlan1.conf`にコピーして、それぞれmyap0とmyap1の要件に合わせて適宜編集する。ファイル名を`インターフェース名.conf`とすることに留意する以外は特に注意事項はない。なお、`/etc/hostapd/hostapd.conf`がなければ`/usr/share/doc/hostapd/examples/hostapd.conf.gz`を解凍すれば手に入る。また、今回の手法では`/etc/default/hostapd`の`DAEMON_CONF`パラメーターは編集する必要はない。

###設定例

```wlan0.conf
interface=wlan0　　# ファイル名のインターフェース名と一致させること
driver=nl80211
ssid=myap0
country_code=JP
hw_mode=a
channel=40
 :
 :
```

```wlan1.conf
interface=wlan1　　# ファイル名のインターフェース名と一致させること
driver=nl80211
ssid=myap1
country_code=JP
hw_mode=g
channel=1
 :
 :
```

設定の妥当性はあらかじめ個別に確認（同じ内容を`hostapd.conf`に書き込んでhostapdを立ち上げてAPとしてちゃんと機能するかチェック）しておくことをお勧めする。

#APの起動
systelctlコマンドでhostpadを起動するのだが、ここがポイントとなる。すでにhostapdが稼働中なら

```shell-session
# systemctl stop hostapd
```

で一旦止める。
その上で、以下2つのコマンドを実行する。

```shell-session
# systemctl start hostapd@wlan0
# systemctl start hostapd@wlan1
```

何もエラーが出なければOK。これで2つのAPが立ち上がるはず。

ちゃんとhostapdが動いているか確認。

```shell-session
# systemctl | grep hostapd@
  hostapd@wlan0.service         loaded activating start     start Advanced IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator (wlan0)
  hostapd@wlan1.service         loaded activating start     start Advanced IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator (wlan1)
```

２つとも`loaded activating start`なら成功している。実際にAPにアクセスできるようになるには少し時間がかかるので、ちょっと待ってから`iwconfig`コマンドでもAPが立ち上がっているか確認するとよい。



#解説
`/lib/systemd/system/hostapd@.service`はsystemdのユニットファイルなのだが、この`@`がポイント。systemdでは名前に`@`がついたサービスは、`@`以降に文字列を加えてサービスを起動すると、その文字列はユニットファイル内で`%i`または`%I`で参照できる、という仕様になっているらしい。

`hostapd@.service`の中身を見てみると、

```hostapd@.service
[Unit]
Description=Advanced IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator (%I)
After=network.target
BindsTo=sys-subsystem-net-devices-%i.device

[Service]
Type=forking
PIDFile=/run/hostapd.%i.pid
Restart=on-failure
RestartSec=2
EnvironmentFile=/etc/default/hostapd
ExecStart=/usr/sbin/hostapd -P /run/hostapd.%i.pid $DAEMON_OPTS /etc/hostapd/%i.conf

[Install]
WantedBy=multi-user.target sys-subsystem-net-devices-%i.device
```

ざっくり言えば、`hostapd@wlan0`で起動した場合、`wlan0`が有効ならば、`/etc/hostapd/wlan0.conf`を設定ファイルとしてhostapdを起動する、という内容。

なるほど。これと同じことを自分でスクリプト書いて実現している人がいたが、こっちを利用する方がはるかに簡単だと思う。

#まとめ
- APを立ち上げたいNICごとに`インターフェース名.conf`にhostapdの設定（通常hostapd.confに記載する内容）を書き込む
- `systemd start hostapd@インターフェース名` でNICごとにhostapdを起動

とてもシンプルだ。

サービス名に`@`をつけておけば、パラメータ付きでサービスを起動できて、ユニットファイル内で`%i`または`%I`で参照できる、ということなので、サービスを自作するときに使えそうだ！