RaspberryPiでL-02Cを使う

[良記事](http://qiita.com/air-gh/items/6add3c0b19e8fe9469aa) を見かけたので、以前いったん挫折したL-02CでQMI接続というのを、もう一回頑張ってみた。

こうやったらOKだった。Raspbian Jessie-lite です。

L-02C のドライバ環境を整える。`udev` ルールにしておいてもいい。

```
modprobe qcserial
echo "1004 618f 0000 05c6 9212" > /sys/bus/usb-serial/drivers/qcserial/new_id
modprobe qmi_wwan
echo "1004 618f" > /sys/bus/usb/drivers/qmi_wwan/new_id
```

L-02C を刺す。CD-ROM としてマウントされた場合は、`eject` する（同等のことを `usb_modeswitch` でやってもいい）。そうすると idVendor=1004, idProduct=618f な USB が出てくる。そして、こんな感じで認識されるはず。

```
T:  Bus=01 Lev=02 Prnt=02 Port=03 Cnt=03 Dev#=  9 Spd=480 MxCh= 0
D:  Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
P:  Vendor=1004 ProdID=618f Rev=00.00
S:  Manufacturer=NTT DOCOMO, INC.
S:  Product=docomo L02C
C:  #Ifs= 4 Cfg#= 1 Atr=80 MxPwr=500mA
I:  If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
I:  If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
I:  If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qcserial
I:  If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan
```

`libqmi-utils`をインストールし、`/etc/qmi-network.conf` を書く。

```/etc/qmi-network.conf
APN=iijmio.jp,CHAP,mio@iij,iij
```

接続には `qmi-network` を使うと便利。

```
qmi-network /dev/cdc-wdm0 start
```

繋がった？ちょっと待ってLEDが反応したのを見計らって実行すると繋がる様子。

```
ip route
journalctl
```

ちなみに…[バンド](https://en.wikipedia.org/wiki/GSM_frequency_bands)を確認しておく。

```
# qmicli -d /dev/cdc-wdm0 --dms-get-band-capabilities
[/dev/cdc-wdm0] Device band capabilities retrieved:
        Bands: 'gsm-dcs-1800, gsm-900-extended, gsm-900-primary, gsm-pcs-1900, wcdma-2100, wcdma-850-us, wcdma-800'
```

そうそう、USB電源設定も強化しておきましょう。L-02C も結構電力食うので。

```
echo usb_max_current=1 >> /boot/config.txt
```

IPv6
----
IIJmio の SIM（みおふぉん）では IPv6 も割り当てることもできる。ただし実験した範囲では L-02C では `wwan0` 上で受け取る IPv6 RA メッセージ内容が壊れていた。[てくろぐ](http://techlog.iij.ad.jp/archives/411#l02c_dns)に「L-02Cでは機器の仕様上、IPv6のDNSサーバを自動的に取得することができない」と書いてあるのと関係があるのかもしれない。

この前提を踏まえつつ、現状 `wwan0` に自動的に global scope のアドレスを割り当てる方法は2通りある。

- NetworkManager + ModemManager の連携機能を使って、qmi プロトコル上で与えられたアドレスを `wwan0` に自動的に反映させる方法
- 6.9.4 以降の `dhcpcd5` の `inform6` オプションを使って、DHCPv6 を `wwan0` 上でいきなり呼び出して反映させる方法

詳しくは[別記事](http://qiita.com/kwi/items/977b70ca85cfe72e7610)を参照。

Windows環境
-------------
公式のドライバでは、こう認識されている。

|ハードウェアID| 名前 |
|:--|:--|
|usb\vid_1004&pid_618f&mi_00 | docomo L02C USB Serial Port |
|usb\vid_1004&pid_618f&mi_01 | docomo L02C NMEA Serial Port |
|usb\vid_1004&pid_618f&mi_02 | docomo L02C (L02CqmiModem) |
|USB\VID_1004&PID_618F&MI_03 | docomo L02C (L02Cqmindis) |

L-02C のドライバ Windows 10 版が出てないからしょうがない。Linux でこれを再現しよう。

ATコマンド
--------
`AT%USBMODEM=0`をあらかじめ設定しておくと、`eject`動作しなくてもいきなり使える。[参考](http://trtr.hatenablog.jp/entry/2014/11/27/011913)


new_id
-------
Linux kernel driver をリビルドするのが骨が折れるのだけど、よーくよく見てみたら、new_id の挙動が[拡張](https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/drivers/usb/core/driver.c?id=refs/tags/v4.4.16#n52)されていた。

`idVendor idProduct bInterfaceClass refVendor refProduct` の形式で登録できて、refVendor refProduct 相当の動きをするように、変化球をつけられるようになった。ありがたい。今回は gobi1k 相当にする必要があったので、`{DEVICE_G1K(0x05c6, 0x9212)}, /* Acer Gobi Modem device */` を使った。もちろん別のものでも良い。ただし `ModemManager` で [blacklist されているもの](https://sources.debian.net/src/modemmanager/1.4.0-1/debian/77-mm-qdl-device-blacklist.rules/)は避けること（G1K一覧の最初にある `05c6 9211` は NG）。

udev rule
---------
udev のルールとして書くとこんな感じ。`ModemManager`のルールが 77 番台を使うので、それより前にする。

```/etc/udev/rules.d/75-l02c.rules
ATTRS{idVendor}=="1004", ATTRS{idProduct}=="61dd", RUN+="/usr/bin/eject /dev/sr0"
ATTRS{idVendor}=="1004", ATTRS{idProduct}=="618f", RUN+="/sbin/modprobe -b qcserial"
SUBSYSTEM=="drivers", ENV{DEVPATH}=="/bus/usb-serial/drivers/qcserial", ATTR{new_id}="1004 618f 0000 05c6 9212"
SUBSYSTEM=="usb", ATTRS{idVendor}=="1004", ATTRS{idProduct}=="618f", RUN+="/sbin/modprobe -b qmi_wwan"
SUBSYSTEM=="drivers", ENV{DEVPATH}=="/bus/usb/drivers/qmi_wwan", ATTR{new_id}="1004 618f"
```

雑談
----
実は昔一度QMI接続を[試みたことがあった](https://twitter.com/kwi/status/667569723475759104)。が、その時は結局 fon 2.0 の USB ポートに挿せば使えてしまうという簡単さを選択して Linux で認識させるのは一旦ペンディングにしていた。

Routerboard で無線と NAT を引き受けつつ、上流は fon 2.0 から携帯網へ、という構成でしばらく運用してきたけど、人数が多かった時に大いにトラブった。L-02C の網接続が切れまくって、どうにもならず。無線やNAT tableは大丈夫でした。fon 2.0 だからデバッグもできないんですよね…。

というわけで、今回の RPi でのセットアップとなりました。これでまた運用に入れてみよう。

まだ様子見だけど、[dhcpcd で不審な挙動をする](https://github.com/RPi-Distro/repo/issues/12)ということは今のところ観測されていない。

運用してみて
-----------
調子が悪いと、こんなエラーが出たりして USB 再挿入の動作を繰り返すようだった。`qmicli --wds-start-network` の `--wds-follow-network` をつけると stdout つなげたままで情報が取れる。

```
Aug 18 12:25:24 raspberrypi kernel: qmi_wwan 1-1.4:1.3: nonzero urb status received: -71
Aug 18 12:25:24 raspberrypi kernel: qmi_wwan 1-1.4:1.3: wdm_int_callback - 0 bytes
Aug 18 12:25:24 raspberrypi kernel: qmi_wwan 1-1.4:1.3: wdm_int_callback - usb_submit_urb failed with result -19
```

-71 は ECOMM, -19 は ENODEV なのだろう。この後 USB デバイスが違う番号で再認識されたりしているので、L-02C がリセットしている様子。

NMEA
-----
USB の認識順番をログで確認して、`/dev/ttyUSB2` が NMEA インターフェースであることは確認できた。さてひょっとしてこれは GPS が取れるのだろうか？

```
cat /dev/ttyUSB2 &
echo "\$GPS_START" > /dev/ttyUSB2
```

果たして出力は…

```
$GPGGA,,,,,,0,,,,,,,,*66
```

これが延々と出てくる。うーむ。何か足りないのか…？