Linux QMAP qmi_wwan multiple PDN setup

Linux QMAP support in qmi_wwan was introduced in kernel v4.12-rc1, with significant bug-fixes in v4.20 and v5.2-rc6.

For those who are unaware of what qmap means, it is Qualcomm way of supporting multiple PDNs with a single rmnet device.

Linux QMAP

The IP datagrams are encapsulated in packets, whose stream is identified by a unique id to be managed by the operating system network interfaces.

Linux QMAP and libqmi

On the user-space side, libqmi through qmicli can be used for setting up qmap-based data connections: the procedure is not complex, but there are a few tricks not easy to understand at a first glance, so the following procedure can help to get quick on the track.

  • Stop ModemManager if running (e.g. in Ubuntu type service ModemManager stop).
  • For better throughput, usually modems require to set a proper dl-datagram-max-size (meaning the maximum sized aggregated amount of data coming from the modem), but this requires to modify the size of the rx urb in the driver. It’s not possible to directly set this from userspace, but changing the qmi_wwan main interface MTU has the side effect to change also the rx_urb_size. To simplify the MTU setting verify that the network interface is not in raw_ip mode:
cat /sys/class/net/<qmi_Wwan netdevice>/qmi/raw_ip

Note that, if you don’t have the commit described in post “qmi_wwan MTU fix after raw_ip switch“, switching to ‘N’ won’t work and you should reboot the modem or reload the kernel module.

  • Configure qmi_wwan master network interface:
# ip link set <qmi_wwan netdevice> down
# ip link set <qmi_wwan netdevice> mtu <dl-datagram-max-size>
  • Create qmap network interfaces:
# cd /sys/class/net/<qmi_wwan netdevice>/qmi/
# echo <qmap mux id 1> > add_mux
# echo <qmap mux id 2> > add_mux
# ip link set <qmi_wwan netdevice> up
# ip link set <QMAP netdevice 1> up
# ip link set <QMAP netdevice 2> up
  • Configure the modem
# qmicli -d <cdc_wdm device> --wda-set-data-format=link-layer-protocol=raw-ip,ul-protocol=qmap,dl-protocol=qmap,dl-max-datagrams=32,dl-datagram-max-size=<dl-datagram-max-size>
  • Bind mux and setup data connection for first qmap network interface and PDN 1:
# qmicli -d <cdc_wdm device> --wds-noop --client-no-release-cid
# qmicli -d <cdc_wdm device> --wds-bind-mux-data-port=mux-id=<qmap mux id 1>,ep-iface-number=2 --client-no-release-cid --client-
 cid=<client cid 1>
# qmicli -d <cdc_wdm device> --wds-start-network=apn=<apn 1> --
 client-no-release-cid --client-cid=<client cid 1>
# qmicli -d <cdc_wdm device> --wds-get-current-settings --client-
 no-release-cid --client-cid=<client cid 1>
  • Configure qmap network interface with the returned address information:
# ip addr add <ip>/<bitmask> dev <QMAP netdevice 1>
  • Do the same for second network interface
# qmicli -d <cdc_wdm device> --wds-noop --client-no-release-cid
# qmicli -d <cdc_wdm device> --wds-bind-mux-data-port=mux-id=<qmap mux id 2>,ep-iface-number=2 --client-no-release-cid --client-
 cid=<client cid 2>
# qmicli -d <cdc_wdm device> --wds-start-network=apn=<apn 2> --
 client-no-release-cid --client-cid=<client cid 2>
# qmicli -d <cdc_wdm device> --wds-get-current-settings --client-
 no-release-cid --client-cid=<client cid 2>
# ip addr add <ip>/<bitmask> dev <QMAP netdevice 2>

If the commands return no error, the data connections should be up.

Testing Linux QMAP data connections can be done with two simple routes and a ping test:

# ip route add 8.8.8.8 via <gateway ip 1>
# ip route add 8.8.4.4 via <gateway ip 2>
# ping 8.8.8.8 -I <QMAP netdevice 1>
# ping 8.8.4.4 -I <QMAP netdevice 2>