Linux MBIM wwan multiple pdn setup

Kernel v5.13 saw the first appearance of the WWAN (Wireless wide area network) subsystem, an attempt to have a common approach to many different driver in the kernel managing WWAN devices (mostly cellular).

In kernel v5.14, Linux MBIM wwan support for multiple pdns has been added: let’s see how easy it is to setup multiple simultaneous data connections with the wwan subsystem, iproute2 and mbimcli.

Linux MBIM wwan

Linux MBIM wwan support in iproute2

The first check to be done is verifying if the version of iproute2 in the system supports wwan:

$ ip link help
Usage: ip link add [link DEV | parentdev NAME] [ name ] NAME
<snip>
	ip link help [ TYPE ]

TYPE := { bareudp | bond | bond_slave | bridge | bridge_slave |
          dummy | erspan | geneve | gre | gretap | ifb |
          ip6erspan | ip6gre | ip6gretap | ip6tnl |
          ipip | ipoib | ipvlan | ipvtap |
          macsec | macvlan | macvtap |
          netdevsim | nlmon | rmnet | sit | team | team_slave |
          vcan | veth | vlan | vrf | vti | vxcan | vxlan | wwan |
          xfrm }

If the wwan type is available, then the version of iproute2 is ok, otherwise a more recent release can be built from the sources available at the project repo.

The second step is to verify that actually there’s a MBIM wwan device in the system. Listing sysfs directory

$ ls /sys/class/wwan/
wwan0  wwan0mbim0  wwan0qmi0

should show a wwanxmbimy devices.

The related netdevice can be identified with:

$ ./ip/ip link show
...
2: wwan0: <POINTOPOINT,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/[519]

Setting-up the data connection

It’s time to start using our Linux MBIM wwan device!

Add the netdevices with the desired session-ids using ip:

ip link add <wwan netdevice name> parentdev wwan0 type wwan linkid <session id>

Supposing we want to use ids 1 and 2:

$ ip link add wwan0-1 parentdev wwan0 type wwan linkid 1
$ ip link add wwan0-2 parentdev wwan0 type wwan linkid 2

Netdevice creation can be checked with:

$ ip link show
...
2: wwan0: <POINTOPOINT,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/[519] 
...
5: wwan0-1: <POINTOPOINT,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/[519] 
6: wwan0-2: <POINTOPOINT,NOARP> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/[519]

With mbimcli check for modem initialization:

$ mbimcli -d /dev/wwan0mbim0 --query-subscriber-ready-status --no-close
[/dev/wwan0mbim0] Subscriber ready status retrieved:
	      Ready state: 'initialized'
	    Subscriber ID: '222101627429691'
	        SIM ICCID: '8939104240067637288F'
	       Ready info: 'none'
	Telephone numbers: (0) 'unknown'
[/dev/wwan0mbim0] Session not closed:
	    TRID: '3'

Attach the modem to the packet service:

$ mbimcli -d /dev/wwan0mbim0 --attach-packet-service --no-open=4 --no-close
[/dev/wwan0mbim0] Successfully attached to packet service

[/dev/wwan0mbim0] Packet service status:
	         Network error: 'unknown'
	  Packet service state: 'attached'
	Available data classes: 'lte'
	          Uplink speed: '0 bps'
	        Downlink speed: '0 bps'
[/dev/wwan0mbim0] Session not closed:
	    TRID: '5'

Then setup the connection for session-id 1:

$ mbimcli -d /dev/wwan0mbim0 --connect=apn='web.omnitel.it',session-id=1 --no-open=6 --no-close
[/dev/wwan0mbim0] Successfully connected

[/dev/wwan0mbim0] Connection status:
	      Session ID: '1'
	Activation state: 'activated'
	Voice call state: 'none'
	         IP type: 'ipv4'
	    Context type: 'internet'
	   Network error: 'unknown'

[/dev/wwan0mbim0] IPv4 configuration available: 'address, gateway, dns, mtu'
     IP [0]: '109.118.180.1/30'
    Gateway: '109.118.180.2'
    DNS [0]: '10.133.47.142'
    DNS [1]: '10.132.100.181'
        MTU: '1500'

Configure netdevice wwan0-1 with the returned information:

$ ip addr add 109.118.180.1/30 dev wwan0-1

Repeat the procedure for session-id 2:

$ mbimcli -d /dev/wwan0mbim0 --connect=apn='mobile.vodafone.it',session-id=2 --no-open=9 --no-close
[/dev/wwan0mbim0] Successfully connected

[/dev/wwan0mbim0] Connection status:
	      Session ID: '2'
	Activation state: 'activated'
	Voice call state: 'none'
	         IP type: 'ipv4'
	    Context type: 'internet'
	   Network error: 'unknown'

[/dev/wwan0mbim0] IPv4 configuration available: 'address, gateway, dns, mtu'
     IP [0]: '100.107.179.69/30'
    Gateway: '100.107.179.70'
    DNS [0]: '10.133.47.150'
    DNS [1]: '10.132.100.212'
        MTU: '1500'

[/dev/wwan0mbim0] IPv6 configuration available: 'none'
[/dev/wwan0mbim0] Session not closed:
	    TRID: '11'

$ ip addr add 100.107.179.69/30 dev wwan0-2

For basic testing, it is possible to configure two simple routes:

$ sudo ip link set wwan0-2 up
$ sudo ip link set wwan0-1 up
$ sudo ip route add 8.8.8.8 via 109.118.180.2
$ sudo ip route add 8.8.4.4 via 100.107.179.70

and start pinging the test addresses:

$ ping 8.8.8.8 -I wwan0-1 
PING 8.8.8.8 (8.8.8.8) from 109.118.180.1 wwan0-1: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=112 time=184 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=112 time=45.6 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=112 time=61.6 ms
...
^C
--- 8.8.8.8 ping statistics ---
40 packets transmitted, 40 received, 0% packet loss, time 39062ms
rtt min/avg/max/mdev = 40.569/48.691/184.129/22.159 ms

$ ping 8.8.4.4 -I wwan0-2 
PING 8.8.4.4 (8.8.4.4) from 100.107.179.69 wwan0-2: 56(84) bytes of data.
64 bytes from 8.8.4.4: icmp_seq=1 ttl=111 time=41.8 ms
64 bytes from 8.8.4.4: icmp_seq=2 ttl=111 time=45.7 ms
64 bytes from 8.8.4.4: icmp_seq=3 ttl=111 time=46.7 ms
...
^C
--- 8.8.4.4 ping statistics ---
26 packets transmitted, 26 received, 0% packet loss, time 25042ms
rtt min/avg/max/mdev = 40.724/44.433/51.836/2.574 ms

To disconnect the sessions:

$ mbimcli -d /dev/wwan0mbim0 --disconnect=2 --no-open=12 --no-close
[/dev/wwan0mbim0] Successfully disconnected

[/dev/wwan0mbim0] Connection status:
	      Session ID: '2'
	Activation state: 'deactivated'
	Voice call state: 'none'
	         IP type: 'default'
	    Context type: 'internet'
	   Network error: 'unknown'
[/dev/wwan0mbim0] Session not closed:
	    TRID: '13'

$ mbimcli -d /dev/wwan0mbim0 --disconnect=1 --no-open=14
[/dev/wwan0mbim0] Successfully disconnected

[/dev/wwan0mbim0] Connection status:
	      Session ID: '1'
	Activation state: 'deactivated'
	Voice call state: 'none'
	         IP type: 'default'
	    Context type: 'internet'
	   Network error: 'unknown'

Finally, the netdevices can be deleted:

$ sudo ip link delete wwan0-1
$ sudo ip link delete wwan0-2

A bit easier than using QMAP, but getting the same result!