This repository has been archived by the owner. It is now read-only.

Get qualcomm modems working #1054

Closed
lawl opened this Issue Dec 29, 2017 · 20 comments

Comments

Projects
None yet
6 participants
@lawl
Contributor

lawl commented Dec 29, 2017

This issue is to split out the progress on getting qualcomm modems working from the general cellular modem issue since I like to document the progress also for myself, and for everyone else that wants to look into this. Last but not least to avoid duplicate work.

@lawl

This comment has been minimized.

Show comment
Hide comment
@lawl

lawl Dec 29, 2017

Contributor

Quick update:

All of this work is currently on my dev phone and not packaged since all of this is explorative at this point.

My understanding currently is that we could maybe completely skip rild on qualcom modems since ofono can talk qmi and there is a project here that translates qmi to qmuxd socket messages. Not sure though.

Quick rundown of what I have done so far for documentation purposes and in case someone else also wants to look into this and as a memo for myself.

I run qmuxd by simply ripping /vendor/lib64 /system/lib64 and /system/bin/linker64 out of the lineageOS system and throw them on my phone, this allows qmuxd to run using the lineageOS bionic stuff. (For development purposes only, to be trimmed down/chrooted/namespaced/seccomp'd to smithereens)

The error creating the sockets above was from me not really paying attention. qmuxd calls setuid(1001) so even though i was running it as root and prepared the /dev/socket/... folders for it, it failed of course.

This is my current preparation script:

# cat makesockets.sh 
#!/bin/sh
mkdir /dev/socket

mkdir /dev/socket/qmux_bluetooth
chown 1001 /dev/socket/qmux_bluetooth

mkdir /dev/socket/qmux_radio
chown 1001 /dev/socket/qmux_radio

mkdir /dev/socket/qmux_audio
chown 1001 /dev/socket/qmux_audio

mkdir /dev/socket/qmux_gps
chown 1001 /dev/socket/qmux_gps

mkdir /dev/socket/qmux_nfc
chown 1001 /dev/socket/qmux_nfc

qmuxd now runs and listens for connections.

I now run socat PTY,link=/tmp/qmiserial2qmuxd .pty,cfmakeraw EXEC:"./qmiserial2qmuxd" which requires a small patch to add an #ifdef ANDROID guard for the termio.h include.

This successfully connects to qmuxd which we can also confirm by running qmuxd in strace

open_qmuxd_socket: connected to qmuxd and received client id 1

Cool, now we want something to run test-queries against it, so we compile libqmi which contains a command line utility qmiclient. This requires a small patch to build against musl that isn't in the latest stable tarball yet.

So we run

qmicli -d /tmp/qmiserial2qmuxd.pty --dms-get-msisdn

and we get

send_qmuxd_request: [1]< 0 34
qmuxd_read_loop: unknown/unsupported qmuxd message 11
handle_qmuxd_response: [1, syserr=-5, qmierr=0, length=3360]< 11 0
handle_qmuxd_response: qmuxd reports syserr; not forwarding to serial

Well, actually we get a bit less output, but i removed the call to exit() on error.

And this is where I'm at now currently. Next planned step. Patch qmiserial2qmuxd a bit more to get the raw response from qmuxd and/or get some logging output from qmuxd, but from straceing it, it doesn't seem like it tries to log anything to android's debuggerd socket, will need to take a closer look though.

Contributor

lawl commented Dec 29, 2017

Quick update:

All of this work is currently on my dev phone and not packaged since all of this is explorative at this point.

My understanding currently is that we could maybe completely skip rild on qualcom modems since ofono can talk qmi and there is a project here that translates qmi to qmuxd socket messages. Not sure though.

Quick rundown of what I have done so far for documentation purposes and in case someone else also wants to look into this and as a memo for myself.

I run qmuxd by simply ripping /vendor/lib64 /system/lib64 and /system/bin/linker64 out of the lineageOS system and throw them on my phone, this allows qmuxd to run using the lineageOS bionic stuff. (For development purposes only, to be trimmed down/chrooted/namespaced/seccomp'd to smithereens)

The error creating the sockets above was from me not really paying attention. qmuxd calls setuid(1001) so even though i was running it as root and prepared the /dev/socket/... folders for it, it failed of course.

This is my current preparation script:

# cat makesockets.sh 
#!/bin/sh
mkdir /dev/socket

mkdir /dev/socket/qmux_bluetooth
chown 1001 /dev/socket/qmux_bluetooth

mkdir /dev/socket/qmux_radio
chown 1001 /dev/socket/qmux_radio

mkdir /dev/socket/qmux_audio
chown 1001 /dev/socket/qmux_audio

mkdir /dev/socket/qmux_gps
chown 1001 /dev/socket/qmux_gps

mkdir /dev/socket/qmux_nfc
chown 1001 /dev/socket/qmux_nfc

qmuxd now runs and listens for connections.

I now run socat PTY,link=/tmp/qmiserial2qmuxd .pty,cfmakeraw EXEC:"./qmiserial2qmuxd" which requires a small patch to add an #ifdef ANDROID guard for the termio.h include.

This successfully connects to qmuxd which we can also confirm by running qmuxd in strace

open_qmuxd_socket: connected to qmuxd and received client id 1

Cool, now we want something to run test-queries against it, so we compile libqmi which contains a command line utility qmiclient. This requires a small patch to build against musl that isn't in the latest stable tarball yet.

So we run

qmicli -d /tmp/qmiserial2qmuxd.pty --dms-get-msisdn

and we get

send_qmuxd_request: [1]< 0 34
qmuxd_read_loop: unknown/unsupported qmuxd message 11
handle_qmuxd_response: [1, syserr=-5, qmierr=0, length=3360]< 11 0
handle_qmuxd_response: qmuxd reports syserr; not forwarding to serial

Well, actually we get a bit less output, but i removed the call to exit() on error.

And this is where I'm at now currently. Next planned step. Patch qmiserial2qmuxd a bit more to get the raw response from qmuxd and/or get some logging output from qmuxd, but from straceing it, it doesn't seem like it tries to log anything to android's debuggerd socket, will need to take a closer look though.

@lawl

This comment has been minimized.

Show comment
Hide comment
@lawl

lawl Dec 29, 2017

Contributor

Interesting project from the same guy/gal that wrote qmiserial2qmuxd where they apparently managed to get basic functionality working without qmuxd: https://github.com/scintill/android_frameworks_opt_telephony_ril_ofono

According to this we'll also need /system/bin/rmt_storage.

Contributor

lawl commented Dec 29, 2017

Interesting project from the same guy/gal that wrote qmiserial2qmuxd where they apparently managed to get basic functionality working without qmuxd: https://github.com/scintill/android_frameworks_opt_telephony_ril_ofono

According to this we'll also need /system/bin/rmt_storage.

@lawl

This comment has been minimized.

Show comment
Hide comment
@lawl

lawl Dec 29, 2017

Contributor

To get debug output from qmuxd and rmt_storage, we can run the following python script. This creates the socket these log to and sends their messages to stdout there is some binary garbage (packet headers?) in there, but we can read the text messages just fine:

import socket
import sys
import os

server_address = '/dev/socket/logdw'

try:
    os.unlink(server_address)
except OSError:
    if os.path.exists(server_address):
        raise

s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
s.bind(server_address)
while 1:
    data = s.recv(1024)
    if not data: break
    print(data)
s.close()

Cleaned up output from rmt_storage:

rmt_storageRemote storage service is not supported on undefined target

Cleaned up output from qmuxd:

libmdmdetectESOC framework not supported
libmdmdetectFound internal modem: modem
Diag_Lib Diag_LSM_Init: Failed to open handle to diag driver, error = 13
libmdmdetectESOC framework not supported
libmdmdetectFound internal modem: modem
QC-QMIlinux_qmi_qmux_io_pwr_up_init.c: Unable to open wakelock file = /sys/power/wake_lock, error [13:Permission denied]

QC-DS-LIBqmuxd: linux_qmi_read_sysfs_config: couldn't open file /sys/module/f_rmnet/parameters/rmnet_ctl_ch
QC-DS-LIBqmuxd: linux_qmi_read_sysfs_config: couldn't open /sys/module/rmnet/parameters/rmnet_ctl_ch
QC-QMIqmuxd: Cannot parse qmi_config.undefined.control_ports_len, config file /system/etc/data/qmi_config.xml

QC-DS-LIBqmuxd:  Failed to load XML configuration [/system/etc/data/qmi_config.xml] for target [undefined], all ports disabled

QC-QMIlinux_qmi_qmux_io_stop_watchdog_timer(): invalid timer_id for conn_id=60

Next step throw rmt_storage into IDA?

Contributor

lawl commented Dec 29, 2017

To get debug output from qmuxd and rmt_storage, we can run the following python script. This creates the socket these log to and sends their messages to stdout there is some binary garbage (packet headers?) in there, but we can read the text messages just fine:

import socket
import sys
import os

server_address = '/dev/socket/logdw'

try:
    os.unlink(server_address)
except OSError:
    if os.path.exists(server_address):
        raise

s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
s.bind(server_address)
while 1:
    data = s.recv(1024)
    if not data: break
    print(data)
s.close()

Cleaned up output from rmt_storage:

rmt_storageRemote storage service is not supported on undefined target

Cleaned up output from qmuxd:

libmdmdetectESOC framework not supported
libmdmdetectFound internal modem: modem
Diag_Lib Diag_LSM_Init: Failed to open handle to diag driver, error = 13
libmdmdetectESOC framework not supported
libmdmdetectFound internal modem: modem
QC-QMIlinux_qmi_qmux_io_pwr_up_init.c: Unable to open wakelock file = /sys/power/wake_lock, error [13:Permission denied]

QC-DS-LIBqmuxd: linux_qmi_read_sysfs_config: couldn't open file /sys/module/f_rmnet/parameters/rmnet_ctl_ch
QC-DS-LIBqmuxd: linux_qmi_read_sysfs_config: couldn't open /sys/module/rmnet/parameters/rmnet_ctl_ch
QC-QMIqmuxd: Cannot parse qmi_config.undefined.control_ports_len, config file /system/etc/data/qmi_config.xml

QC-DS-LIBqmuxd:  Failed to load XML configuration [/system/etc/data/qmi_config.xml] for target [undefined], all ports disabled

QC-QMIlinux_qmi_qmux_io_stop_watchdog_timer(): invalid timer_id for conn_id=60

Next step throw rmt_storage into IDA?

@lawl

This comment has been minimized.

Show comment
Hide comment
@lawl

lawl Dec 29, 2017

Contributor

This is pseudocode for my understanding of what the check does that spits out the undefined target message in rmt_storage:

var baseband = property_get("ro.baseband");
var supported_basebands = ["msm", "apq", "dsda3", "sqlte"];
if(!supported_basebands.contains(baseband)){
    android_log_print("rmt_storage", "Remote storage service is not supported on %s target\n", baseband);
    property_set("ctl.stop", "rmt_storage");
    exit(1);
}

property_get is an import and my understanding of how this works is that it queries /dev/socket/property_service which I think is provided by android's init.

So the options are

a) binary patch it
b) write a simple emulator for the property service that feeds it whatever we need, it's it's quite likely qmuxd calls property_get() too and it might be used in other places in the binary.

Contributor

lawl commented Dec 29, 2017

This is pseudocode for my understanding of what the check does that spits out the undefined target message in rmt_storage:

var baseband = property_get("ro.baseband");
var supported_basebands = ["msm", "apq", "dsda3", "sqlte"];
if(!supported_basebands.contains(baseband)){
    android_log_print("rmt_storage", "Remote storage service is not supported on %s target\n", baseband);
    property_set("ctl.stop", "rmt_storage");
    exit(1);
}

property_get is an import and my understanding of how this works is that it queries /dev/socket/property_service which I think is provided by android's init.

So the options are

a) binary patch it
b) write a simple emulator for the property service that feeds it whatever we need, it's it's quite likely qmuxd calls property_get() too and it might be used in other places in the binary.

@lawl lawl referenced this issue Dec 29, 2017

Closed

Let's get the cellular modem working! #598

0 of 6 tasks complete
@lawl

This comment has been minimized.

Show comment
Hide comment
@lawl

lawl Dec 29, 2017

Contributor

Actually, it's reading the properties from /dev/__properties__ and writes to /dev/socket/property_service. @opendata26 graciously provided his /dev/__properties__ folder and his /property_contexts file. Slapping these into my file system sucessfully get's past that crash and we get a bit further in running rmt_service. We can trim these down later too, probably.

�	K(���y
              �rmt_storageShared memory initialised successfully.
�	K(����
              �rmt_storageFailed to open partition /dev/block/bootdevice/by-name/modemst1 err 2 (No such file or directory). This is very bad!!!

�	K(�B�
             �rmt_storageUnable to open /dev/block/bootdevice/by-name

�	K(��>�
              �rmt_storageFailed to open partition /dev/block/bootdevice/by-name/modemst2 err 2 (No such file or directory). This is very bad!!!

�	K(�6�"
              �rmt_storageUnable to open /dev/block/bootdevice/by-name

�	K(���Q
              �rmt_storageFailed to open partition /dev/block/bootdevice/by-name/fsc err 2 (No such file or directory). This is very bad!!!

�	K(���v
              �rmt_storageUnable to open /dev/block/bootdevice/by-name

�	K(����
              �rmt_storageFailed to open partition /dev/block/bootdevice/by-name/fsg err 2 (No such file or directory). This is very bad!!!

�	K(����
              �rmt_storageUnable to open /dev/block/bootdevice/by-name

�	K(�-��
              �rmt_storage0 GPT partitions found

This is very good!!! :)

Contributor

lawl commented Dec 29, 2017

Actually, it's reading the properties from /dev/__properties__ and writes to /dev/socket/property_service. @opendata26 graciously provided his /dev/__properties__ folder and his /property_contexts file. Slapping these into my file system sucessfully get's past that crash and we get a bit further in running rmt_service. We can trim these down later too, probably.

�	K(���y
              �rmt_storageShared memory initialised successfully.
�	K(����
              �rmt_storageFailed to open partition /dev/block/bootdevice/by-name/modemst1 err 2 (No such file or directory). This is very bad!!!

�	K(�B�
             �rmt_storageUnable to open /dev/block/bootdevice/by-name

�	K(��>�
              �rmt_storageFailed to open partition /dev/block/bootdevice/by-name/modemst2 err 2 (No such file or directory). This is very bad!!!

�	K(�6�"
              �rmt_storageUnable to open /dev/block/bootdevice/by-name

�	K(���Q
              �rmt_storageFailed to open partition /dev/block/bootdevice/by-name/fsc err 2 (No such file or directory). This is very bad!!!

�	K(���v
              �rmt_storageUnable to open /dev/block/bootdevice/by-name

�	K(����
              �rmt_storageFailed to open partition /dev/block/bootdevice/by-name/fsg err 2 (No such file or directory). This is very bad!!!

�	K(����
              �rmt_storageUnable to open /dev/block/bootdevice/by-name

�	K(�-��
              �rmt_storage0 GPT partitions found

This is very good!!! :)

@lawl

This comment has been minimized.

Show comment
Hide comment
@lawl

lawl Dec 30, 2017

Contributor
# mkdir -p /dev/block/bootdevice/by-name/
# ln -s /dev/disk/by-partlabel/modemst1 /dev/block/bootdevice/by-name/modemst1
# ln -s /dev/disk/by-partlabel/modemst2 /dev/block/bootdevice/by-name/modemst2
# ln -s /dev/disk/by-partlabel/fsc /dev/block/bootdevice/by-name/fsc
# ln -s /dev/disk/by-partlabel/fsg /dev/block/bootdevice/by-name/fsg

and we get

H���!�;�rmt_storageShared memory initialised successfully.
H��kpI;�rmt_storageRegistering modemst1: 0x4a /boot/modem_fs1

H����r;�rmt_storageRegistering modemst2: 0x4b /boot/modem_fs2

H�����rmt_storageRegistering fsc: 0xff /boot/modem_fsc

H���0+�rmt_storageRegistering fsg: 0x58 /boot/modem_fsg

H��h�H�rmt_storage4 GPT partitions found

H��-P���rmt_storageCapset success!
H������QMI_FWxport_reg Failed for service_id=0xe version=0x1 on 12

H��l�;��rmt_storageUnable to register service!

rmt_storage drops a bunch of capabilities. It then calls

setgid(3004)                            = 0
setuid(9999)                            = 0

It now tries to create a socket

bind(12, {sa_family=AF_IB, sa_data="\0\0\1\0\0\0\16\0\0\0\1\0\0\0\0\0\0\0"}, 20) = -1 EPERM (Operation not permitted)

The interesting part here is sa_family=AF_IB, which seems to mean Native InfiniBand address.

According to Wikipedia, InfiniBand

is used for data interconnect both among and within computers.

This leads me to believe it's actually trying to talk to the radio :)

Reasons why it fails here could be manyfold, either e.g. missing permissions on the user(group) it drops to, or the fact that the android properties i currently use aren't from this phone and it could try to access the wrong address(?).

Contributor

lawl commented Dec 30, 2017

# mkdir -p /dev/block/bootdevice/by-name/
# ln -s /dev/disk/by-partlabel/modemst1 /dev/block/bootdevice/by-name/modemst1
# ln -s /dev/disk/by-partlabel/modemst2 /dev/block/bootdevice/by-name/modemst2
# ln -s /dev/disk/by-partlabel/fsc /dev/block/bootdevice/by-name/fsc
# ln -s /dev/disk/by-partlabel/fsg /dev/block/bootdevice/by-name/fsg

and we get

H���!�;�rmt_storageShared memory initialised successfully.
H��kpI;�rmt_storageRegistering modemst1: 0x4a /boot/modem_fs1

H����r;�rmt_storageRegistering modemst2: 0x4b /boot/modem_fs2

H�����rmt_storageRegistering fsc: 0xff /boot/modem_fsc

H���0+�rmt_storageRegistering fsg: 0x58 /boot/modem_fsg

H��h�H�rmt_storage4 GPT partitions found

H��-P���rmt_storageCapset success!
H������QMI_FWxport_reg Failed for service_id=0xe version=0x1 on 12

H��l�;��rmt_storageUnable to register service!

rmt_storage drops a bunch of capabilities. It then calls

setgid(3004)                            = 0
setuid(9999)                            = 0

It now tries to create a socket

bind(12, {sa_family=AF_IB, sa_data="\0\0\1\0\0\0\16\0\0\0\1\0\0\0\0\0\0\0"}, 20) = -1 EPERM (Operation not permitted)

The interesting part here is sa_family=AF_IB, which seems to mean Native InfiniBand address.

According to Wikipedia, InfiniBand

is used for data interconnect both among and within computers.

This leads me to believe it's actually trying to talk to the radio :)

Reasons why it fails here could be manyfold, either e.g. missing permissions on the user(group) it drops to, or the fact that the android properties i currently use aren't from this phone and it could try to access the wrong address(?).

@JBBgameich

This comment has been minimized.

Show comment
Hide comment
@JBBgameich

JBBgameich Dec 30, 2017

Contributor

This is a completely blind guess, but in Halium, a few groups and permissions are set up which could also be relevant for your qualcomm blobs: https://github.com/Halium/rootfs-builder/blob/ubuntu/customization/hooks/01-setup_user_group.chroot

Contributor

JBBgameich commented Dec 30, 2017

This is a completely blind guess, but in Halium, a few groups and permissions are set up which could also be relevant for your qualcomm blobs: https://github.com/Halium/rootfs-builder/blob/ubuntu/customization/hooks/01-setup_user_group.chroot

@lawl

This comment has been minimized.

Show comment
Hide comment
@lawl

lawl Dec 31, 2017

Contributor

To test working around permission issues I decided it's time to start LD_PRELOAD hacking

int setuid(int uid){
	return 0;
}

compile with gcc -shared -fPIC -nostdlib lel.c -o lel.so. This nukes their calls to drop privileges and keeps them running as root, this is just for testing and not meant for production.

When we now run LD_PRELOAD=$PWD/lel.so strace ./rmt_storage we get.

recvfrom(13, 0x7fe8bd5e70, 20, MSG_DONTWAIT, NULL, NULL) = -1 ENOMSG (No message of desired type)
pselect6(14, [12 13], NULL, NULL, NULL, NULL

Which, could be okay? Maybe there is just no message, not sure, at least it's not exiting or crashing anymore.

When we now run qmuxd with the same hack, we get

      �QC-QMIlinux_qmi_qmux_io.c: Unable to open port id /dev/smdcntl0, error [110:Connection timed out]

K��x}
     �QC-QMIqmi_qmux_open_connection: QMI_QMUX_IO_PLATFORM_OPEN_CONN failed conn_id=0 rc=-1 

K��&u�
      �QC-DS-LIBqmuxd: opening connection for conn_id=0 [DATA5_CNTL] failed on attempt 2, Waiting 50 milliseconds before retry

K+��<��QC-QMIlinux_qmi_qmux_io.c: Unable to open port id /dev/smdcntl0, error [110:Connection timed out]

K+��Ɣ�QC-QMIqmi_qmux_open_connection: QMI_QMUX_IO_PLATFORM_OPEN_CONN failed conn_id=0 rc=-1 

In dmesg we get a bunch of

[ 2342.217539] smd_pkt_open: wait on smd_pkt_dev id:0 allocation failed rc:-110
Contributor

lawl commented Dec 31, 2017

To test working around permission issues I decided it's time to start LD_PRELOAD hacking

int setuid(int uid){
	return 0;
}

compile with gcc -shared -fPIC -nostdlib lel.c -o lel.so. This nukes their calls to drop privileges and keeps them running as root, this is just for testing and not meant for production.

When we now run LD_PRELOAD=$PWD/lel.so strace ./rmt_storage we get.

recvfrom(13, 0x7fe8bd5e70, 20, MSG_DONTWAIT, NULL, NULL) = -1 ENOMSG (No message of desired type)
pselect6(14, [12 13], NULL, NULL, NULL, NULL

Which, could be okay? Maybe there is just no message, not sure, at least it's not exiting or crashing anymore.

When we now run qmuxd with the same hack, we get

      �QC-QMIlinux_qmi_qmux_io.c: Unable to open port id /dev/smdcntl0, error [110:Connection timed out]

K��x}
     �QC-QMIqmi_qmux_open_connection: QMI_QMUX_IO_PLATFORM_OPEN_CONN failed conn_id=0 rc=-1 

K��&u�
      �QC-DS-LIBqmuxd: opening connection for conn_id=0 [DATA5_CNTL] failed on attempt 2, Waiting 50 milliseconds before retry

K+��<��QC-QMIlinux_qmi_qmux_io.c: Unable to open port id /dev/smdcntl0, error [110:Connection timed out]

K+��Ɣ�QC-QMIqmi_qmux_open_connection: QMI_QMUX_IO_PLATFORM_OPEN_CONN failed conn_id=0 rc=-1 

In dmesg we get a bunch of

[ 2342.217539] smd_pkt_open: wait on smd_pkt_dev id:0 allocation failed rc:-110
@MartijnBraam

This comment has been minimized.

Show comment
Hide comment
@MartijnBraam

MartijnBraam Jan 12, 2018

Member

I guess there is a higher chance of qualcomm having hacked something into the kernel that misuses infiniband addressing than that it actually using inifiniband to communicate with the modem (which is normally used in supercomputers and large SAN's for datacenters)

Member

MartijnBraam commented Jan 12, 2018

I guess there is a higher chance of qualcomm having hacked something into the kernel that misuses infiniband addressing than that it actually using inifiniband to communicate with the modem (which is normally used in supercomputers and large SAN's for datacenters)

@scintill

This comment has been minimized.

Show comment
Hide comment
@scintill

scintill Jan 22, 2018

Contributor

I stumbled on this thread, and I'm glad to see you've made some sense out of my work and have gotten started making broader applications of it!

AF_IB is likely actually AF_MSMIPC, the Qualcommm IPC socket type, but it's not mainlined, so tools like strace interpret the value as a different constant name. I'm not very familiar with postmarketOS yet -- are you running a mainline kernel (not Android)? If you're not using an Android kernel, qmuxd and rmt_storage probably aren't going to work. There is an open-source equivalent of rmt_storage here, and I have a fork that works on top of AF_MSMIPC.

I would probably recommend skipping qmuxd. For a long time, I didn't understand what magic it was doing to send QMI since I couldn't get my tools to work. I finally figured out the issue was that poll() on the smdcntl0 device didn't work how qmicli et al expected. I fixed that with this LD_PRELOAD wrapper. This might be specific to Qualcomm's patches in the Android kernels, though. Anyway, if you can find a serial device you can talk QMI to, I would use that directly rather than qmuxd and qmiserial2qmuxd.

My readme here might have some pointers on getting the modem up (maybe your SMD timeout issues), but maybe your kernel/device is different. It also might not be necessary if you're using enough proprietary stuff -- from what I can tell the proprietary things are more robust at initialization right now, so apparently I haven't learned and implemented some parts of that process.

I won't have a lot of time to hack on this, but I'll try to keep track and help where I can. When you get oFono up, I can show you some patches that haven't merged yet, to add some features like voicecall support.

Contributor

scintill commented Jan 22, 2018

I stumbled on this thread, and I'm glad to see you've made some sense out of my work and have gotten started making broader applications of it!

AF_IB is likely actually AF_MSMIPC, the Qualcommm IPC socket type, but it's not mainlined, so tools like strace interpret the value as a different constant name. I'm not very familiar with postmarketOS yet -- are you running a mainline kernel (not Android)? If you're not using an Android kernel, qmuxd and rmt_storage probably aren't going to work. There is an open-source equivalent of rmt_storage here, and I have a fork that works on top of AF_MSMIPC.

I would probably recommend skipping qmuxd. For a long time, I didn't understand what magic it was doing to send QMI since I couldn't get my tools to work. I finally figured out the issue was that poll() on the smdcntl0 device didn't work how qmicli et al expected. I fixed that with this LD_PRELOAD wrapper. This might be specific to Qualcomm's patches in the Android kernels, though. Anyway, if you can find a serial device you can talk QMI to, I would use that directly rather than qmuxd and qmiserial2qmuxd.

My readme here might have some pointers on getting the modem up (maybe your SMD timeout issues), but maybe your kernel/device is different. It also might not be necessary if you're using enough proprietary stuff -- from what I can tell the proprietary things are more robust at initialization right now, so apparently I haven't learned and implemented some parts of that process.

I won't have a lot of time to hack on this, but I'll try to keep track and help where I can. When you get oFono up, I can show you some patches that haven't merged yet, to add some features like voicecall support.

@lawl

This comment has been minimized.

Show comment
Hide comment
@lawl

lawl Jan 22, 2018

Contributor

Hey there! It's awesome you're chiming in, i haven't had a lot of time to hack on this either lately. But if you do have time, I do have some questions.

AF_IB is likely actually AF_MSMIPC, the Qualcommm IPC socket type, but it's not mainlined, so tools like strace interpret the value as a different constant name.

Ahh! That'd make sense. I'll look into that.

are you running a mainline kernel (not Android)?

No this is currently an android kernel running alpine linux userland (musl/busybox). Specifically it's running the LineageOS kernel for my phone. (Our plan is to eventually move to mainline, but that's probably not practical to start with, so we still mostly use outdated android kernels, except for a few phones where mainlining work has already been started, e.g. the N900).

I would probably recommend skipping qmuxd.

Sorry, you're way more knowledgeable than me. My understanding was that we need qmuxd to talk to the modem? My understanding was that you can't talk to newer chipsets via QMI anymore and need qmuxd to talk to the modem via shared memory devices. Is that wrong?

Anyway, if you can find a serial device you can talk QMI to, I would use that directly rather than qmuxd and qmiserial2qmuxd.

Uhh, it shows I have no clue what I'm doing here, do you have any pointers on how I would figure out if my device can talk QMI directly (and possibly how to identify the appropriate serial device)?

Anyways, I hope I can look a bit more deeply into your response in the comming days. I really appreciate you finding this. I didn't dare trying to ping you yet with anything before looking further into this!

Contributor

lawl commented Jan 22, 2018

Hey there! It's awesome you're chiming in, i haven't had a lot of time to hack on this either lately. But if you do have time, I do have some questions.

AF_IB is likely actually AF_MSMIPC, the Qualcommm IPC socket type, but it's not mainlined, so tools like strace interpret the value as a different constant name.

Ahh! That'd make sense. I'll look into that.

are you running a mainline kernel (not Android)?

No this is currently an android kernel running alpine linux userland (musl/busybox). Specifically it's running the LineageOS kernel for my phone. (Our plan is to eventually move to mainline, but that's probably not practical to start with, so we still mostly use outdated android kernels, except for a few phones where mainlining work has already been started, e.g. the N900).

I would probably recommend skipping qmuxd.

Sorry, you're way more knowledgeable than me. My understanding was that we need qmuxd to talk to the modem? My understanding was that you can't talk to newer chipsets via QMI anymore and need qmuxd to talk to the modem via shared memory devices. Is that wrong?

Anyway, if you can find a serial device you can talk QMI to, I would use that directly rather than qmuxd and qmiserial2qmuxd.

Uhh, it shows I have no clue what I'm doing here, do you have any pointers on how I would figure out if my device can talk QMI directly (and possibly how to identify the appropriate serial device)?

Anyways, I hope I can look a bit more deeply into your response in the comming days. I really appreciate you finding this. I didn't dare trying to ping you yet with anything before looking further into this!

@scintill

This comment has been minimized.

Show comment
Hide comment
@scintill

scintill Jan 23, 2018

Contributor

Sorry, you're way more knowledgeable than me. My understanding was that we need qmuxd to talk to the modem?

My knowledge might also be outdated at this point, as my phone was released in 2013. Maybe you are right about the newer chipsets. Also, maybe you should start with the proprietary stack after all, until you see some success. Anyway, on my device (Samsung GS4 Mini LTE aka I9195 aka serranoltexx), qmuxd talks QMI to SMD serial devices, exposing a socket-based protocol for rild, which qmuxd proxies to the serial device (I think one reason is preventing multiple clients from interfering with each other talking to the same serial device.) When I use the wrapper I linked above, I can directly use the serial device similarly to a QMI USB modem attached to a PC, or how the phone looks to a PC when I put it in a tethering mode (something like setprop sys.usb.config diag,serial_smd,serial_tty,rmnet_bam,mass_storage,adb)

What device do you have? To see if your phone is similar to mine, try looking in /sys/class/smdpkt to see if you have smdpkt devices. For me, /dev/smdcntl0 is the main one for phone functions. I think things like GPS are available on others. There is also information in /sys/kernel/debug/smd , although I'm drawing a blank now on how I've correlated the names in tbl with devices.

Based on your rmt_storage errors and qmuxd timing out trying to connect to the SMD device, I would guess the modem is not booting. On my device, if rmt_storage isn't working, then the modem fails and can't be talked to over SMD. When you blocked the setuid() call, what is rmt_storage's log output?

Contributor

scintill commented Jan 23, 2018

Sorry, you're way more knowledgeable than me. My understanding was that we need qmuxd to talk to the modem?

My knowledge might also be outdated at this point, as my phone was released in 2013. Maybe you are right about the newer chipsets. Also, maybe you should start with the proprietary stack after all, until you see some success. Anyway, on my device (Samsung GS4 Mini LTE aka I9195 aka serranoltexx), qmuxd talks QMI to SMD serial devices, exposing a socket-based protocol for rild, which qmuxd proxies to the serial device (I think one reason is preventing multiple clients from interfering with each other talking to the same serial device.) When I use the wrapper I linked above, I can directly use the serial device similarly to a QMI USB modem attached to a PC, or how the phone looks to a PC when I put it in a tethering mode (something like setprop sys.usb.config diag,serial_smd,serial_tty,rmnet_bam,mass_storage,adb)

What device do you have? To see if your phone is similar to mine, try looking in /sys/class/smdpkt to see if you have smdpkt devices. For me, /dev/smdcntl0 is the main one for phone functions. I think things like GPS are available on others. There is also information in /sys/kernel/debug/smd , although I'm drawing a blank now on how I've correlated the names in tbl with devices.

Based on your rmt_storage errors and qmuxd timing out trying to connect to the SMD device, I would guess the modem is not booting. On my device, if rmt_storage isn't working, then the modem fails and can't be talked to over SMD. When you blocked the setuid() call, what is rmt_storage's log output?

@mirh

This comment has been minimized.

Show comment
Hide comment
@mirh

mirh Feb 2, 2018

Just for the records, A LOT of QMI-related work has just been scheduled for mainline in 4.16
https://patchwork.codeaurora.org/patch/396259/
https://patchwork.codeaurora.org/patch/396263/

mirh commented Feb 2, 2018

Just for the records, A LOT of QMI-related work has just been scheduled for mainline in 4.16
https://patchwork.codeaurora.org/patch/396259/
https://patchwork.codeaurora.org/patch/396263/

@scintill

This comment has been minimized.

Show comment
Hide comment
@scintill

scintill Feb 27, 2018

Contributor

I got QMI calls working on my i9195!! Due to time shortage I didn't do something really cool like send an SMS, but I'm pretty confident that's just a matter of getting the right packages built (see bottom of post.) Maybe somebody else will have the honor of sending the first SMS from postmarketOS on a Qualcomm device. ;)

Here are some commands and example output that will hopefully help others.

# get https://github.com/scintill/pmbootstrap/tree/qmimodem for the aports I added
./pmbootstrap.py install --add rmtfs,libsmdpkt_wrapper,libqmi

# Then, over ssh:
# mount modem firmware that kernel hotplug system requests (hacky, will temporarily disappear any other firmware...)
sudo mount -o ro /dev/disk/by-partlabel/modem /lib/firmware
sudo mount -o bind /lib/firmware/image /lib/firmware
ls /lib/firmware
# keymaste.b00  mldap.b02  modem.b04  modem.mdt	  modem_fw.b09	modem_fw.b17  modem_fw.b31  prov.mdt  q6.mdt	    skm.b01	  sshdcpap.b03	tima_key.b00  tima_lkm.b02  tima_pkm.mdt  vidc.b01   wcnss.b04
# keymaste.b01  mldap.b03  modem.b05  modem_fw.b00  modem_fw.b10	modem_fw.b18  modem_fw.fli  q6.b00    sec_stor.b00  skm.b02	  sshdcpap.mdt	tima_key.b01  tima_lkm.b03  tzapps.b00	  vidc.b02   wcnss.b05
# keymaste.b02  mldap.mdt  modem.b06  modem_fw.b01  modem_fw.b11	modem_fw.b23  modem_fw.mdt  q6.b01    sec_stor.b01  skm.b03	  tima_atn.b00	tima_key.b02  tima_lkm.mdt  tzapps.b01	  vidc.b03   wcnss.b06
# keymaste.b03  modem.b00  modem.b07  modem_fw.b02  modem_fw.b12	modem_fw.b24  prov.b00	    q6.b03    sec_stor.b02  skm.mdt	  tima_atn.b01	tima_key.b03  tima_pkm.b00  tzapps.b02	  vidc.mdt   wcnss.mdt
# keymaste.mdt  modem.b01  modem.b08  modem_fw.b03  modem_fw.b13	modem_fw.b25  prov.b01	    q6.b04    sec_stor.b03  sshdcpap.b00  tima_atn.b02	tima_key.mdt  tima_pkm.b01  tzapps.b03	  wcnss.b00
# mldap.b00     modem.b02  modem.b09  modem_fw.b04  modem_fw.b15	modem_fw.b27  prov.b02	    q6.b05    sec_stor.mdt  sshdcpap.b01  tima_atn.b03	tima_lkm.b00  tima_pkm.b02  tzapps.mdt	  wcnss.b01
# mldap.b01     modem.b03  modem.b10  modem_fw.b05  modem_fw.b16	modem_fw.b28  prov.b03	    q6.b06    skm.b00	    sshdcpap.b02  tima_atn.mdt	tima_lkm.b01  tima_pkm.b03  vidc.b00	  wcnss.b02

# link paths that rmtfs looks to for servicing modem requests (your device's paths may vary; see your error output from rmtfs)
sudo ln -s /dev/disk/by-partlabel/modemst1 /boot/modem_fs1
sudo ln -s /dev/disk/by-partlabel/modemst2 /boot/modem_fs2
sudo ln -s /dev/disk/by-partlabel/fsg      /boot/modem_fsg

# put firmware log in background
tail -f /var/log/firmwareload.log &

sudo rmtfs -v &

# failed to open /dev/qcom_rmtfs_mem1: No such file or directory
# loading /lib/firmware/q6.mdt
# loading /lib/firmware/q6.b03
# loading /lib/firmware/q6.b04
# loading /lib/firmware/q6.b05
# loading /lib/firmware/q6.b06
# loading /lib/firmware/modem_fw.mdt
# loading /lib/firmware/modem_fw.b02
# loading /lib/firmware/modem_fw.b03
# loading /lib/firmware/modem_fw.b04
# loading /lib/firmware/modem_fw.b05
# loading /lib/firmware/modem_fw.b09
# loading /lib/firmware/modem_fw.b10
# loading /lib/firmware/modem_fw.b11
# loading /lib/firmware/modem_fw.b12
# loading /lib/firmware/modem_fw.b13
# loading /lib/firmware/modem_fw.b15
# loading /lib/firmware/modem_fw.b16
# loading /lib/firmware/modem_fw.b17
# loading /lib/firmware/modem_fw.b18
# loading /lib/firmware/modem_fw.b23
# loading /lib/firmware/modem_fw.b24
# loading /lib/firmware/modem_fw.b25
# loading /lib/firmware/modem_fw.b27
# loading /lib/firmware/modem_fw.b28
# loading /lib/firmware/modem_fw.b31
# loading /lib/firmware/modem.mdt
# loading /lib/firmware/modem.b02
# loading /lib/firmware/modem.b03
# loading /lib/firmware/modem.b04
# loading /lib/firmware/modem.b05
# loading /lib/firmware/modem.b06
# loading /lib/firmware/modem.b07
# loading /lib/firmware/modem.b08
# loading /lib/firmware/modem.b09
# loading /lib/firmware/modem.b10
# registering services
# E|qrtr: sendto(): No such device
# failed to publish rmtfs service. waiting and trying again...[RMTFS] packet; from: 0:4
# [RMTFS] open /boot/modem_fs1 => 0 (0:0)
# [RMTFS] packet; from: 0:2
# [RMTFS] packet; from: 0:5
# [RMTFS] open /boot/modem_fs2 => 1 (0:0)
# [RMTFS] packet; from: 0:6
# [RMTFS] open /boot/modem_fsg => 2 (0:0)
# [RMTFS] packet; from: 0:4
# [RMTFS] alloc 0, 3145728 => 0x0 (-1884291072:0)
# [RMTFS] packet; from: 0:6
# [RMTFS] iovec 2, not forced => (0:0)
# [RMTFS]       read 0:1 0x8fb00000
# [RMTFS]       read 6143:1 0x8fdffe00
# [RMTFS] packet; from: 0:4
# [RMTFS] iovec 0, not forced => (0:0)
# [RMTFS]       read 0:1 0x8fb00000
# [RMTFS]       read 6143:1 0x8fdffe00
# [RMTFS] packet; from: 0:5
# [RMTFS] iovec 1, not forced => (0:0)
# [RMTFS]       read 0:1 0x8fb00000
# [RMTFS]       read 6143:1 0x8fdffe00
# [RMTFS] packet; from: 0:5
# [RMTFS] iovec 1, not forced => (0:0)
# [RMTFS]       read 1:6142 0x8fb00200

# make some QMI requests!
sudo env LD_PRELOAD=/usr/lib/libsmdpkt_wrapper.so qmicli -d /dev/smdcntl0 --get-service-version-info
# [27 Feb 2018, 08:35:23] -Warning ** [/dev/smdcntl0] couldn't load driver of cdc-wdm port
# [27 Feb 2018, 08:35:23] -Warning ** [/dev/smdcntl0] requested auto mode but no MBIM QMUX support available
# [27 Feb 2018, 08:35:23] -Warning ** [/dev/smdcntl0] requested QMI mode but unexpected driver found: unknown
# [/dev/smdcntl0] Supported versions:
# 	ctl (1.5)
# 	wds (1.23)
# 	dms (1.13)
# 	nas (1.25)
# 	qos (1.3)
# 	wms (1.10)
# 	auth (1.2)
# 	at (1.2)
# 	voice (2.1)
# 	cat2 (2.11)
# 	uim (1.23)
# 	pbm (1.4)
# 	test (1.0)
# 	loc (2.0)
# 	sar (1.0)
# 	ims (1.0)
# 	ts (1.0)
# 	tmd (1.0)
# 	wda (1.3)
# 	csvt (1.0)
# 	imsp (1.0)
# 	imsa (1.0)
# 	unknown [0xe3] (0.0)
# 	unknown [0xe4] (0.0)
# 	unknown [0xe5] (0.0)
# 	unknown [0xe6] (0.0)
# 	unknown [0xe7] (0.0)

sudo env LD_PRELOAD=/usr/lib/libsmdpkt_wrapper.so qmicli -d /dev/smdcntl0 --dms-get-msisdn
# should show phone number

sudo env LD_PRELOAD=/usr/lib/libsmdpkt_wrapper.so qmicli -d /dev/smdcntl0 --uim-get-card-status
# [/dev/smdcntl0] Successfully got card status
# Provisioning applications:
# 	Primary GW:   slot '0', application '0'
# 	Primary 1X:   session doesn't exist
# 	Secondary GW: session doesn't exist
# 	Secondary 1X: session doesn't exist
# Card [0]:
# 	Card state: 'present'
# 	UPIN state: 'not-initialized'
# 		UPIN retries: '0'
# 		UPUK retries: '0'
# 	Application [0]:
# 		Application type:  'usim (2)'
# 		Application state: 'ready'
# 		Application ID:
# 			A0:00:00:00:87:10:02:FF:FF:FF:FF:89:06:19:00:00
# 		Personalization state: 'ready'
# 		UPIN replaces PIN1: 'no'
# 		PIN1 state: 'disabled'
# 			PIN1 retries: '3'
# 			PUK1 retries: '10'
# 		PIN2 state: 'enabled-not-verified'
# 			PIN2 retries: '10'
# 			PUK2 retries: '10'
# 	Application [1]:
# 		Application type:  'isim (5)'
# 		Application state: 'detected'
# 		Application ID:
# 			A0:00:00:00:87:10:04:FF:FF:FF:FF:89:07:03:00:00
# 		Personalization state: 'unknown'
# 		UPIN replaces PIN1: 'no'
# 		PIN1 state: 'disabled'
# 			PIN1 retries: '3'
# 			PUK1 retries: '10'
# 		PIN2 state: 'not-initialized'
# 			PIN2 retries: '0'
# 			PUK2 retries: '0'

sudo env LD_PRELOAD=/usr/lib/libsmdpkt_wrapper.so qmicli -d /dev/smdcntl0 --nas-get-operator-name
# SIM/network operator name

Next steps are to install/build uqmi (it can send SMSs; as far as I know qmicli doesn't) or ofono (I see it's in the Alpine testing repo, might need some patching to point to smdcntl0, and will need libsmdpkt_wrapper.so as above. See my Android fork for some help on that; of course not all of the changes will be needed.) There is also plenty more work to do with automating/packaging the above stuff, cleaning up the patches I made to get it working, making sure it's robust [could be some timing-related flakiness], etc.

(If anyone's kernel has the mainline AF_QIPCRTR, we will need to un-do some patches I made to get this stuff working with AF_MSM_IPC which ships with Android kernels. That's for rmtfs, at least. Maybe the serial QMI device is a little different on mainline too.)

Contributor

scintill commented Feb 27, 2018

I got QMI calls working on my i9195!! Due to time shortage I didn't do something really cool like send an SMS, but I'm pretty confident that's just a matter of getting the right packages built (see bottom of post.) Maybe somebody else will have the honor of sending the first SMS from postmarketOS on a Qualcomm device. ;)

Here are some commands and example output that will hopefully help others.

# get https://github.com/scintill/pmbootstrap/tree/qmimodem for the aports I added
./pmbootstrap.py install --add rmtfs,libsmdpkt_wrapper,libqmi

# Then, over ssh:
# mount modem firmware that kernel hotplug system requests (hacky, will temporarily disappear any other firmware...)
sudo mount -o ro /dev/disk/by-partlabel/modem /lib/firmware
sudo mount -o bind /lib/firmware/image /lib/firmware
ls /lib/firmware
# keymaste.b00  mldap.b02  modem.b04  modem.mdt	  modem_fw.b09	modem_fw.b17  modem_fw.b31  prov.mdt  q6.mdt	    skm.b01	  sshdcpap.b03	tima_key.b00  tima_lkm.b02  tima_pkm.mdt  vidc.b01   wcnss.b04
# keymaste.b01  mldap.b03  modem.b05  modem_fw.b00  modem_fw.b10	modem_fw.b18  modem_fw.fli  q6.b00    sec_stor.b00  skm.b02	  sshdcpap.mdt	tima_key.b01  tima_lkm.b03  tzapps.b00	  vidc.b02   wcnss.b05
# keymaste.b02  mldap.mdt  modem.b06  modem_fw.b01  modem_fw.b11	modem_fw.b23  modem_fw.mdt  q6.b01    sec_stor.b01  skm.b03	  tima_atn.b00	tima_key.b02  tima_lkm.mdt  tzapps.b01	  vidc.b03   wcnss.b06
# keymaste.b03  modem.b00  modem.b07  modem_fw.b02  modem_fw.b12	modem_fw.b24  prov.b00	    q6.b03    sec_stor.b02  skm.mdt	  tima_atn.b01	tima_key.b03  tima_pkm.b00  tzapps.b02	  vidc.mdt   wcnss.mdt
# keymaste.mdt  modem.b01  modem.b08  modem_fw.b03  modem_fw.b13	modem_fw.b25  prov.b01	    q6.b04    sec_stor.b03  sshdcpap.b00  tima_atn.b02	tima_key.mdt  tima_pkm.b01  tzapps.b03	  wcnss.b00
# mldap.b00     modem.b02  modem.b09  modem_fw.b04  modem_fw.b15	modem_fw.b27  prov.b02	    q6.b05    sec_stor.mdt  sshdcpap.b01  tima_atn.b03	tima_lkm.b00  tima_pkm.b02  tzapps.mdt	  wcnss.b01
# mldap.b01     modem.b03  modem.b10  modem_fw.b05  modem_fw.b16	modem_fw.b28  prov.b03	    q6.b06    skm.b00	    sshdcpap.b02  tima_atn.mdt	tima_lkm.b01  tima_pkm.b03  vidc.b00	  wcnss.b02

# link paths that rmtfs looks to for servicing modem requests (your device's paths may vary; see your error output from rmtfs)
sudo ln -s /dev/disk/by-partlabel/modemst1 /boot/modem_fs1
sudo ln -s /dev/disk/by-partlabel/modemst2 /boot/modem_fs2
sudo ln -s /dev/disk/by-partlabel/fsg      /boot/modem_fsg

# put firmware log in background
tail -f /var/log/firmwareload.log &

sudo rmtfs -v &

# failed to open /dev/qcom_rmtfs_mem1: No such file or directory
# loading /lib/firmware/q6.mdt
# loading /lib/firmware/q6.b03
# loading /lib/firmware/q6.b04
# loading /lib/firmware/q6.b05
# loading /lib/firmware/q6.b06
# loading /lib/firmware/modem_fw.mdt
# loading /lib/firmware/modem_fw.b02
# loading /lib/firmware/modem_fw.b03
# loading /lib/firmware/modem_fw.b04
# loading /lib/firmware/modem_fw.b05
# loading /lib/firmware/modem_fw.b09
# loading /lib/firmware/modem_fw.b10
# loading /lib/firmware/modem_fw.b11
# loading /lib/firmware/modem_fw.b12
# loading /lib/firmware/modem_fw.b13
# loading /lib/firmware/modem_fw.b15
# loading /lib/firmware/modem_fw.b16
# loading /lib/firmware/modem_fw.b17
# loading /lib/firmware/modem_fw.b18
# loading /lib/firmware/modem_fw.b23
# loading /lib/firmware/modem_fw.b24
# loading /lib/firmware/modem_fw.b25
# loading /lib/firmware/modem_fw.b27
# loading /lib/firmware/modem_fw.b28
# loading /lib/firmware/modem_fw.b31
# loading /lib/firmware/modem.mdt
# loading /lib/firmware/modem.b02
# loading /lib/firmware/modem.b03
# loading /lib/firmware/modem.b04
# loading /lib/firmware/modem.b05
# loading /lib/firmware/modem.b06
# loading /lib/firmware/modem.b07
# loading /lib/firmware/modem.b08
# loading /lib/firmware/modem.b09
# loading /lib/firmware/modem.b10
# registering services
# E|qrtr: sendto(): No such device
# failed to publish rmtfs service. waiting and trying again...[RMTFS] packet; from: 0:4
# [RMTFS] open /boot/modem_fs1 => 0 (0:0)
# [RMTFS] packet; from: 0:2
# [RMTFS] packet; from: 0:5
# [RMTFS] open /boot/modem_fs2 => 1 (0:0)
# [RMTFS] packet; from: 0:6
# [RMTFS] open /boot/modem_fsg => 2 (0:0)
# [RMTFS] packet; from: 0:4
# [RMTFS] alloc 0, 3145728 => 0x0 (-1884291072:0)
# [RMTFS] packet; from: 0:6
# [RMTFS] iovec 2, not forced => (0:0)
# [RMTFS]       read 0:1 0x8fb00000
# [RMTFS]       read 6143:1 0x8fdffe00
# [RMTFS] packet; from: 0:4
# [RMTFS] iovec 0, not forced => (0:0)
# [RMTFS]       read 0:1 0x8fb00000
# [RMTFS]       read 6143:1 0x8fdffe00
# [RMTFS] packet; from: 0:5
# [RMTFS] iovec 1, not forced => (0:0)
# [RMTFS]       read 0:1 0x8fb00000
# [RMTFS]       read 6143:1 0x8fdffe00
# [RMTFS] packet; from: 0:5
# [RMTFS] iovec 1, not forced => (0:0)
# [RMTFS]       read 1:6142 0x8fb00200

# make some QMI requests!
sudo env LD_PRELOAD=/usr/lib/libsmdpkt_wrapper.so qmicli -d /dev/smdcntl0 --get-service-version-info
# [27 Feb 2018, 08:35:23] -Warning ** [/dev/smdcntl0] couldn't load driver of cdc-wdm port
# [27 Feb 2018, 08:35:23] -Warning ** [/dev/smdcntl0] requested auto mode but no MBIM QMUX support available
# [27 Feb 2018, 08:35:23] -Warning ** [/dev/smdcntl0] requested QMI mode but unexpected driver found: unknown
# [/dev/smdcntl0] Supported versions:
# 	ctl (1.5)
# 	wds (1.23)
# 	dms (1.13)
# 	nas (1.25)
# 	qos (1.3)
# 	wms (1.10)
# 	auth (1.2)
# 	at (1.2)
# 	voice (2.1)
# 	cat2 (2.11)
# 	uim (1.23)
# 	pbm (1.4)
# 	test (1.0)
# 	loc (2.0)
# 	sar (1.0)
# 	ims (1.0)
# 	ts (1.0)
# 	tmd (1.0)
# 	wda (1.3)
# 	csvt (1.0)
# 	imsp (1.0)
# 	imsa (1.0)
# 	unknown [0xe3] (0.0)
# 	unknown [0xe4] (0.0)
# 	unknown [0xe5] (0.0)
# 	unknown [0xe6] (0.0)
# 	unknown [0xe7] (0.0)

sudo env LD_PRELOAD=/usr/lib/libsmdpkt_wrapper.so qmicli -d /dev/smdcntl0 --dms-get-msisdn
# should show phone number

sudo env LD_PRELOAD=/usr/lib/libsmdpkt_wrapper.so qmicli -d /dev/smdcntl0 --uim-get-card-status
# [/dev/smdcntl0] Successfully got card status
# Provisioning applications:
# 	Primary GW:   slot '0', application '0'
# 	Primary 1X:   session doesn't exist
# 	Secondary GW: session doesn't exist
# 	Secondary 1X: session doesn't exist
# Card [0]:
# 	Card state: 'present'
# 	UPIN state: 'not-initialized'
# 		UPIN retries: '0'
# 		UPUK retries: '0'
# 	Application [0]:
# 		Application type:  'usim (2)'
# 		Application state: 'ready'
# 		Application ID:
# 			A0:00:00:00:87:10:02:FF:FF:FF:FF:89:06:19:00:00
# 		Personalization state: 'ready'
# 		UPIN replaces PIN1: 'no'
# 		PIN1 state: 'disabled'
# 			PIN1 retries: '3'
# 			PUK1 retries: '10'
# 		PIN2 state: 'enabled-not-verified'
# 			PIN2 retries: '10'
# 			PUK2 retries: '10'
# 	Application [1]:
# 		Application type:  'isim (5)'
# 		Application state: 'detected'
# 		Application ID:
# 			A0:00:00:00:87:10:04:FF:FF:FF:FF:89:07:03:00:00
# 		Personalization state: 'unknown'
# 		UPIN replaces PIN1: 'no'
# 		PIN1 state: 'disabled'
# 			PIN1 retries: '3'
# 			PUK1 retries: '10'
# 		PIN2 state: 'not-initialized'
# 			PIN2 retries: '0'
# 			PUK2 retries: '0'

sudo env LD_PRELOAD=/usr/lib/libsmdpkt_wrapper.so qmicli -d /dev/smdcntl0 --nas-get-operator-name
# SIM/network operator name

Next steps are to install/build uqmi (it can send SMSs; as far as I know qmicli doesn't) or ofono (I see it's in the Alpine testing repo, might need some patching to point to smdcntl0, and will need libsmdpkt_wrapper.so as above. See my Android fork for some help on that; of course not all of the changes will be needed.) There is also plenty more work to do with automating/packaging the above stuff, cleaning up the patches I made to get it working, making sure it's robust [could be some timing-related flakiness], etc.

(If anyone's kernel has the mainline AF_QIPCRTR, we will need to un-do some patches I made to get this stuff working with AF_MSM_IPC which ships with Android kernels. That's for rmtfs, at least. Maybe the serial QMI device is a little different on mainline too.)

@MartijnBraam

This comment has been minimized.

Show comment
Hide comment
@MartijnBraam

MartijnBraam Feb 27, 2018

Member

I guess we need to copy the modem firmware to a firmware package in pmos to prevent the issue with firmware loading (and to be able to update it)

Member

MartijnBraam commented Feb 27, 2018

I guess we need to copy the modem firmware to a firmware package in pmos to prevent the issue with firmware loading (and to be able to update it)

@ollieparanoid

This comment has been minimized.

Show comment
Hide comment
@ollieparanoid

ollieparanoid Feb 27, 2018

Member

amazing work @scintill! \o/

Next steps are to install/build uqmi (it can send SMSs; as far as I know qmicli doesn't) or ofono (I see it's in the Alpine testing repo, might need some patching to point to smdcntl0, and will need libsmdpkt_wrapper.so as above.

I'd recommend ofono, that is what UIs like Plasma Mobile, LuneOS UI etc. are compatible with.

Member

ollieparanoid commented Feb 27, 2018

amazing work @scintill! \o/

Next steps are to install/build uqmi (it can send SMSs; as far as I know qmicli doesn't) or ofono (I see it's in the Alpine testing repo, might need some patching to point to smdcntl0, and will need libsmdpkt_wrapper.so as above.

I'd recommend ofono, that is what UIs like Plasma Mobile, LuneOS UI etc. are compatible with.

@scintill

This comment has been minimized.

Show comment
Hide comment
@scintill

scintill Feb 28, 2018

Contributor

Just to make sure we're on the same page with the firmware, it comes from a partition that ships on the device. I lean toward not packaging it -- they are probably copyrighted and not redistributable, and also the images might have country/network-specific customizations we don't necessarily want to deal with knowing about. The updating is interesting, but we'd probably have to look on XDA and download sketchy files, without a lot of insight into whether they are actually universally better, or safe. I know security updates are a focus of this project, so maybe there is some middle ground of tracking available firmware versions and just notifying the user if a newer one is available?

This firmware image mount is kind of a pain with the way main/postmarketos-base/firmwareload.sh is now, because not only does it need a mount point, but there is a subdirectory within the partition. Thoughts on how to do this best? I am thinking about changing that script to just recursively search /lib/firmware, so the existing structure can be retained, and I can mount at something like /lib/firmware/modem and it will work too. But I don't know much about the intended structure of that directory, beyond what I guess by grepping for /lib/firmware/ in aports.

I will try ofono when I have some time, maybe later this week.

Contributor

scintill commented Feb 28, 2018

Just to make sure we're on the same page with the firmware, it comes from a partition that ships on the device. I lean toward not packaging it -- they are probably copyrighted and not redistributable, and also the images might have country/network-specific customizations we don't necessarily want to deal with knowing about. The updating is interesting, but we'd probably have to look on XDA and download sketchy files, without a lot of insight into whether they are actually universally better, or safe. I know security updates are a focus of this project, so maybe there is some middle ground of tracking available firmware versions and just notifying the user if a newer one is available?

This firmware image mount is kind of a pain with the way main/postmarketos-base/firmwareload.sh is now, because not only does it need a mount point, but there is a subdirectory within the partition. Thoughts on how to do this best? I am thinking about changing that script to just recursively search /lib/firmware, so the existing structure can be retained, and I can mount at something like /lib/firmware/modem and it will work too. But I don't know much about the intended structure of that directory, beyond what I guess by grepping for /lib/firmware/ in aports.

I will try ofono when I have some time, maybe later this week.

@ollieparanoid

This comment has been minimized.

Show comment
Hide comment
@ollieparanoid

ollieparanoid Feb 28, 2018

Member

Regarding firmware files, after discussing last year we agreed upon packaging the firmware files, and not using Android's firmware partition. See the FAQ for reasoning. If you think this is a mistake and have good arguments for doing it differently, then feel free to open the discussion again. One idea to work around the redistribution problem is proposed in #797. Right now the firmware packages are simply not part of the binary package repository, so they get built when users run pmbootstrap install.

When packaged this way, the firmware load script should also work, right? If not, we can of course extend it. 👍

Member

ollieparanoid commented Feb 28, 2018

Regarding firmware files, after discussing last year we agreed upon packaging the firmware files, and not using Android's firmware partition. See the FAQ for reasoning. If you think this is a mistake and have good arguments for doing it differently, then feel free to open the discussion again. One idea to work around the redistribution problem is proposed in #797. Right now the firmware packages are simply not part of the binary package repository, so they get built when users run pmbootstrap install.

When packaged this way, the firmware load script should also work, right? If not, we can of course extend it. 👍

@scintill

This comment has been minimized.

Show comment
Hide comment
@scintill

scintill Mar 5, 2018

Contributor

Ah, I see now you've gone through some of the same firmware concerns already. OK, I will see how it goes with packaged firmware. I noticed the modem firmware file I got had a couple of other partitions it, so that could be something to watch out for -- if the modem/bootloader/etc. is reading those partitions and we're feeding it mismatched firmware files from our package, something might get confused. (Though I've had to go to a lot of trouble to port rmtfs, supposedly because the modem can't see the eMMC storage, so maybe it's not an issue.)

Tonight I sent some SMS's with ofono! I am out of time to package ofono nicely, but I've polished some of the code from before. Firmware is packaged, and you don't need to make those symlinks in /boot yourself. It's at https://github.com/scintill/pmbootstrap/tree/qmimodem2 . Check out this commit to see what you need to add in your device, if you have a similar one. The commands to work with this code are similar to before, but I moved the LD_PRELOAD libs to /usr/lib/preload.

Here's a quick dump of patches to Alpine's ofono package (some is hacky debugging):

diff --git a/aports/main/ofono/source/ofono-1.21/plugins/udevng.c b/aports/main/ofono/source/ofono-1.21/plugins/udevng.c
index ec4d34e..e2393a6 100644
--- a/aports/main/ofono/source/ofono-1.21/plugins/udevng.c
+++ b/aports/main/ofono/source/ofono-1.21/plugins/udevng.c
@@ -201,6 +201,7 @@ static gboolean setup_gobi(struct modem_info *modem)
 
 	DBG("%s", modem->syspath);
 
+	if (modem->type != MODEM_TYPE_SERIAL) {
 		for (list = modem->devices; list; list = list->next) {
 			struct device_info *info = list->data;
 
@@ -234,6 +235,9 @@ static gboolean setup_gobi(struct modem_info *modem)
 
 		if (qmi == NULL || mdm == NULL || net == NULL)
 			return FALSE;
+	} else {
+		qmi = modem->serial->devnode;
+	}
 
 	DBG("qmi=%s net=%s mdm=%s gps=%s diag=%s", qmi, net, mdm, gps, diag);
 
@@ -1337,9 +1341,9 @@ static struct udev_device* get_serial_modem_device(struct udev_device *dev)
  * - The modem consists of only a single interface
  * - The device must have an OFONO_DRIVER property from udev
  */
-static void add_serial_device(struct udev_device *dev)
+static void add_serial_device(const char *syspath, struct udev_device *dev)
 {
-	const char *syspath, *devpath, *devname, *devnode;
+	const char *devpath, *devname, *devnode;
 	struct modem_info *modem;
 	struct serial_device_info *info;
 	const char *subsystem;
@@ -1348,7 +1352,7 @@ static void add_serial_device(struct udev_device *dev)
 
 	mdev = get_serial_modem_device(dev);
 	if (!mdev) {
-		DBG("Device is missing required OFONO_DRIVER property");
+		DBG("Device %s is missing required OFONO_DRIVER property", syspath);
 		return;
 	}
 
@@ -1644,7 +1648,7 @@ static void check_usb_device(struct udev_device *device)
 	add_device(syspath, devname, driver, vendor, model, device);
 }
 
-static void check_device(struct udev_device *device)
+static void check_device(const char *syspath, struct udev_device *device)
 {
 	const char *bus;
 
@@ -1659,7 +1663,7 @@ static void check_device(struct udev_device *device)
 			(g_str_equal(bus, "usbmisc") == TRUE))
 		check_usb_device(device);
 	else
-		add_serial_device(device);
+		add_serial_device(syspath, device);
 
 }
 
@@ -1708,6 +1712,7 @@ static void enumerate_devices(struct udev *context)
 		return;
 
 	udev_enumerate_add_match_subsystem(enumerate, "tty");
+	udev_enumerate_add_match_subsystem(enumerate, "smdpkt");
 	udev_enumerate_add_match_subsystem(enumerate, "usb");
 	udev_enumerate_add_match_subsystem(enumerate, "usbmisc");
 	udev_enumerate_add_match_subsystem(enumerate, "net");
@@ -1722,7 +1727,7 @@ static void enumerate_devices(struct udev *context)
 
 		device = udev_device_new_from_syspath(context, syspath);
 		if (device != NULL) {
-			check_device(device);
+			check_device(syspath, device);
 			udev_device_unref(device);
 		}
 
@@ -1774,7 +1779,7 @@ static gboolean udev_event(GIOChannel *channel, GIOCondition cond,
 		if (udev_delay > 0)
 			g_source_remove(udev_delay);
 
-		check_device(device);
+		check_device(NULL, device);
 
 		udev_delay = g_timeout_add_seconds(1, check_modem_list, NULL);
 	} else if (g_str_equal(action, "remove") == TRUE)

And

$ cat /usr/lib/udev/rules.d/10-ofono-smdpkt.rules 
KERNEL=="smdcntl0", ENV{OFONO_DRIVER}="gobi"

Launch and test with

sudo env OFONO_QMI_DEBUG=1 LD_PRELOAD=/usr/lib/preload/libsmdpkt_wrapper.so /usr/sbin/ofonod -d -n

sudo dbus-send --print-reply --system --dest=org.ofono /gobi_0 org.ofono.Modem.SetProperty string:"Powered" variant:boolean:"true"
sudo dbus-send --print-reply --system --dest=org.ofono /gobi_0 org.ofono.Modem.GetProperties
sudo dbus-send --print-reply --system --dest=org.ofono /gobi_0 org.ofono.Modem.SetProperty string:"Online" variant:boolean:"true"
sudo dbus-send --system --print-reply --dest=org.ofono /gobi_0 org.ofono.MessageManager.SendMessage string:"$PHONE_NUMBER" string:"Hello world! -postmarketOS"
Contributor

scintill commented Mar 5, 2018

Ah, I see now you've gone through some of the same firmware concerns already. OK, I will see how it goes with packaged firmware. I noticed the modem firmware file I got had a couple of other partitions it, so that could be something to watch out for -- if the modem/bootloader/etc. is reading those partitions and we're feeding it mismatched firmware files from our package, something might get confused. (Though I've had to go to a lot of trouble to port rmtfs, supposedly because the modem can't see the eMMC storage, so maybe it's not an issue.)

Tonight I sent some SMS's with ofono! I am out of time to package ofono nicely, but I've polished some of the code from before. Firmware is packaged, and you don't need to make those symlinks in /boot yourself. It's at https://github.com/scintill/pmbootstrap/tree/qmimodem2 . Check out this commit to see what you need to add in your device, if you have a similar one. The commands to work with this code are similar to before, but I moved the LD_PRELOAD libs to /usr/lib/preload.

Here's a quick dump of patches to Alpine's ofono package (some is hacky debugging):

diff --git a/aports/main/ofono/source/ofono-1.21/plugins/udevng.c b/aports/main/ofono/source/ofono-1.21/plugins/udevng.c
index ec4d34e..e2393a6 100644
--- a/aports/main/ofono/source/ofono-1.21/plugins/udevng.c
+++ b/aports/main/ofono/source/ofono-1.21/plugins/udevng.c
@@ -201,6 +201,7 @@ static gboolean setup_gobi(struct modem_info *modem)
 
 	DBG("%s", modem->syspath);
 
+	if (modem->type != MODEM_TYPE_SERIAL) {
 		for (list = modem->devices; list; list = list->next) {
 			struct device_info *info = list->data;
 
@@ -234,6 +235,9 @@ static gboolean setup_gobi(struct modem_info *modem)
 
 		if (qmi == NULL || mdm == NULL || net == NULL)
 			return FALSE;
+	} else {
+		qmi = modem->serial->devnode;
+	}
 
 	DBG("qmi=%s net=%s mdm=%s gps=%s diag=%s", qmi, net, mdm, gps, diag);
 
@@ -1337,9 +1341,9 @@ static struct udev_device* get_serial_modem_device(struct udev_device *dev)
  * - The modem consists of only a single interface
  * - The device must have an OFONO_DRIVER property from udev
  */
-static void add_serial_device(struct udev_device *dev)
+static void add_serial_device(const char *syspath, struct udev_device *dev)
 {
-	const char *syspath, *devpath, *devname, *devnode;
+	const char *devpath, *devname, *devnode;
 	struct modem_info *modem;
 	struct serial_device_info *info;
 	const char *subsystem;
@@ -1348,7 +1352,7 @@ static void add_serial_device(struct udev_device *dev)
 
 	mdev = get_serial_modem_device(dev);
 	if (!mdev) {
-		DBG("Device is missing required OFONO_DRIVER property");
+		DBG("Device %s is missing required OFONO_DRIVER property", syspath);
 		return;
 	}
 
@@ -1644,7 +1648,7 @@ static void check_usb_device(struct udev_device *device)
 	add_device(syspath, devname, driver, vendor, model, device);
 }
 
-static void check_device(struct udev_device *device)
+static void check_device(const char *syspath, struct udev_device *device)
 {
 	const char *bus;
 
@@ -1659,7 +1663,7 @@ static void check_device(struct udev_device *device)
 			(g_str_equal(bus, "usbmisc") == TRUE))
 		check_usb_device(device);
 	else
-		add_serial_device(device);
+		add_serial_device(syspath, device);
 
 }
 
@@ -1708,6 +1712,7 @@ static void enumerate_devices(struct udev *context)
 		return;
 
 	udev_enumerate_add_match_subsystem(enumerate, "tty");
+	udev_enumerate_add_match_subsystem(enumerate, "smdpkt");
 	udev_enumerate_add_match_subsystem(enumerate, "usb");
 	udev_enumerate_add_match_subsystem(enumerate, "usbmisc");
 	udev_enumerate_add_match_subsystem(enumerate, "net");
@@ -1722,7 +1727,7 @@ static void enumerate_devices(struct udev *context)
 
 		device = udev_device_new_from_syspath(context, syspath);
 		if (device != NULL) {
-			check_device(device);
+			check_device(syspath, device);
 			udev_device_unref(device);
 		}
 
@@ -1774,7 +1779,7 @@ static gboolean udev_event(GIOChannel *channel, GIOCondition cond,
 		if (udev_delay > 0)
 			g_source_remove(udev_delay);
 
-		check_device(device);
+		check_device(NULL, device);
 
 		udev_delay = g_timeout_add_seconds(1, check_modem_list, NULL);
 	} else if (g_str_equal(action, "remove") == TRUE)

And

$ cat /usr/lib/udev/rules.d/10-ofono-smdpkt.rules 
KERNEL=="smdcntl0", ENV{OFONO_DRIVER}="gobi"

Launch and test with

sudo env OFONO_QMI_DEBUG=1 LD_PRELOAD=/usr/lib/preload/libsmdpkt_wrapper.so /usr/sbin/ofonod -d -n

sudo dbus-send --print-reply --system --dest=org.ofono /gobi_0 org.ofono.Modem.SetProperty string:"Powered" variant:boolean:"true"
sudo dbus-send --print-reply --system --dest=org.ofono /gobi_0 org.ofono.Modem.GetProperties
sudo dbus-send --print-reply --system --dest=org.ofono /gobi_0 org.ofono.Modem.SetProperty string:"Online" variant:boolean:"true"
sudo dbus-send --system --print-reply --dest=org.ofono /gobi_0 org.ofono.MessageManager.SendMessage string:"$PHONE_NUMBER" string:"Hello world! -postmarketOS"
@ollieparanoid

This comment has been minimized.

Show comment
Hide comment
@ollieparanoid

ollieparanoid Mar 13, 2018

Member

Amazing work! I've created a wiki page for now, let's create smaller issues when we're working on something specific.

Member

ollieparanoid commented Mar 13, 2018

Amazing work! I've created a wiki page for now, let's create smaller issues when we're working on something specific.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.