← 一覧へ戻る

[Arch Linux][ThinkPad][LTE]X1 Carbon Gen7の内蔵LTE(XMM7360)をModemManagerのgitビルドで動かす方法

ThinkPad X1 Carbon 第7世代に載っているFibocom L850-GL(Intel XMM7360)を、Arch Linuxで通信できる状態まで持っていきました。以前試したときはModemManager 1.26待ちという結論で諦めていたのですが、gitのmainから自前ビルドすれば動くことがわかりました。ただしMVNOのSIMでは繋がらないという制約が残っています。

環境

  1. ThinkPad X1 Carbon Gen 7
  2. Arch Linux
    1. カーネル 6.18.51-1-lts
    2. AURヘルパーはyay
  3. モデム
    1. Fibocom L850-GL / Intel XMM7360
    2. PCI ID 8086:7360
    3. PCIアドレス 02:00.0 (Subsystem 1cf8:8521)
    4. ドライバはmainlineのiosm
  4. ModemManager
    1. リポジトリ版 1.24.2 (XMM7360未対応)
    2. gitビルド版 1.25.95-dev-123-ge1f80615
  5. SIM
    1. IIJmio タイプD
    2. ahamo

現象

iosmがロードされてポート自体は生えています。

/dev/wwan0at0      ATコマンドポート
/dev/wwan0at1      ATコマンドポート(こちらがprimaryになる)
/dev/wwan0xmmrpc0  XMM独自のRPCポート
wwan0              ネットワークインターフェース

しかしArchのModemManager 1.24.2ではモデムが認識されません。XMM7360のネイティブRPCプロトコルへの対応が2026-05-24のコミットで入ったものの、それを含むリリース(1.26)がまだ出ていないためです。

gitからビルドしても、今度は初期化の途中で落ちます。

(intel) Intel XMM7360 in RPC mode found...
--> uta-ms-sms-init      → OK
--> uta-ms-cbs-init      → OK
--> uta-ms-net-open      → OK
--> uta-ms-net-set-radio-signal-reporting  ← ここで無応答
couldn't start initialization: Failed to complete init sequence: Serial command timed out
fatal error initializing: Fatal error: modem is unusable

さらにそこを越えても、IIJmioのSIMでは接続段階で必ず失敗します。

解決方法

1. ModemManagerをgitからprefix分離でビルド

システムのlibqmi/libmbimを置き換えるとNetworkManagerを巻き込むので、/opt/mm-gitに隔離します。AURのmodemmanager-gitはマージ済みパッチが残っていたりPKGBUILDがautotoolsのままだったりで通らなかったので使いません。

sudo pacman -S --needed base-devel meson ninja git gobject-introspection \
  help2man gettext libgudev polkit glib2-devel

mkdir -p ~/src && cd ~/src
git clone https://gitlab.freedesktop.org/mobile-broadband/libmbim.git
git clone https://gitlab.freedesktop.org/mobile-broadband/libqmi.git
git clone https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git

export PREFIX=/opt/mm-git
export PKG_CONFIG_PATH=$PREFIX/lib/pkgconfig
export LD_LIBRARY_PATH=$PREFIX/lib

cd ~/src/libmbim && meson setup build --prefix=$PREFIX -Dintrospection=false \
  && ninja -C build && sudo meson install -C build

cd ~/src/libqmi && meson setup build --prefix=$PREFIX -Dintrospection=false -Dqrtr=false \
  && ninja -C build && sudo meson install -C build

cd ~/src/ModemManager && meson setup build --prefix=$PREFIX \
  -Dintrospection=false -Dqrtr=false \
  -Dsystemdsystemunitdir=no -Dbash_completion=false \
  && ninja -C build && sudo meson install -C build

-Dqrtr=falseをlibqmiだけに付けてModemManagerに付け忘れると、こうなります。MM側のqrtrオプションがautoなので、QRTR無しでビルドしたqmi-glibとぶつかります。

meson.build:327:2: ERROR: Assert failed: Couldn't find QRTR support in qmi-glib.

ArchWikiに「1.25.95-devタグまでのスナップショットはRPCメッセージのパースでassertion failureを起こす」とあるので、タグではなくmainのHEADを使ってください。

git -C ~/src/ModemManager describe --tags
# 1.25.95-dev-123-ge1f80615 のようにコミット数が付いていればOK

mmcli —versionは1.25.95と表示されますが、upstreamが次のバージョンバンプまで文字列を据え置くためで、mainのHEADでもこう出ます。

2. パッケージ版ModemManagerを完全に黙らせる

git版を起動しても即座にこう出て死ぬ場合があります。

<wrn> could not acquire the 'org.freedesktop.ModemManager1' service name

D-Bus名は1プロセスしか持てないので、パッケージ版が先に握っていると起動できません。しかもmmcli -Lは生きているほうに喋りに行くので、「モデムが見つからない」という表示になって原因が見えにくいです。

sudo systemctl stop ModemManager
sudo systemctl mask ModemManager
sudo pkill -f '/usr/bin/ModemManager'

# D-Bus活性化で勝手に起きてくるのも塞ぐ
sudo mv /usr/share/dbus-1/system-services/org.freedesktop.ModemManager1.service{,.disabled}
sudo systemctl reload dbus

pgrep -a ModemManager   # 空になることを確認

パスが/usr/bin/ModemManagerである点に注意。/usr/sbin/だと思い込んでpkillのパターンを外し、何度も同じ失敗を繰り返しました。

3. udevルールを手で入れる

meson installではudevルールがインストールされません。ソースツリーから直接コピーします。

sudo find ~/src/ModemManager/src -name '*.rules' -exec cp {} /etc/udev/rules.d/ \;
sudo udevadm control --reload
sudo udevadm trigger

ルールはsrc/直下(80-mm-candidate.rules)とsrc/plugins/配下(77-mm-xxx-port-types.rules)に分かれています。data/にはありません。

なおIntelプラグイン用のudevルールは存在しません。XMMRPCポートの判別は/sys/class/wwan/wwan0xmmrpc0/typeの内容を見てMM内部で行われます。

4. FCC unlockを有効にする

L850-GLはFCCロックがかかっていて、解錠しないとモデムが使えません。ModemManagerに同梱の解錠スクリプトはデフォルト無効なので、シンボリックリンクを張ります。

sudo ln -sf /opt/mm-git/share/ModemManager/fcc-unlock.available.d/8086:7360 \
  /opt/mm-git/etc/ModemManager/fcc-unlock.d/

手動でも叩けます。

sudo FCC_UNLOCK_DEBUG_LOG=1 /opt/mm-git/share/ModemManager/fcc-unlock.available.d/8086:7360 \
  dummy wwan0at0 wwan0at1 wwan0xmmrpc0
sudo cat /var/log/mm-xmm7360-fcc.log

成功するとこう出ます。

Attempt #1 to unlock WWAN modem
Requesting FCC lock state from modem
Got response from modem: state=0, mode=2
Requesting challenge from modem
Got challenge from modem: dc74416b
Sending hash to modem: 07ca92d3
FCC unlock successful (response 1)

このスクリプトはXMMRPCポートに生バイト列を書き込んでチャレンジを受け取り、ベンダーIDハッシュと連結してSHA-256を取り、先頭4バイトをエンディアン反転して返すという処理をシェルスクリプトでやっています。

state=0はコールドブート直後にしか出ません。検証するときは再起動ではなく完全に電源を落とす必要があります。

5. init sequenceのタイムアウトを伸ばすパッチ

src/plugins/intel/mm-broadband-modem-xmm7360.cのinit_sequenceを見ると、各コマンドのタイムアウトが3秒固定でした。

/* Timeout of the command, in seconds */
guint timeout;

この個体では3秒では足りず、しかも成否がタイミング依存で揺れます(通る回と通らない回がある)。20秒に伸ばしたら安定しました。

cd ~/src/ModemManager
sed -i '1107,1113s/, 3, FALSE, /, 20, FALSE, /' \
  src/plugins/intel/mm-broadband-modem-xmm7360.c
ninja -C build && sudo meson install -C build

行番号はHEADによって変わるので、init_sequenceの定義を見て調整してください。

allow_retry_onceをTRUEにするのは逆効果でした。リトライが走るとRPCポートがI/Oエラーに落ちて、モデムが完全に使用不能になります。

6. 起動と接続

sudo systemctl stop NetworkManager   # 競合を避ける
sudo LD_LIBRARY_PATH=/opt/mm-git/lib /opt/mm-git/sbin/ModemManager --debug

別ターミナルで確認します。

export LD_LIBRARY_PATH=/opt/mm-git/lib
/opt/mm-git/bin/mmcli -L
/opt/mm-git/bin/mmcli -m 0

うまくいくとこうなります。

System   |                drivers: iosm
         |                 plugin: Intel
         |           primary port: wwan0at1
         |                  ports: wwan0 (net), wwan0at1 (at), wwan0xmmrpc0 (xmmrpc)
Status   |                  state: registered
         |            access tech: lte
         |         signal quality: 29% (recent)
3GPP     |            operator id: 44010
         |          operator name: NTT DOCOMO
         |           registration: home
         |   packet service state: attached

接続します。

/opt/mm-git/bin/mmcli -m 0 --simple-connect="apn=spmode.ne.jp,ip-type=ipv4v6"
/opt/mm-git/bin/mmcli -b 0

Status             |          connected: yes
                   |          interface: wwan0
IPv4 configuration |             method: static
                   |            address: 10.x.x.x
                   |             prefix: 0
                   |                dns: 110.163.0.6

prefixが0で返ってくるので、手動で振るときは/32を指定します。ポイントツーポイントなのでゲートウェイ指定は不要です。

sudo ip link set wwan0 up
sudo ip addr add 10.x.x.x/32 dev wwan0
sudo ip route add default dev wwan0
ping -c 3 google.com

64 bytes from rl-in-f138.1e100.net: icmp_seq=1 ttl=106 time=38.9 ms

繋がりました。

7. systemdユニット化

sudo tee /etc/systemd/system/modemmanager-git.service << 'EOF'
[Unit]
Description=ModemManager (git build for XMM7360)
After=polkit.service
Requires=polkit.service

[Service]
Type=dbus
BusName=org.freedesktop.ModemManager1
ExecStart=/opt/mm-git/sbin/ModemManager
Environment=LD_LIBRARY_PATH=/opt/mm-git/lib
Restart=on-abort

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now modemmanager-git

NetworkManagerも新しいlibmm-glibを見る必要があります。これを入れないとnmcli device statusにモデムが出てこず、接続しようとしてNo suitable device found for this connectionになります。

sudo mkdir -p /etc/systemd/system/NetworkManager.service.d
sudo tee /etc/systemd/system/NetworkManager.service.d/override.conf << 'EOF'
[Service]
Environment=LD_LIBRARY_PATH=/opt/mm-git/lib
EOF
sudo systemctl daemon-reload
sudo systemctl restart NetworkManager

あとは普通に繋がります。

nmcli c add type gsm ifname '*' con-name ahamo apn spmode.ne.jp
nmcli c modify ahamo connection.autoconnect yes
nmcli c up ahamo

残った制約:MVNOのSIMでは繋がらない

IIJmio(タイプD、ドコモ網)のSIMでは、どうやっても接続できませんでした。モデムはregistered/attachedまで行き、APNも認証情報もbearerに正しく載っているのに、接続段階で必ず失敗します。

--> (async) uta-ms-net-attach-req
<-- (unsolicited) uta-ms-net-is-attach-allowed-ind-cb
(status が毎回 0xffffffff)
Giving up on attach-net operation after three failed attempts

リトライ上限を3から12に増やして97回試行させましたが全部同じ。認証方式をpap/chapで明示しても、IP typeをipv4単独にしても変わりませんでした。

コードを追うと原因が見えます。src/plugins/intel/mm-bearer-xmm7360.cのattach要求を組み立てる関数がこれです。

static GByteArray *
pack_uta_ms_net_attach_req (void)
{
    static const Xmm7360RpcMsgArg args[] = {
        { XMM7360_RPC_MSG_ARG_TYPE_BYTE, { .b = 0 } },
        { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
        { XMM7360_RPC_MSG_ARG_TYPE_LONG, { .l = 0 } },
        /* ... 以下すべて 0 または 0xffff 固定 ... */
    };
    return xmm7360_rpc_args_to_byte_array (args);
}

全フィールドが定数で、APNも認証情報も何も運んでいません。ログにもallowed auth: unknownと出ます。

ahamo(ドコモ直販なので認証不要)のSIMに差し替えて同じことをやったら、一発で繋がりました。

SIM認証attach試行結果
IIJmio タイプDPAP/CHAP必須97回全てstatus 0xffffffff
ahamo不要1回connected: yes

同一ハード・同一ビルド・同一手順での差なので、原因は認証情報がattach要求に載っていないことで確定です。

以前xmm7360-pciのopen_xdatachannel.pyを使っていたときも、まったく同じ地点で詰まっていました。あちらもpack_UtaMsCallPsAttachApnConfigReqにAPNしか渡しておらず、PAP/CHAPを送っていません。別実装が同じ場所に同じ形の穴を持っているわけで、このRPCの解析がまだそこまで到達していないことの表れだと思います。

SIMを差し替えるときの注意

初期EPS bearerのAPNがモデム内部に残ります。IIJmioからahamoに差し替えたとき、initial bearer apnがiijmio.jpのままドコモ網に登録しようとしてregistration deniedになりました。

export LD_LIBRARY_PATH=/opt/mm-git/lib
/opt/mm-git/bin/mmcli -m 0 --3gpp-set-initial-eps-bearer-settings="apn=spmode.ne.jp,ip-type=ipv4v6"
/opt/mm-git/bin/mmcli -m 0 --3gpp-register-home

—3gpp-register-homeも必要でした。待っているだけではidleのまま動きません。

SIMの抜き差しは電源を落としてから。活線で入れ替えるとFCCロック状態に戻って—enableが要ります。

回り道したところ

ATポートが死んでいると誤診した

Serial command timed outを見て「ATが応答しない」と判断し、こういうテストをしました。

sudo sh -c 'exec 3<>/dev/wwan0at1; printf "AT\r" >&3; timeout 3 head -c 100 <&3 | xxd'

無反応。両ポートとも。コールドブート直後でもFCC unlock直後でも無反応。「この個体ではATインターフェースが使えない」という結論に一度傾きました。

ところがpicocomで叩いたら普通に返ってきました。

$ sudo picocom -b 115200 /dev/wwan0at1
Terminal ready
AT
OK

テスト方法が間違っていただけでした。デバイスを開いてすぐ読みに行っていて、応答が返る前にタイムアウトしていたようです。wwanのキャラクタデバイスはttyとは挙動が違うので、素直にシリアル端末で確認したほうが確実です。

誤診に基づいて「ATポートをudevでMMから隠す」という対策まで打ちましたが、当然これは逆効果でFailed to find primary AT portになるだけでした。ルールを削除したら通るようになったという間抜けな結末です。

ログのgrepでキーワードを欲張った

広く取ると無関係なttyS4(Intel AMTのシリアルポート)のプローブログが大量に混ざって、肝心の行がheadやtailから押し出されます。このモデムのデバイスパスは0000:02:00.0、プラグインマネージャのタスクはtask 2なので、そこで絞るのが早いです。

grep -E 'task 2|02:00\.0' /tmp/mm.log

ttyS4のプローブに毎回20秒かかるのはAMTのシリアルポートを掴もうとしているだけで、LTEとは無関係です。

タイムアウト延長が効くケースと効かないケース

init sequenceの3秒から20秒は効きました。一方、attach要求のタイムアウトを3秒から60秒に伸ばしたのは完全に無駄でした。ログを見ると応答は数ミリ秒で返っているんですよね。返ってきた内容が「失敗」なだけで。

「タイムアウトした」というエラーメッセージを見たとき、遅れているのか、そもそも来ないのか、来ているけど中身が失敗なのかを区別しないと、見当違いの対策を打つことになります。

まとめ

X1 Carbon Gen 7の内蔵LTEは、ModemManagerをgitから自前ビルドすれば動きます。必要なのはprefix分離ビルド、パッケージ版の無効化、udevルールの手動配置、FCC unlockの有効化、init sequenceのタイムアウト延長パッチの5点です。

ただしMVNO(認証が必要なAPN)では現状繋がりません。ahamoやドコモ直販のような認証不要の回線なら実用できます。

ModemManager 1.26がリリースされればprefix分離ビルドは不要になるはずですが、attachの認証問題は別途対応が必要です。upstreamに報告予定。

正直、素直にテザリングしたほうが早いです。それでも動いたときは嬉しいので、こういうのはやめられません。

参考

  1. xmm7360-pci - ArchWiki
  2. ModemManager - GitLab
  3. xmm7360-pci - GitHub

コメント

読み込み中…

    URLを含むコメントは、確認後に表示されます。