[Jolla C2] MMS fails with operators using a separate MMS APN – no route installed for MMS context (gateway 0.0.0.0)

REPRODUCIBILITY: 100 %

OS VERSION: 5.1.0.11 (Pispala); hw release 1.1.0.12; ofono 1.29+git12-1.16.4.jolla, ofono-binder-plugin 1.1.25-1.12.2.jolla, libgbinder 1.1.45-1.15.1.jolla, libgbinder-radio 1.6.1-1.9.2.jolla, mms-engine 1.0.83

HARDWARE: Jolla C2 (Reeder s19mps)

UI LANGUAGE: Norwegian (bokmål)

REGRESSION: Unknown — issue present since first setup of this device; no earlier release tested on it

DESCRIPTION:

MMS sending and receiving fail with a deterministic 60-second timeout when the operator uses a separate MMS APN (tested with Happybytes, an MVNO on Telenor Norway: MMS APN mms, MMSC http://mms.media, no proxy — the exact settings published by the operator). Ordinary internet over the internet APN works fine throughout.

Root cause, verified live on the device: when mms-engine activates the MMS context, oFono’s binder plugin reports the data call settings (address, DNS) but no kernel route is ever installed via the MMS interface (seth_lte1). The data call reports gateways=0.0.0.0, and because the MMS context is not managed by connman (it is activated standalone by mms-engine via oFono D-Bus), it — unlike the internet context — receives neither a prefix route nor an on-link default route.

mms-engine binds its HTTP session to the MMS interface address (SOUP_SESSION_LOCAL_ADDRESS in mms_task_http.c), but routing is destination-based: the TCP packets leave via the internet APN’s default route (default dev seth_lte0 scope link) with a source address from the MMS pool, and the operator’s ingress filtering drops them. libsoup’s default 60 s session timeout then surfaces as HTTP status 7 (Connection terminated unexpectedly).

Proof: with a host route via seth_lte1 forced in as root, the MMSC answers immediately — curl from the MMS source IP gets HTTP/1.1 405 Method Not Allowed, Allow: POST,OPTIONS (the expected MMSC reply to a GET) — and a real MMS sent from the Messages app succeeds, including reception of the MMS notification. Network, provisioning, APN settings, MMSC and mms-engine are all fine; the only missing piece is a route via the MMS interface.

PRECONDITIONS:

  • A SIM from an operator that uses a separate MMS APN (Telenor Norway and its MVNOs qualify: APN mms, MMSC http://mms.media, no proxy).
  • MMS access point configured per the operator’s instructions (Settings → System → Mobile network → MMS access point).
  • Mobile data working normally on the internet APN; WiFi switched off (not required for the bug, but keeps the analysis clean).
  • For observing the internals: developer mode enabled, SSH over USB.

STEPS TO REPRODUCE:

  1. Insert the SIM, configure the MMS access point as above (APN mms, MMSC http://mms.media, MMS proxy empty).

  2. SSH in over USB and watch interfaces and the routing table:

    while true; do ip -4 addr show seth_lte1 2>/dev/null; ip -4 route show; sleep 1; done
    
  3. From the Messages app, share a small picture to your own number.

  4. Observe that seth_lte1 comes up with a 10.120.x.x address — and that the routing table never gains any route via seth_lte1.

  5. Wait ~60 s and watch the message fail. mms-engine retries roughly every 76 s, ~11 attempts total, then the message is permanently failed.

  6. Optional counter-proof, as root:

    dbus-send --system --print-reply --dest=org.ofono /ril_0/context2 \
        org.ofono.ConnectionContext.SetProperty string:Active variant:boolean:true
    ip route replace 148.122.173.15/32 dev seth_lte1
    ip route replace 148.122.173.79/32 dev seth_lte1
    curl -4 -v --interface 10.120.95.111 http://mms.media/   # → 405, Allow: POST,OPTIONS
    

    Resend the MMS from the app while those routes exist → it succeeds and the MMS notification arrives.

EXPECTED RESULT:

When the MMS context is activated, a usable route via the MMS interface (seth_lte1) is installed (on-link default route or equivalent source-based routing), so that the MMS POST bound to the MMS source address reaches the MMSC. The MMS is delivered and the incoming MMS notification/content is retrieved — as it does on Android handsets with the same SIM and the same operator settings.

ACTUAL RESULT:

seth_lte1 comes up (e.g. inet 10.120.95.111/32) but no route referencing seth_lte1 is ever created. Routing table captured live while the MMS context was UP:

$ ip -4 route show
0.0.0.0 dev seth_lte0 scope link
default dev seth_lte0 scope link
10.0.0.0/8 dev seth_lte0 proto kernel scope link src 10.8.167.111
10.8.167.0/24 dev seth_lte0 proto kernel scope link src 10.8.167.111
192.168.2.0/24 dev usb0 proto kernel scope link src 192.168.2.15

Consequently every MMS send fails after exactly 60 s. mms-engine log (identical for every attempt, 30+ attempts across all configuration variants):

[mms-task-http] MMS interface address 10.120.105.253
[mms-task-http] m-send.req (261475 bytes) -> http://mms.media -> m-send.conf
... exactly 60 s later ...
[mms-task-http] HTTP status 7 (Connection terminated unexpectedly)

m-send.conf is 0 bytes — the MMSC never answered, because the SYNs went out the internet APN with a foreign source address and were dropped by the operator. MMS reception (notification content retrieval) fails for the same reason.

MODIFICATIONS:

  • OpenRepos packages installed for diagnostics: MMS Logger 1.0.20, oFono/sailfish-log-viewer.
  • Developer mode + SSH enabled.
  • After diagnosing, a workaround systemd service (mms-route-fix.service, runs a small script that adds host routes to the MMSC via seth_lte1 whenever that interface is up) was installed — with it, MMS works flawlessly. All attached logs were captured before the workaround was installed.
  • No other patches, no WayDroid, no alternative repositories.

ADDITIONAL INFORMATION:

oFono activates the MMS context without any error (ofono.log):

binder_data_call_new_aidl() [status=0,retry=-1,cid=2,active=2,type=0,
  ifname=seth_lte1,mtu=0,address=10.120.105.253,
  dns=148.122.173.7 148.122.173.77,gateways=0.0.0.0,pcscf=]
setting up data call
mtu_limit_apply() seth_lte1 mtu 1500 => 1280
pri_update_mms_context_settings() proxy mms.media port 80

Counter-proof with forced routes (context up, root):

# ping -c2 148.122.173.7                    # MMS-APN DNS via seth_lte1
64 bytes from 148.122.173.7: seq=0 ttl=60 time=88.668 ms

# curl -4 -v --interface 10.120.95.111 http://mms.media/
* Established connection to mms.media (148.122.173.15 port 80) from 10.120.95.111
> GET / HTTP/1.1
< HTTP/1.1 405 Method Not Allowed
< Server: nginx/1.29.3
< Allow: POST,OPTIONS                        ← MMSC alive and reachable

End-to-end success with routes held in place — journal:

Sep 30 00:38:04 JollaC2 ofonod[1479]: 2f 6d 6d 73 2e 6d 65 64 69 61 2f ...  /mms.media/3ePw3...
Sep 30 00:38:04 JollaC2 ofonod[1479]: plugins/sailfish_pushforwarder.c:
             pf_handle_datagram() content type application/vnd.wap.mms-message

Workaround in use (systemd watchdog; MMS then works fully automatically):

#!/bin/sh
IP=/usr/sbin/ip
IFACE=seth_lte1
MMSC_IPS="148.122.173.15 148.122.173.79"   # mms.media (Telenor NO)
while true; do
    if "$IP" -4 addr show "$IFACE" 2>/dev/null | grep -q "inet "; then
        for ip_ in $MMSC_IPS; do
            "$IP" route replace "${ip_}/32" dev "$IFACE" 2>/dev/null
        done
    fi
    sleep 1
done

Suggested proper fix (source level): install source-policy routing for MMS contexts — e.g. in oFono core (src/gprs.c) when a context of type MMS is activated with IPv4 gateway 0.0.0.0/unset, add (and remove on deactivation):

ip rule  add pref 100 from <mms_ipv4> lookup <table>
ip route add default dev <mms_ifname> table <table>      # on-link default

This mirrors Android’s per-network routing tables and cannot interfere with the default internet route. Alternatives: synthesize a usable gateway in binder_gprs_context_set_gateway() when the data call reports 0.0.0.0, or let mms-engine (mms-connman-nemo) manage the route for its own connection (grant CAP_NET_ADMIN). Regression criteria: MMS works with separate-MMS-APN operators and with proxy-based MMSCs; ordinary traffic still uses the internet APN during transfers; no routes/rules leak after context release.

rename “workaround.targz” to “workaround.tar.gz”, unzip and follow instructions in readme or setup manually.

workaround.targz (3.4 KB)

2 Likes

Files and instruction for the workaround added.

have you tried configuring mmsc ip as a proxy for itself?

Tried it now and it works. Two findings then:

It works only if the real MMSC hostname is kept. With MMSC = http://mms.media + MMS proxy = 148.122.173.15:80 (the MMSC’s own IP), a real send/receive completes fully — every MM1 transaction (send, notification, retrieve, acknowledge) HTTP 200 in ~2 s.

Watching the routing table while toggling the proxy (context cycled via D-Bus) shows that the system installs a host route for the MMS proxy via the MMS interface (oFono src/gprs.c: pri_update_mms_context_settings()), but never for the MMSC host itself. Empty proxy → no route at all → mms-engine’s SYNs, bound to the MMS source address, egress via the internet APN’s default route and are silently dropped → the exact-60-second timeouts. Your trick feeds the MMSC IP through the proxy field, making the system itself install the missing route.

On the gateway 0.0.0.0: that’s normal for LTE point-to-point bearers, reported by the modem — not an operator misconfiguration; the same SIM works on Android. The internet context gets an on-link default from connman, but the MMS context is activated standalone by mms-engine and gets nothing except the proxy special case — which is gateway-independent, hence the trick works despite 0.0.0.0. So, the defect is simply that the special case covers the proxy and not the MMSC.

Workaround caveat: with the proxy IP hardcoded, if the operator moves the MMSC, MMS breaks silently.

Possible fix: route the resolved MMSC host exactly like the proxy when no proxy is set —
via <gateway> if the data call provides a real gateway, on-link otherwise.

For reference only: link to providers’ setup instructions for internet and MMS on Android: Kundeservice - Trenger du hjelp | Happybytes