Linux
RaspberryPi
udev

Raspberry Piで、L-03DをEthernetとして認識する

More than 1 year has passed since last update.


やっぱり

前回USBモデムL-03Dの認識ができたが、ttyとして認識し、PPPを使う。世は既にPDPtype=IPで、本来PPPは不要。さらに、L-03Dの取説によると、


L-03D Connection Manager でのパケット通信は、より高速な NDIS 方式(無線LANのような方式)となっております。従来のダイヤルアップでの接続を行うこともできます。


とあり、NDIS方式のほうが高速そうな書きぶりだ。


QMI

Qualcomm社のモデムインターフェースはQMIで、ttyとは異なる専用インターフェース。これを扱えるオープンソースlibqmiがあると友人が教えてくれた。ありがとう & びっくり。

Raspberry Pi + UX302NCの例はこちらが答えそのもので、このエントリーも不要なくらい。これをL-03Dでやってみる。


まるっきり真似

登録するドライバーは2つ。


  1. qmi_wwan: 取説で言うNDIS相当のドライバーで、制御用の/dev/cdc-wdm0とNICのwwan0ができる

  2. qcserial: ATコマンド等が使える従来のttyUSB*ができる


/etc/udev/rules.d/99-l03d.rules

ATTRS{idVendor}=="1004", ATTRS{idProduct}=="6327", RUN+="/usr/bin/eject /dev/sr0"

SUBSYSTEM=="usb", ATTRS{idVendor}=="1004", ATTRS{idProduct}=="6326", RUN+="/sbin/modprobe -b qmi_wwan"
SUBSYSTEM=="drivers", ENV{DEVPATH}=="/bus/usb/drivers/qmi_wwan", ATTR{new_id}="1004 6326"
ATTRS{idVendor}=="1004", ATTRS{idProduct}=="6326", RUN+="/sbin/modprobe -b qcserial"
SUBSYSTEM=="drivers", ENV{DEVPATH}=="/bus/usb-serial/drivers/qcserial", ATTR{new_id}="1004 6326"

ATTR{new_id}は、VID/PIDをL-03Dに合わせて変更した。


動作確認

pi@raspberrypi:~ $ lsmod

Module Size Used by
:
qcserial 5129 0
usb_wwan 7104 1 qcserial
usbserial 29640 2 qcserial,usb_wwan
:
qmi_wwan 11679
cdc_wdm 10749 1 qmi_wwan
:
pi@raspberrypi:~ $ usb-devices
:
T: Bus=01 Lev=02 Prnt=02 Port=01 Cnt=02 Dev#= 5 Spd=480 MxCh= 0
D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=1004 ProdID=6326 Rev=00.00
S: Manufacturer=NTT DOCOMO, INC.
S: Product=docomo L03D
C: #Ifs= 4 Cfg#= 1 Atr=80 MxPwr=500mA
I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=qcserial
I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan
I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan

うーむ、qmi_wwanが2個できるのは変。

root@raspberrypi:~# qmicli -d /dev/cdc-wdm0 --dms-get-manufactuarer

(しーん)
^Z
root@raspberrypi:~# qmicli -d /dev/cdc-wdm1 --dms-get-manufactuarer
[/dev/cdc-wdm1] Device manufacturer retrieved:
Manufacturer: 'QUALCOMM INCORPORATED'

1つは生きているようだが、気持ち悪い。


再調査


Windowsでは

Windowsの公式ドライバではどうか。

ドライバのプロパティの詳細などを見ると…


  • USB Serial Port = MI_00 (COMポート)

  • NMEA Serial Port = MI_01 (COMポート)

  • Modem Driver = MI_02 (ATコマンドのCOMポート)

  • USB NDIS Driver = MI_03

というUSB Composite Deviceの構成。これを認識するには…。


udevのnew_id

そもそも、udevで設定しているATTR{new_id}="1004 6326"とは何なのか。

こちらにある通り、ドライバーに書かれていないVID/PIDを持ったデバイスを、特定のドライバーで登録できるようになっている。これは便利。だが、USB Composite Deviceの順番は指定できないのか。

本家によると、


idVendor idProduct bInterfaceClass RefIdVendor RefIdProduct


の並びが指定できる。今回はClassは全部0xffっぽいし、ダメか…。


ドライバーのソースを読む


linux/drivers/usb/serial/qcserial.c

        /*

* Composite mode; don't bind to the QMI/net interface as that
* gets handled by other drivers.
*/

switch (id->driver_info) {
case QCSERIAL_G1K:
/*
* Gobi 1K USB layout:
* 0: DM/DIAG (use libqcdm from ModemManager for communication)
* 1: serial port (doesn't respond)
* 2: AT-capable modem port
* 3: QMI/net
*/

if (nintf < 3 || nintf > 4) {
dev_err(dev, "unknown number of interfaces: %d\n", nintf);
altsetting = -1;
goto done;
}

if (ifnum == 0) {
dev_dbg(dev, "Gobi 1K DM/DIAG interface found\n");
altsetting = 1;
} else if (ifnum == 2)
dev_dbg(dev, "Modem port found\n");
else
altsetting = -1;
break;


nintfの0〜2がCOMポートと認識するようにすれば良さそうだが、同じ並びのものはこのソースには無さそう…。新しいdriver_infoを定義しようと思ったが、面倒になった。そこで…。


ドライバ改造(インチキ)

何故インチキかと言うと、L-03DはGOBI1Kではないが、USB Composite Deviceの構成が似ているGOBI1Kの定義をそのまま使っているから…。


qcserial


drivers/usb/serial/qcserial.c

--- a/drivers/usb/serial/qcserial.c

+++ b/drivers/usb/serial/qcserial.c
@@ -74,6 +74,7 @@ static const struct usb_device_id id_table[] = {
{DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */
{DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */
{DEVICE_G1K(0x1bc7, 0x900e)}, /* Telit Gobi QDL device */
+ {DEVICE_G1K(0x1004, 0x6326)}, /* NTT docomo L-03D */

/* Gobi 2000 devices */
{USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */


qmi_wwan


drivers/net/usb/qmi_wwan.c

--- a/drivers/net/usb/qmi_wwan.c

+++ b/drivers/net/usb/qmi_wwan.c
@@ -812,6 +812,7 @@ static const struct usb_device_id products[] = {
{QMI_GOBI1K_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */
+ {QMI_GOBI1K_DEVICE(0x1004, 0x6326)}, /* NTT docomo L-03D */

/* 5. Gobi 2000 and 3000 devices */
{QMI_GOBI_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */


動作再確認


デバイス認識

pi@raspberrypi:~ $ lsmod

Module Size Used by
qcserial 5225 0
usb_wwan 7104 1 qcserial
qmi_wwan 11703 0
cdc_wdm 10749 1 qmi_wwan
usbserial 29640 2 qcserial,usb_wwan
:
pi@raspberrypi:~$ usb-devices
:
T: Bus=01 Lev=02 Prnt=02 Port=02 Cnt=02 Dev#= 5 Spd=480 MxCh= 0
D: Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=1004 ProdID=6326 Rev=00.00
S: Manufacturer=NTT DOCOMO, INC.
S: Product=docomo L03D
C: #Ifs= 4 Cfg#= 1 Atr=80 MxPwr=500mA
I: If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
I: If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
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

If#=0と1が(none)になっているが、とりあえず、If#=2のATコマンドポートと、If#=3のwwanが現れた。


iijmioで接続


qmicliインストール

sudo apt-get install libqmi-utils


設定ファイル設置


/etc/qmi-network.conf

APN=iijmio.jp,CHAP,mio@iij,iij



APN接続

pi@raspberrypi:~$ sudo qmi-network /dev/cdc-wdm0 start

Loading profile...
APN: iijmio.jp,CHAP,mio@iij,iij
Starting network with 'qmicli -d /dev/cdc-wdm0 --wds-start-network=iijmio.jp,CHAP,mio@iij,iij --client-no-release-cid'...
error: couldn't start network: QMI protocol error (14): 'CallFailed'
call end reason (3): generic-no-service
verbose call end reason (3,2001): [cm] no-service
Saving state... (CID: 1)
error: network start failed, no packet data handle
Clearing state...

つながらん。qmicli --help-allしたコマンドを片っ端から打っても、つながらん。最新のlibqmiをビルドして使っても、つながらん。

pi@raspberrypi:~ $ sudo qmicli -d /dev/cdc-wdm0 --nas-get-system-info

[/dev/cdc-wdm0] Successfully got system info:
GSM service:
Status: 'none'
True Status: 'none'
Preferred data path: 'no'
WCDMA service:
Status: 'none'
True Status: 'none'
Preferred data path: 'no'
LTE service:
Status: 'limited'
True Status: 'limited-regional'
Preferred data path: 'no'
Domain: 'unknown'
Service capability: 'ps'
Roaming status: 'off'
Forbidden: 'no'
Location Area Code: 'xxxxx'
Cell ID: 'xxxxxxxx'
MCC: '440'
MNC: '10'
Tracking Area Code: '0'
Voice support: 'yes'

このlimitedが問題のようだ。


PPP接続

この状態で、PPP接続してみる。

pi@raspberrypi:~ $ sudo pon iijmio.jp

pi@raspberrypi:~ $ ifconfig ppp0
ppp0 Link encap:Point-to-Point Protocol
inet addr:100.xx.xx.xx P-t-P:10.64.64.64 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 Metric:1
RX packets:17 errors:0 dropped:0 overruns:0 frame:0
TX packets:18 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:3
RX bytes:1435 (1.4 KiB) TX bytes:941 (941.0 B)

ちゃんとつながる。

sudo poffした後、もう一度sudo qmicli -d /dev/cdc-wdm0 --nas-get-system-infoすると、LTE serviceStatus: 'available'となる。一旦availableになると、

pi@raspberrypi:~ $ sudo qmi-network /dev/cdc-wdm0 start

Loading profile...
APN: iijmio.jp,CHAP,mio@iij,iij
Starting network with 'qmicli -d /dev/cdc-wdm0 --wds-start-network=iijmio.jp,CHAP,mio@iij,iij --client-no-release-cid'...
Saving state... (CID: 1)
Saving state... (PDH: 36003144)
Network started successfully

…となり、QMIでつながる。

pi@raspberrypi:~ $ ifconfig wwan0

wwan0 Link encap:Ethernet HWaddr xx:xx:xx:xx:xx:xx
inet addr:100.xx.xxx.xxx Bcast:100.255.255.255 Mask:255.0.0.0
inet6 addr: fe80::d058:5531:253a:32e3/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:34 errors:0 dropped:0 overruns:0 frame:0
TX packets:98 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:3525 (3.4 KiB) TX bytes:14876 (14.5 KiB)

うーむ、何をすればavailableになるのか。


USBキャプチャ

WindowsのWiresharkでは、usbpcapが使える。これと同じQMI制御を行えば、PPP接続しなくてもネットワークにつながるはず。

実際にUSBキャプチャは動作したのだが、ここまでやって、気づいてしまったのだ。

pi@raspberrypi:~ $ sudo 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'
LTE bands: '1'

Band1しか使えないのかよ! そもそも、2012年発売と、かなり古いのであった…。


オチ

面倒なので、UX302NC買います!

でも、YAMAHASEIL(L-02Cだが)も使えるので、絶対使う方法はあるはずなのだが…くやしい。