IIJmio SIMでIPv6 on Raspberry Pi

[L-02C で qmi 接続できるようになった](http://qiita.com/kwi/items/eb089d05cc3428cddbd8) ので、少し足を延ばしてIPv6接続を頑張ってみた。SIMは[みおふぉん](https://www.iijmio.jp/hdd/miofone/)を使っているので、[IPv6も使える](http://techlog.iij.ad.jp/archives/411)ことになっている。

Raspbian jessie-lite をベースにします。下に行くにしたがって重装備になっていきます。

# libqmi

まずモデムは`qcserial`と`qmi_wwan`で認識されている状態にする。すると `/dev/cdc-wwan0` で qmi プロトコルで通信できるようになっている。libqmi を使って、コマンドラインからqmiプロトコルで操作できる。前回使った qmi-network はこの形。

実は `qmi-network` は shell script で、実体は `qmicli` がやっている。中身を抜き出すとこんな感じになっている。

```bash
# qmicli -d /dev/cdc-wdm0 --wds-start-network=iijmio.jp,auth=CHAP,mio@iij,iij --client-no-release-cid
[/dev/cdc-wdm0] Network started
        Packet data handle: '28388580'
[/dev/cdc-wdm0] Client ID not released:
        Service: 'wds'
            CID: '3'
# qmicli -d /dev/cdc-wdm0 --wds-stop-network=28388580 --client-cid=3
Network cancelled... releasing resources
[/dev/cdc-wdm0] Network stopped
```

## IPv6 PDP

IPv6 接続を明示的に行いたい場合はPDP typeを指定することになる。本家の[開発repository](https://cgit.freedesktop.org/libqmi/commit/?id=81c213791e794311a01f3f69e763eb9b10c84f4d)だと、`--wds-start-network-apn`の引数が拡張されて、`ip-type`を指定できるようになっている。（libqmi リリース済みのものは今のところ無い）。こんな感じでビルドする。

```bash
# apt-get install gtk-doc-tools libglib2.0-dev
# git clone https://anongit.freedesktop.org/git/libqmi.git
# cd libqmi
# ./autogen.sh
# make install
```

`--wds-start-network` の引数の形が変わっていることに注意して、`ip-type` を指定した場合は、こんな感じになる。

```bash
# /usr/local/bin/qmicli -d /dev/cdc-wdm0 --wds-start-network=apn=iijmio.jp,auth=CHAP,username=mio@iij,password=iij,ip-type=6 --client-no-release-cid
[/dev/cdc-wdm0] Network started
        Packet data handle: '28388580'
[/dev/cdc-wdm0] Client ID not released:
        Service: 'wds'
            CID: '3'
```

## IPv6 割り当て

そんなこんなでIPv6アドレスが割り当てられたことは `--wds-get-current-settings` というコマンド引数を使って確認する。この引数は 1.14.2 や 1.16.0 に入っている（残念ながら raspbian jessie の 1.10.2 には入っていない）。

```bash
# /usr/local/bin/qmicli -d /dev/cdc-wdm0 --wds-get-current-settings
[/dev/cdc-wdm0] Current settings retrieved:
           IP Family: IPv6
        IPv6 address: 2001:240:2401:e6de:74a5:fb54:ee07:d515/64
IPv6 gateway address: 6ce8:84f1:945a:a678::/64
    IPv6 primary DNS: 2001:240::13
  IPv6 secondary DNS: 2001:240::14
                 MTU: 1500
             Domains: none
```

[ログ](https://cgit.freedesktop.org/libqmi/commit/?id=543cf5c93984139865f919e7348bff2b54c16f39)に書いてあるように、この値を使って `wwam0` の IP アドレスや DNS 登録を更新するのが、通信コストの最も安い方法のようだ。

`qmicli` 自体には自動的に `wwan0` に割り当てる仕組みはない。想像だけれども、理由は PPP pdp の場合は `pppd` がアドレス設定を行うので、そことの整合性を取って自動設定しない、ということではないだろうか。`dhcpcd` などで割り当てを行うのが良いだろう。

ちなみに L-02C では `wwan0` を通じて IPv6 RA を取得すると値がおかしかった（原因未調査）ので、この値を使うべし。[てくろぐ](http://techlog.iij.ad.jp/archives/411#l02c_dns)に「L-02Cでは機器の仕様上、IPv6のDNSサーバを自動的に取得することができない」と書いてあるのと関係があるのかもしれない。UX302NC では正常な値で取得されたので、そうなのだろう。この場合でも、上位が DHCPv6 で配布している IIJmio みおふぉんの環境では、`dhcpcd` 6.9.4 以降で使える `inform6` を使うと、L-02C でも `wwan0` に global scope の IPv6 アドレスを自動的に割り当てられた。この割り当ては qmi 上での割り当てとは別に `wwan0` リンク上で行われるもので、異なるアドレスが割当たる。

```dhcpcd.conf
interface wwan0
inform6
```

# ModemManager

qmi 接続よりももう少し抽象度を上げて、[qmi や mbim もひっくるめて扱える](https://aleksander.es/data/FOSDEM%202014%20-%20LTE%20in%20your%20Linux%20based%20system.pdf)便利なプログラム ModemManager というものがある。raspbian jessie では`modemmanager`というパッケージで入る（`libqmi-proxy`と`policykit-1`パッケージも入れておく）。

ModemManager は daemon が常駐していて、その daemon が `/dev/cdc-wwan0` を管理する。ModemManager も qmicli と同様に libqmi を使って QMI プロトコル通信する。コマンドライン `mmcli` からは D-BUS 経由で ModemManager と通信する。

```text
 L-02C --(USB)-- qmi_wwan -- /dev/cdc-wwan0 --(qmi)-- ModemManager --(D-Bus)-- mmcli
```

`mmcli` からは D-Bus 経由になるので、少し雰囲気が変わる。[マニュアル](https://www.freedesktop.org/software/ModemManager/man/1.0.0/mmcli.8.html)を参照しながら使う。具体的な操作例はこんな感じになる。

```bash
# mmcli -L

Found 1 modems:
        /org/freedesktop/ModemManager1/Modem/0 [LG Electronics Inc] docomo L02C

```

マニュアルに `-m, --modem=[PATH|INDEX]` と書いてあるけれど、PATH というのは「D-Bus の PATH」で、例えば上の `/org/freedesktop/ModemManager1/Modem/0` ですね。INDEX のほうは、最後の `0` だけを指しています。どちらで指定しても大丈夫。接続～切断までの簡単な流れは次の通り。

```bash
# mmcli -m 0 -e
# mmcli -m 0 --simple-connect=apn=iijmio.jp,user=mio@iij,password=iij
successfully connected the modem
# mmcli -m 0 --list-bearers

Found 1 bearers:

        /org/freedesktop/ModemManager1/Bearer/0
# mmcli -b 0
Bearer '/org/freedesktop/ModemManager1/Bearer/0'
  -------------------------
  Status             |   connected: 'yes'
                     |   suspended: 'no'
                     |   interface: 'wwan0'
                     |  IP timeout: '20'
  -------------------------
  Properties         |         apn: 'iijmio.jp'
                     |     roaming: 'allowed'
                     |     IP type: 'none'
                     |        user: 'mio@iij'
                     |    password: 'iij'
                     |      number: 'none'
                     | Rm protocol: 'unknown'
  -------------------------
  IPv4 configuration |   method: 'dhcp'
                     |  address: 'unknown'
                     |   prefix: '0'
                     |  gateway: 'unknown'
                     |      DNS: none
                     |      MTU: '1500'
  -------------------------
  IPv6 configuration |   method: 'unknown'
# mmcli -b 0 -x
successfully disconnected the bearer
# mmcli -m 0 -d
```

`--simple-connect` は `--create-bearer` と `-b [PATH|INDEX] --connect` を一気に実行するショートカット。もちろん別々にやってもいい。

IPv4 の設定は qmi 経由では取れたり取れなかったりする様子で、`dhcpcd` が `wwan0` 上で自動取得するのに任せるのが良さそう。単に `mmcli -m 0` とやると、モデムの情報が取得できる。

## IPv6 PDP

接続する際に次のようにすると、明示的に IPv6 になる。

```bash
# mmcli -m 0 --simple-connect=apn=iijmio.jp,user=mio@iij,password=iij,ip-type=ipv6
successfully connected the modem
```

## IPv6 割り当て

```bash
# mmcli -b 1
Bearer '/org/freedesktop/ModemManager1/Bearer/1'
  -------------------------
  Status             |   connected: 'yes'
                     |   suspended: 'no'
                     |   interface: 'wwan0'
                     |  IP timeout: '20'
  -------------------------
  Properties         |         apn: 'iijmio.jp'
                     |     roaming: 'allowed'
                     |     IP type: 'ipv6'
                     |        user: 'mio@iij'
                     |    password: 'iij'
                     |      number: 'none'
                     | Rm protocol: 'unknown'
  -------------------------
  IPv4 configuration |   method: 'unknown'
  -------------------------
  IPv6 configuration |   method: 'dhcp'
                     |  address: '2001:240:2401:2bfd:189f:2fdf:b0c3:8b'
                     |   prefix: '64'
                     |  gateway: 'e03f:496e:14a1:762e::'
                     |      DNS: '2001:240::13', '2001:240::14'
                     |      MTU: '1500'
```

IPv6 のときは qmi でアドレスが入っている。こちらも `wwan0` に自動的にアドレスが割当たったり、DNS 設定がされたりとかはしないので、この値をみて手動で割り当てるべし。

繰り返しになるけれども L-02C では DHCPv6 で情報が取れないので、この値に頼るしかない様子です。

# NetworkManager

実は NetworkManager は最近では ModemManager と連携するようになっている。raspbian jessie に `network-manager` パッケージをインストールする。

```text
 L-02C --(USB)-- qmi_wwan -- /dev/cdc-wwan0 --(qmi)-- ModemManager --(D-Bus)-- NetworkManager --(D-Bus)-- nmcli
```

接続～切断は次のようなコマンドになる。

```bash
# nmcli connection add autoconnect no type gsm ifname cdc-wdm0 apn iijmio.jp  user mio@iij password iij
Connection 'gsm-cdc-wdm0' (b518ef13-8c72-45bb-ac1a-588db73ab1f3) successfully added.
# nmcli c up b518ef13-8c72-45bb-ac1a-588db73ab1f3
# nmcli c down b518ef13-8c72-45bb-ac1a-588db73ab1f3
```

## IPv6 PDP

NetworkManager [1.0.0 から IPv6 接続がサポート](https://mail.gnome.org/archives/networkmanager-list/2014-December/msg00030.html)されるので、別途コンパイルしてインストールする。Raspbian jessie のパッケージは 0.9 なので。NetworkManager 1.2.4 (stable) をインストールする際には `libmm-glib-dev`, `libreadline6-dev`, `libndp-dev`, `ppp-dev`, `libnss3-dev`,  `uuid-dev`, `libnl-3-dev`, `libgudev-1.0-dev`, `libdbus-glib-1-dev` パッケージをインストールしておく。

インストール後 `ln -s /etc/NetworkManager /usr/local/etc` しておくと簡単。

```bash
systemctl unmask NetworkManager
systemctl unmask NetworkManager-dispatcher
```

明示的に PDP は指定できないけれども、モデムがサポートしていれば IPv6 を自動的に有効にしている。NetworkManager 側で IPv4 を無効化すれば IPv6 専用となる。

## IPv6 割り当て

NetworkManager が D-Bus 経由で ModemManager の情報をシステムに反映してくれる。全自動。

接続～切断はこんな感じになる。

```bash
# nmcli d
DEVICE    TYPE      STATE         CONNECTION
cdc-wdm0  gsm       disconnected  --
eth0      ethernet  unmanaged     --
lo        loopback  unmanaged     --
wlan0     wifi      unmanaged     --
# nmcli c add autoconnect no type gsm ifname cdc-wdm0 apn iijmio.jp user mio@iij password iij
Connection 'gsm-cdc-wdm0' (23ac16f0-5f8f-4080-969b-43a4ed13aa4e) successfully added.
# nmcli c modify 23ac16f0-5f8f-4080-969b-43a4ed13aa4e ipv4.method Disabled
# nmcli c up 23ac16f0-5f8f-4080-969b-43a4ed13aa4e
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/1)
# ip addr show dev wwan0
4: wwan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether 76:b0:b5:85:6d:ee brd ff:ff:ff:ff:ff:ff
    inet6 2001:240:2403:8213:94dd:bfe:8a47:154f/64 scope global
       valid_lft forever preferred_lft forever
# nmcli c show 23ac16f0-5f8f-4080-969b-43a4ed13aa4e
connection.id:                          gsm-cdc-wdm0
connection.uuid:                        23ac16f0-5f8f-4080-969b-43a4ed13aa4e
connection.interface-name:              cdc-wdm0
connection.type:                        gsm
connection.autoconnect:                 yes
connection.autoconnect-priority:        0
connection.timestamp:                   1471871592
connection.read-only:                   no
connection.permissions:
connection.zone:                        --
connection.master:                      --
connection.slave-type:                  --
connection.autoconnect-slaves:          -1 (default)
connection.secondaries:
connection.gateway-ping-timeout:        0
connection.metered:                     unknown
connection.lldp:                        -1 (default)
ipv4.method:                            disabled
ipv4.dns:
ipv4.dns-search:
ipv4.dns-options:                       (default)
ipv4.dns-priority:                      0
ipv4.addresses:
ipv4.gateway:                           --
ipv4.routes:
ipv4.route-metric:                      -1
ipv4.ignore-auto-routes:                no
ipv4.ignore-auto-dns:                   no
ipv4.dhcp-client-id:                    --
ipv4.dhcp-timeout:                      0
ipv4.dhcp-send-hostname:                yes
ipv4.dhcp-hostname:                     --
ipv4.dhcp-fqdn:                         --
ipv4.never-default:                     no
ipv4.may-fail:                          yes
ipv4.dad-timeout:                       -1 (default)
ipv6.method:                            auto
ipv6.dns:
ipv6.dns-search:
ipv6.dns-options:                       (default)
ipv6.dns-priority:                      0
ipv6.addresses:
ipv6.gateway:                           --
ipv6.routes:
ipv6.route-metric:                      -1
ipv6.ignore-auto-routes:                no
ipv6.ignore-auto-dns:                   no
ipv6.never-default:                     no
ipv6.may-fail:                          yes
ipv6.ip6-privacy:                       -1 (unknown)
ipv6.addr-gen-mode:                     stable-privacy
ipv6.dhcp-send-hostname:                yes
ipv6.dhcp-hostname:                     --
gsm.number:                             *99#
gsm.username:                           mio@iij
gsm.password:                           <hidden>
gsm.password-flags:                     0 (none)
gsm.apn:                                iijmio.jp
gsm.network-id:                         --
gsm.pin:                                <hidden>
gsm.pin-flags:                          0 (none)
gsm.home-only:                          no
gsm.device-id:                          --
gsm.sim-id:                             --
gsm.sim-operator-id:                    --
GENERAL.NAME:                           gsm-cdc-wdm0
GENERAL.UUID:                           23ac16f0-5f8f-4080-969b-43a4ed13aa4e
GENERAL.DEVICES:                        cdc-wdm0
GENERAL.STATE:                          activated
GENERAL.DEFAULT:                        no
GENERAL.DEFAULT6:                       yes
GENERAL.VPN:                            no
GENERAL.ZONE:                           --
GENERAL.DBUS-PATH:                      /org/freedesktop/NetworkManager/ActiveConnection/1
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/Settings/3
GENERAL.SPEC-OBJECT:                    /
GENERAL.MASTER-PATH:                    --
IP4.ADDRESS[1]:                         169.254.136.188/16
IP4.GATEWAY:
IP6.ADDRESS[1]:                         2001:240:2403:8213:94dd:bfe:8a47:154f/64
IP6.GATEWAY:                            345e:3437:1252:9881::
IP6.DNS[1]:                             2001:240::13
IP6.DNS[2]:                             2001:240::14
# nmcli c down 23ac16f0-5f8f-4080-969b-43a4ed13aa4e
Connection 'gsm-cdc-wdm0' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/1)
```

# Ubuntu Mate

もういっそここまで来たら Raspbian jessie じゃなくて Ubuntu Mate 使ったほうが手っ取り早いかも。NetworkManager で QMI ですぐに繋がるし、IPv6 も `wwan0` に反映される。DNS登録も入るし、経路も入る。

IPv6 のみの接続が最初うまくいかないときは、IPv4v6 で一度接続してから、IPv6 にするといけたりするみたい（未調査）。

# まとめ

方法がいくつかあるのをまとめると、こんな選択肢になるだろう。

- libqmi master HEAD をインストール + ネットワーク設定手動反映
- ModemManager + ネットワーク設定手動反映
- NetworkManager 1.2.4 をインストール
- （Raspbian ではなく）Ubuntu Mate をインストール

私は libqmi を Raspbian に入れて使おうかなぁ…

`libqmi`, `ModemManager` を作り上げた [Aleksander Morgado](https://aleksander.es/) さんに感謝！