OpenWrtでRakuten WiFi PocketをUSB接続で使う


環境

  • Rakuten WiFi Pocket R310
    • ソフトウェアバージョン: R310_V3.19_20210302
    • ハードウェアバージョン: V3.0
    • OSバージョン: 3.4.110
    • SIM: Rakuten UN-LIMIT V
root@OpenWrt:~# cat /etc/openwrt_release
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='21.02.0-rc1'
DISTRIB_REVISION='r16046-59980f7aaf'
DISTRIB_TARGET='ath79/generic'
DISTRIB_ARCH='mips_24kc'
DISTRIB_DESCRIPTION='OpenWrt 21.02.0-rc1 r16046-59980f7aaf'
DISTRIB_TAINTS=''

必要なパッケージのインストール

デフォルトではマスストレージデバイスとして認識されているようですので、usb_modeswitchをインストールします。

root@OpenWrt:~# opkg update
root@OpenWrt:~# opkg install usb-modeswitch
root@OpenWrt:~# cat /sys/kernel/debug/usb/devices
...
T:  Bus=01 Lev=02 Prnt=02 Port=01 Cnt=02 Dev#=  5 Spd=480  MxCh= 0
D:  Ver= 2.00 Cls=02(comm.) Sub=00 Prot=00 MxPS=64 #Cfgs=  1
P:  Vendor=19d2 ProdID=1557 Rev= 1.01
S:  Manufacturer=DEMO,Incorporated
S:  Product=DEMO Mobile Boardband
S:  SerialNumber=1234567890ABCDEF
C:* #Ifs= 3 Cfg#= 1 Atr=c0 MxPwr=500mA
A:  FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=06 Prot=00
I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=06 Prot=00 Driver=(none)
E:  Ad=87(I) Atr=03(Int.) MxPS=  16 Ivl=32ms
I:* If#= 1 Alt= 0 #EPs= 0 Cls=0a(data ) Sub=00 Prot=00 Driver=(none)
I:  If#= 1 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=(none)
E:  Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=(none)
E:  Ad=82(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E:  Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=125us

CDC-ECM(0x02,0x06)として認識されたので、cdc_etherカーネルモジュールをインストールします。

root@OpenWrt:~# opkg install kmod-usb-net-cdc-ether
root@OpenWrt:~# dmesg | grep cdc_ether
[  336.882875] usbcore: registered new interface driver cdc_ether
[  341.468475] cdc_ether 1-1.2:1.0 eth1: register 'cdc_ether' at usb-ehci-platform-1.2, ZTE CDC Ethernet Device, 34:4b:50:00:00:00

インターフェースを追加

「wwan」と「wwan6」の名前でインターフェースを追加します。
物理インターフェースの「eth1」に紐付けて、ファイアウォールゾーンの「wan」に割り当てます。

uci set network.wwan=interface
uci set network.wwan.ifname='eth1'
uci set network.wwan.proto='dhcp'
uci set network.wwan6=interface
uci set network.wwan6.ifname='eth1'
uci set network.wwan6.proto='dhcpv6'
uci commit network

uci set dhcp.wwan='dhcp'
uci set dhcp.wwan.interface='wwan'
uci set dhcp.wwan.ignore='1'
uci commit dhcp

uci add_list firewall.@zone[1].network='wwan'
uci add_list firewall.@zone[1].network='wwan6'
uci commit firewall

/etc/init.d/network restart
/etc/init.d/firewall reload

接続テスト

root@OpenWrt:~# ifstatus wwan
...
        "proto": "dhcp",
        "device": "eth1",
        "ipv4-address": [
                {
                        "address": "192.168.0.100",
                        "mask": 24
                }
        ],
        "route": [
                {
                        "target": "0.0.0.0",
                        "mask": 0,
                        "nexthop": "192.168.0.1",
                        "source": "192.168.0.100/32"
                }
        ],
        "dns-server": [
                "192.168.0.1"
        ],
...

root@OpenWrt:~# ifstatus wwan6
...
        "proto": "dhcpv6",
        "device": "eth1",
        "ipv6-address": [
                {
                        "address": "240b:c010:411:d7cb:364b:50ff:fe00:0",
                        "mask": 64,
                        "preferred": 61,
                        "valid": 241
                }
        ],
        "ipv6-prefix": [

        ],
        "ipv6-prefix-assignment": [

        ],
        "route": [
                {
                        "target": "240b:c010:411:d7cb:0:f:9449:eb01",
                        "mask": 64,
                        "nexthop": "::",
                        "metric": 256,
                        "valid": 241,
                        "source": "::/0"
                },
                {
                        "target": "::",
                        "mask": 0,
                        "nexthop": "fe80::1",
                        "metric": 512,
                        "valid": 241,
                        "source": "240b:c010:411:d7cb:364b:50ff:fe00:0/64"
                }
        ],
        "dns-server": [
                "fe80::1"
        ],
...

root@OpenWrt:~# ping -c 4 google.com
PING google.com (172.217.25.238): 56 data bytes
64 bytes from 172.217.25.238: seq=0 ttl=114 time=42.521 ms
64 bytes from 172.217.25.238: seq=1 ttl=114 time=23.051 ms
64 bytes from 172.217.25.238: seq=2 ttl=114 time=21.842 ms
64 bytes from 172.217.25.238: seq=3 ttl=114 time=41.539 ms

root@OpenWrt:~# ping6 -c 4 google.com
PING google.com (2404:6800:4004:81b::200e): 56 data bytes
64 bytes from 2404:6800:4004:81b::200e: seq=0 ttl=115 time=301.799 ms
64 bytes from 2404:6800:4004:81b::200e: seq=1 ttl=115 time=28.033 ms
64 bytes from 2404:6800:4004:81b::200e: seq=2 ttl=115 time=35.634 ms
64 bytes from 2404:6800:4004:81b::200e: seq=3 ttl=115 time=26.224 ms

LAN側のホストからIPv6を使えるようにする

Rakuten WiFi PocketからのRAを見てみます。

Pフラグは0となっていますのでND Proxy (RFC 4389)が使えそうです。
以下のようにND Proxyを設定します。

uci set dhcp.wwan6='dhcp'
uci set dhcp.wwan6.interface='wwan6'
uci set dhcp.wwan6.ndp='relay'
uci set dhcp.wwan6.ra='relay'
uci set dhcp.wwan6.master='1'
uci set dhcp.lan.dhcpv6='server'
uci set dhcp.lan.ndp='relay'
uci set dhcp.lan.ra='relay'
address="$(ifstatus lan | jsonfilter -e '@["ipv6-prefix-assignment"][0]["local-address"].address')"
[ "$address" ] && uci add_list dhcp.lan.dns="$address"
uci commit dhcp

/etc/init.d/odhcpd restart

設定の結果は次のようになります。

  • WWAN6をアップストリームインターフェースに指定します。(master='1')
  • WWAN6/LANインターフェース間でNS/NAパケットをproxyします。(ndp='relay')
  • WWAN6/LANインターフェース間でRS/RAパケットをproxyします。(ra='relay')
  • LANインターフェイスのULAをDNSサーバアドレスとしてリンク上のホストに通知します。(dhcpv6='server', dns=1)

LAN側のホストからipv6.google.comにtraceroute (tracert)してみます。

> tracert ipv6.google.com

ipv6.l.google.com [2404:6800:4004:810::200e] へのルートをトレースしています
経由するホップ数は最大 30 です:

  1    <1 ms    <1 ms    <1 ms  OpenWrt.lan [fd57:1deb:47a3::1]
  2     3 ms     1 ms     1 ms  240b:c010:411:d7cb:0:f:9449:ec01
  3    35 ms    57 ms    41 ms  240b:c010:102:1b58::4
  4    49 ms    52 ms    65 ms  240b:c010:102:1b58::4
  5    55 ms    49 ms    51 ms  240b:c010:102:15e5:0:4:0:584
  6    66 ms    65 ms    68 ms  240b:c010:105::7225:0:1
  7    50 ms    42 ms    31 ms  240b:c010:105::7225:0:2
  8    73 ms    37 ms    74 ms  240b:c010:115::8223:0:0
  9    52 ms    66 ms    45 ms  240b:c010:125::8122:0:0
 10    62 ms    42 ms    58 ms  2001:4860:1:1::14b6
 11    45 ms    58 ms    54 ms  2001:4860:0:1000::1
 12     *        *        *     要求がタイムアウトしました。
 13   108 ms    52 ms    46 ms  nrt12s28-in-x0e.1e100.net [2404:6800:4004:810::200e]

トレースを完了しました。

Rakuten WiFi PocketのTips

Wi-Fiを無効にする場合

Wi-Fiは使用しないので管理画面から無効に設定しましたが、本体のボタンを操作したり再起動すると有効に戻ってしまうようです。

/root/r310-wifi-enabled.sh
#!/bin/sh

ROUTER_IP="192.168.0.1"
USERNAME="admin"
PASSWORD="admin"

log() {
    logger -t "$(basename $0 .sh)" "$1: ${2-$(cat)}"
}

base64_uri() {
    echo -n "$1" | base64 -w0 | jq -sRr @uri
}

loginfo() {
    curl -s "http://$ROUTER_IP/reqproc/proc_get" \
        -H "Referer: http://$ROUTER_IP/index.html" \
        --data "multi_data=1&isTest=false&cmd=loginfo%2C${*// /%2C}"
}

cmd() {
    local loginfo=$(loginfo "$*")
    # Login
    [ "$(echo $loginfo | jq -cRr 'fromjson?|.loginfo')" = ok ] || {
        curl -s "http://$ROUTER_IP/reqproc/proc_post" \
            -H "Referer: http://$ROUTER_IP/index.html" \
            --data "isTest=false&goformId=LOGIN&username=$(base64_uri $USERNAME)&password=$(base64_uri $PASSWORD)" |
        jq -r '.result' |
        log LOGIN
        loginfo=$(loginfo "$*")
    }
    echo "$loginfo" | jq -cR 'fromjson?|del(.loginfo)'
}

# Get Wi-Fi state
wifi_cur_state=$(cmd wifi_cur_state | jq -r '.wifi_cur_state')
[ "$wifi_cur_state" ] || exit 1
log wifi_cur_state "$wifi_cur_state"

# Enable or disable Wi-Fi
wifi_enabled="${1:-0}"
[ "$wifi_cur_state" = "$wifi_enabled" ] || {
    curl -s "http://$ROUTER_IP/reqproc/proc_post" \
        -H "Referer: http://$ROUTER_IP/index.html" \
        --data "goformId=SET_WIFI_INFO&isTest=false&wifiEnabled=$wifi_enabled" |
    jq -r '.result' |
    log wifiEnabled
}
root@OpenWrt:~# opkg install curl jq coreutils-base64
root@OpenWrt:~# chmod +x r310-wifi-enabled.sh
root@OpenWrt:~# ./r310-wifi-enabled.sh
root@OpenWrt:~# ./r310-wifi-enabled.sh 1
root@OpenWrt:~# echo "*/10 * * * * /root/r310-wifi-enabled.sh" >> /etc/crontabs/root
root@OpenWrt:~# /etc/init.d/cron restart

MCC/MNCの取得

ログイン処理が必要だったので上記のスクリプトを使い回しています。

--- r310-wifi-enabled.sh 2021-03-25 16:00:38.991491600 +0900
+++ r310-cmd.sh 2021-03-25 16:01:28.979587700 +0900
@@ -32,17 +32,4 @@
     echo "$loginfo" | jq -cR 'fromjson?|del(.loginfo)'
 }

-# Get Wi-Fi state
-wifi_cur_state=$(cmd wifi_cur_state | jq -r '.wifi_cur_state')
-[ "$wifi_cur_state" ] || exit 1
-log wifi_cur_state "$wifi_cur_state"
-
-# Enable or disable Wi-Fi
-wifi_enabled="${1:-0}"
-[ "$wifi_cur_state" = "$wifi_enabled" ] || {
-    curl -s "http://$ROUTER_IP/reqproc/proc_post" \
-        -H "Referer: http://$ROUTER_IP/index.html" \
-        --data "goformId=SET_WIFI_INFO&isTest=false&wifiEnabled=$wifi_enabled" |
-    jq -r '.result' |
-    log wifiEnabled
-}
+cmd "$*"
$ ./r310-cmd.sh mcc mnc
{"mcc":"440","mnc":"11"}

auローミングが終了したエリアで使用しているため、44053に接続した場合に正しい値を返すかどうかは分かりません。

参考


  1. ra='relay'に設定した場合は、DNSサーバアドレスを明示的に指定しないと受信したRAのRDNSSを書き換えてくれないようなので念のため設定しました。現時点ではRakuten Wifi PocketはRDNSSをサポートしていないので省略しても問題ありません。