RaspberryPi 3 b+をアクセスポイントとクライアントで使い分ける

ラズパイをアクセスポイントにして〜のような記事はたくさんあるが，いくつか前提を確認しないがためにハマったポイントがあるので，覚書としてメモしておく．

~~追記：raspi Zero Wで初めから検証したらうまくいかない．現在原因探してます．わかったら修正します．~~
2020/07/16 追記：原因がわかったので，更新しました．

## 対象環境
* RaspberryPi 3 b+
* Raspbian GNU/Linux 10 (buster) Release 10

## 対象のやりたいこと
* ラズパイをアクセスポイントとして利用しつつ，ラズパイをインターネットに接続したい．
上記を実現したいが，有線が使えない場合

## 結論
さらっと調べた感じ，対象のやりたいことを実現するには有線と無線をブリッジする必要がありそうだった．ハマった理由としては，ずっと無線と無線のブリッジをしようと頑張ってて，「うまくいかない．．．」と言っていたから．
無線と無線のブリッジをするためには，ラズパイ３にwifiモジュールを追加でつければうまくいくと思う．

今回はwifiモジュールを持ち合わせていなかったため，ラズパイをアクセスポイント(AP)として利用する場合とクライアントとして利用する場合で設定を簡単に切り替えられるようにした．

## 参考にさせていただいた記事
https://www.raspberrypi.org/documentation/configuration/wireless/access-point-routed.md [公式]
https://qiita.com/yamato225/items/24acb27403136732e01b#apwifi
https://qiita.com/wannabe/items/a66c4549e4a11491f9d5

## やったこと
* hostapdとdnsmasqのインストール ※ raspberrypi zero Wの場合注意
* /etc/hostapd/hostapd.confの設定
* /etc/dnsmasq.confの設定
* /etc/wpa_supplicant/wpa_supplicant.confの設定確認
* クライアント→APの切り替えテスト
* AP→クライアントの切り替えテスト
* スクリプト化

---

### hostapdとdnsmasqのインストール
```code
$ sudo apt install -y hostapd dnsmasq
```
hostapd: アクセスポイント用のツール．
dnsmasq: ホスト名とIPアドレスを覚えるDNSサーバ．

raspberry pi zero Wの場合はdnsmasqではなく，dnsmasq-baseをインストール

```code
$ sudo apt install -y hostapd dnsmasq-base
```


---
### /etc/hostapd/hostapd.confの設定
```conf:/etc/hostapd/hostapd.conf
interface=wlan0
driver=nl80211
ssid=<SSID名>
hw_mode=g
channel=6
ieee80211n=1
wmm_enabled=1
ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_key_mgmt=WPA-PSK
wpa_passphrase=<パスワード>
rsn_pairwise=CCMP
```
無線LANアダプタwlan0をアクセスポイントモードにする．

---
### /etc/dnsmasq.confの設定
```conf:/etc/dnsmasq.conf
interface=wlan0
dhcp-range=192.168.100.2,192.168.100.40,255.255.255.0,24h
```
アクセスポイントモード時に192.168.100.2〜192.168.100.40のipアドレスを利用して子機にipを割り振る．
今回はローカルネットワークのみで繋がるようにしてる．
用途に応じて172.42.1.2〜172.42.1.40とかでもOK．

### /etc/wpa_supplicant/wpa_supplicant.confの設定確認
wifiに接続できていれば変更する必要はありません．

---
```bash
sudo systemctl unmask hostapd
sudo systemctl disable hostapd
sudo systemctl restart dhcpcd
```
切り替えテストの前に↑をやっておく

### クライアント→APの切り替えテスト

```bash
sudo systemctl stop wpa_supplicant
sudo systemctl stop dhcpcd
sudo ip addr add 192.168.100.1 dev wlan0
sudo ip route add default via 192.168.100.1 
sudo systemctl start dnsmasq
sudo systemctl start hostapd
```
これで/etc/hostapd/hostapd.confで設定したSSID名のアクセスポイントができることを確認．
ラズパイはローカルネットワークを構築し，外部ネットワークと接続できなくなる．

### AP→クライアントの切り替えテスト

```bash
sudo systemctl stop hostapd
sudo systemctl stop dnsmasq
sudo ip addr flush dev wlan0
sudo systemctl start wpa_supplicant
sudo systemctl start dhcpcd
```
APモードからクライアントへ切り替わり，wifiが利用できるようになることを確認．
SSID名のアクセスポイントにアクセスできなくなっていることを確認．

### スクリプト
切り替えのコマンドをまとめて~/host.sh, ~/client.shとかにまとめておいていつでも切り替えられるようにしておく．

```shell:host.sh
sudo systemctl stop wpa_supplicant
sudo systemctl stop dhcpcd
sudo ip addr add 192.168.100.1 dev wlan0 # /etc/dnsmasq.confの設定に合わせる
sudo ip route add default via 192.168.100.1 
sudo systemctl start dnsmasq
sudo systemctl start hostapd
```

```shell:client.sh
sudo systemctl stop hostapd
sudo systemctl stop dnsmasq
sudo ip addr flush dev wlan0
sudo systemctl start wpa_supplicant
sudo systemctl start dhcpcd
```

デフォルトでどちらかを起動させるために/etc/rc.localを編集しておく．今回はデフォルトでclient.shの設定が起動できるようにしておく．
（なぜかsh client.shを書いても設定が反映されなかったので，client.shの中身をそのまま移植する形にした．）

```conf:/etc/rc.local
sudo systemctl stop hostapd
sudo systemctl stop dnsmasq
sudo ip addr flush dev wlan0
sudo systemctl start wpa_supplicant
sudo systemctl start dhcpcd

# exit 0の前に記入
```


## まとめ
ラズパイ3でAPモードとクライアントモードの切り替えを行った．有線に接続できず，さらに追加のwifiモジュールも持っていない状況で，ラズパイをAPモードとしてもクライアントモードとしても使いたいと言った場合に，簡単にAPモードとクライアントモードの切り替えを行えるようにするという折衷案．

この状況以外であれば，機器を用意して，ブリッジを利用すれば良いと思う．参考記事として上部に記載しているので参照していただきたい．