QMI trace of VoLTE registration

TLDR; the trace

To document and improve the understanding of VoLTE, I've created pcap traces of the QMI message of the VoLTE registration.

The original pcap file has been created using a Oneplus 6T running lineageos/Android with a german 1&1 simcard of the brand maxxim, which uses the Vodafone network in Germany.

To capture the traffic I've used SCAT and qmi-frida-tracer.

SCAT is used to capture radio packets within the same trace, it both exports NAS-EPS (radio management), but also user traffic. It makes it easier to put QMI messages into relation with messages on the radio side and improve the understanding. E.g. a NAS-EPS or SIP message trigger an event on the QMI side. Also if a QMI TLV is unknown, we might use the radio message to decipher it.

qmi-frida-tracer was ran against the following daemons:

  • qcrild (first pid)
  • qcrild (second pid)
  • imsdatadaemon
  • imsqmidaemon

I've put the Oneplus 6T into an usb mode supporting all 3: diag,adb and rmnet.

rmnet is required to use qmicli later to set the correct PDC profile to allow the Android to register to VoLTE.

Test setup

The setup consist of 2x VMs:

  • 1x VM where all the tools ran and the Oneplus 6T is connected (192.168.56.108)
  • 1x VM where the traffic is captured and wireshark runs. (192.168.56.1)

Put the Oneplus 6T into the correct usb mode:

adb root; sleep 1; adb shell setprop sys.usb.config diag,serial_cdev,rmnet,adb

Running SCAT (git version 7eac9c5bea) with: scat -u -t qc -v 0x05c6 -p 0x9091 -i 0 -H 192.168.56.1

qmi-frida-trace to pass traffic to 192.168.56.1 (modify line where 127.0.0.1 is set as target):

./qmi-frida-tracer.py -n imsdatadaemon
./qmi-frida-tracer.py -n imsqmidaemon
./qmi-frida-tracer.py -p 1584 # first qcrild pid
./qmi-frida-tracer.py -p 1598 # second qcrild pid

Additional I'll set later a VoLTE capable PDC profile using qmicli -d /dev/cdc-wdm0 --pdc-activate-config=software,2F:1D:0C:4C:28:2D:50:FC:03:84:D8:9E:F3:92:81:C7:DB:A5:1A:7E.

Modification of the trace

For privacy reasons the pcap file which has been published here, has been filtered, but the essential parts are present. All packets which contain either the IMSI, IMEI, phone number or location have been removed. Further:

  • Service 0x44 was removed. The service is still unknown, but not suspected to interact with IMS (yet).
  • All radio packets (from SCAT) except a couple ones, have been removed, because most of them contains privacy related informations.
  • All data packets have been removed including SIP, RTP traffic, because those contains both the IMEI, phone number and called phone number.
  • The responses of the simcard (service: uim) to Read Transparent File or Read Record and request/responses of Send APDU.
  • NAS: Get Signal Info has been removed, because it clutters the pcap.
  • Voice service: Dial Call and All Call Status were removed, but no IMS specific parts.

To get the most use out of the pcap, please use the wireshark dissector embedded into the .tar.gz of the pcap.

wireshark -X lua_script:qmi_dissector_gen.lua -X lua_script:scat.lua ./trace_volte.pcapng

I've commented on a couple packets, there are some QMI messages which are unknown to libqmi, I've looked them up, but all aren't related. To most I've added comments to the packet in the pcap. I recommend adding the comment coloumn to the packet overview. It is possible to use the source port of the UDP/GSMTAP message to determine which process received or sent the QMI message.

From the traffic I deduct:

  • 44303: imsdatadaemon
  • 39675: qcrild (it could be also imsqmidaemon, but the traffic contains to much additional traffic)
  • 58075: qcrild
  • 49595: scat (radio packets)

The most interesting parts of the pcap are:

  • filter qmi.service_id == 0x0012 || qmi.service_id == 0x302 showing IMS subsystem traffic
  • filter udp.srcport == 44303 showing traffic of the imsdatadaemon

If you would like to know more about the pcap or have questions about the removed parts, you can reach us by the matrix channel #openimsd:postmarketos.org

Test report

All times in UTC:

  • 10:48: Reboot phone
  • 10:49: Put phone into airplane without simcard, enable adb root, switch mode to rmnet/qmi + diag + adb
  • 10:49: start scat
  • 10:50: attach frida to current rild processes
  • 10:54: put simcard into the phone
  • 11:01: enter required pin 4556
  • 11:02: check if qcrild still have correct pids (sometime they change)
  • 11:15: enable frida also for imsqmidaemon & imsdatadaemon
  • 11:18: disable airplane
  • 11:20: enable airplane
  • 11:23: check if qcrild still have correct pids (sometime they change)
  • 11:24: libqmi: set pdc profile, failed CID allocation failed. timed out
  • 11:25: qmicli: pdc: exceute monitor-refresh, get software list, re-do libqmi set pdc profile again, works now
  • 11:26: disable airplane
  • 11:30: check VoLTE registration via phone info debug ui (*#*#4636#*#*), VoLTE registered!
  • 11:39: calling another phone
  • 11:42: get called by another phone
  • 11:43: terminate call
  • 11:44: enable airplane

wireshark filter

To filter for privacy I used the following chaos filter:

((frame.marked == true) || ((((!(qmi.service_id == 0x0047) ) && !( (qmi.message_id == 0x0039) && qmi.service_id == 0x0b)) && !((qmi.message_id == 0x0020) && (qmi.service_id == 0xb) && (qmi.trans_response == 1)) && !((qmi.message_id == 0x0021) && (qmi.service_id == 0x0b)  && (qmi.trans_response == 1)) && !((qmi.message_id == 0x0024) && (qmi.service_id == 0x02)  && (qmi.trans_response == 1))) && !lte_rrc &&  !((qmi.message_id == 0x0043) && (qmi.service_id == 0x03)  && (qmi.trans_response == 1)) &&  !((qmi.message_id == 0x004d || qmi.message_id == 0x00ac) && (qmi.service_id == 0x03)  && (qmi.trans_response == 1)) &&  !(((qmi.message_id == 0x0082) || (qmi.message_id == 0x00c3 || qmi.message_id == 0x004e || qmi.message_id == 0x0051) ) && (qmi.service_id == 0x03)  && (qmi.trans_indication == 1)) && ((qmi.message_id == 0x003b) && (qmi.service_id == 0x0b))  && !gsm_a.ccch  && !lte_rrc  && (!qmi.service_id ==0x44) && !evs && !amr && !udp.port == 47290 && !(ip.flags.mf == True) && !lte_rrc && !nas-eps))

The trace

This project was funded through the NGI0 Core Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 101092990.

links

social