Taming an LTE card in Linux

When I wrote my request for help on how to do voice calls with a PCI-attached cellular modem I realised that writing a bit about how I'm dealing with the IP part of that thing might perhaps be mildly entertaining to some subset of the computer-literate public. After all, we are dealing with rather serious privacy issues here. So, let's start with these:

Controlling registration

Just like almost any other piece of mobile phone tech, an LTE card with a SIM inserted will by default try to register with the network operator's infrastructure when it is switched on (or resumed, more likely, in the case of a notebook part). If this is successful, it will create a data point in the logs there, which in turn will be stored for a few days or, depending on the human rights situation in the current jurisdiction (as in: is telecom data retention in effect?), for up to two years. This record links you with a time (at which you used your computer) and a location (at which you presumably were at that point). That's fairly sensitive data by any measure.

So: You don't want to create these records unless you really want network. But how do you avoid registration? There are various possible ways, but I found the simplest and probably most robust one is to use Linux's rfkill framework, which is in effect a refined version of airline mode. To make that convenient, I am defining two aliases:

alias fon="sudo rfkill unblock wwan"
alias keinfon="sudo rfkill block wwan"

(“keinfon“ is “no phone“ in German); put these into your .bashrc or perhaps into .aliases if your .bashrc includes that file.

Since I consider rfkill relatively a relatively unlikely target for privilege escalation, I have added , NOPASSWD: usr/sbin/rfkill to my system user's line in /etc/sudoers.d, but that's of course optional.

With that, when I want to use internet over LTE, I type fon, wait a few seconds for the registration to happen and then bring up the interface. When done, I bring down the interface and say keinfon. It would probably be more polite to the service operators if I de-registered from the infrastructure before that, but for all I can see only marginally so; they'll notice you're gone at the next PLU. I don't think there are major privacy implications either way.

It might be wiser to do the block/unblock routine in pre-up and post-down scripts in /etc/network/interfaces, but since registration is slow and I rather regularly find myself reconnecting while on the cell network, I'd consider that over-automation. And, of course, I still hope that one day I can do GSM voice calls over the interface, in which case the card shouldn't be blocked just because nobody is using it for an internet connection.

Phone Status

In case I forget the keinfon, I want to be warned about my gear leaking all the data to o2 (my network operator). I hence wrote a shell script display-phone-status.sh like this:

#!/bin/sh
if /usr/sbin/rfkill list | grep -A3 "Wireless WAN" | grep 'blocked: yes' > /dev/null; then
  echo "WWAN blocked."
else
  /usr/games/xcowsay -t 10 -f "Steve Italic 42" --at 0,520 --image ~/misc/my-icons/telephone.xpm 'Ich petze gerade!'
fi

The notification you'll want to change, for instance because you won't have the nice icon and may not find the font appropriate. The German in there means ”I'm squealing on you.“. Here's how this works out:

Screenshot: an old-style telephone with a baloon saying „Ich petze gerade“

I execute that at every wakeup, which is a bit tricky because xcowsay needs to know the display. If you still run pm-utils and are curious how I'm doing that, poke me and I'll write a post.

Connection

Mainly because tooling for MBIM and other more direct access methods felt fairly painful last time I looked, I am still connecting through PPP, even though that's extremely silly over an IP medium like LTE. Part of the reason I'm writing this post is because duckduckgo currently returns nothing useful if you look for “o2 connection string“ or something like that. I tried yesterday because surprisingly while the internet connection worked over GSM, when connected over LTE (see below on how I'm controlling that), executing the good old:

AT+CGDCONT=1, "IPV4V6", "internet"

would get me an ERROR. That command – basically specifying the protocol requested and the name of an „access point“ (and no, I have never even tried to figure out what role that „access point“ might have had even in GSM) – admittedly seems particularly silly in LTE, where you essentially have an internet connection right from the start. I'm pretty sure it didn't use to hurt LTE connections three years ago, though. Now it does, and so that's my chat script for o2 (put it into /etc/ppp/chat-o2 with the peer definition below):

IMEOUT 5
ECHO ON
ABORT 'BUSY'
ABORT 'ERROR'
ABORT 'NO ANSWER'
ABORT 'NO CARRIER'
ABORT 'NO DIALTONE'
ABORT 'RINGING\r\n\r\nRINGING'
'' "ATZ"
OK 'ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0'
OK "\d\dATD*99#"
CONNECT ""

You can probably do without almost all of this and just run ATD*99# if you're stingy; but over the past 15 years of using cellular modems in one way or another, each piece of configuration was useful at one time. I'm not claiming they are now.

Similarly, my /etc/ppp/peers/o2 configuration file might contain a bit of cruft:

/dev/ttyACM0
115200
debug
noauth
usepeerdns
ipcp-accept-remote
ipcp-accept-local
remotename any
user thing
local
nocrtscts
defaultroute
noipdefault
connect "/usr/sbin/chat -v -f /etc/ppp/chat-o2"

lcp-echo-interval 300
lcp-echo-failure 10

I'd expect the liberal LCP configuration at the bottom of the file is still very beneficial in the o2 network.

To manage the network, I use normal Debian ifupdown with this stanza in /etc/network/interfaces:

iface o2 inet ppp
  provider o2

To bring up the interface, I have an icon on my desktop that executes sudo ifup o2.

Monitoring

To see what's going through a network connection, I have a script monitor in /etc/network/if-up.d; this is unconditionally executed once an interface comes up. A case statement brings up wmnet instances with parameters somewhat adapted to the respective interfaces:

#!/bin/sh
case $IFACE in
wlan* )
  su - anselm -c 'DISPLAY=:0 nohup wmwave -r 200' > /dev/null 2>&1 &
  su - anselm -c "DISPLAY=:0 nohup wmnet -l -x 1000000 -d 200000 -r green -t red -W $IFACE" > /dev/null 2>&1 &
  ;;
ppp*)
  su - anselm -c "DISPLAY=:0 nohup wmnet -l -x 1000000 -d 200000 -r green -t red -W $IFACE" > /dev/null 2>&1 &
  ;;
o2 | n900)
  su - anselm -c "DISPLAY=:0 nohup wmnet -l -x 1000000 -d 200000 -r green -t red -W ppp0" > /dev/null 2>&1 &
  ;;
esac

The complicated su logic is necessary because again, the little window maker dockapps need access to the X display.

That whole part is a bit weak, not only because of the hard-coded user name and DISPLAY (these are fairly safe bets for a personal computer) and because it relies some configuration of your window manager to place the dockapps at predictable positions.

More importantly, ifupdown executes the script too early: To ifupdown, the interface is up when the pppd is up. But it is only then that pppd starts to negotiate, and these negotiations fail quite easily (e.g., when you're in a dead zone, and there are plenty of those with o2). If that happens, you have an essentially dead wmnet on the desktop. I clean up rather unspecifically in /etc/network/if-down.d/monitor:

#!/bin/sh
case $IFACE in
wlan* )
  killall wmwave
  killall wmnet
  ;;
ppp*|o2|n900)
  killall wmnet
  ;;
esac
exit 0

The implicit assumption here that the computer will only have one wireless network connection at a time.

Modem Configuration

I used to have to do a bit of modem configuration in the olden days. It's rarer these days, but I thought I might as well publish the source of a program, I wrote back then to encapsulate that configuration. I still find it is useful now and then to choose between the access methods LTE (fast, but perhaps smaller cells hence less stable) and GSM (slow, but perhaps more robust with larger cells and better coverage), which this script can do if your card supports the AT+XACT command. While I would guess that includes many Sierra modems, I have no idea how many that may be. Anyway, here's how that ought to look like (and perhaps the most relevant piece of information is the <home>, which means there's an infrastructure connection – as opposed to, for instance, <offline>):

$ modemconfig.py -a LTE
Modem is >home<
Using LTE
Running on band BAND_LTE_1

If you think you might find this kind of thing useful: It's on https://codeberg.org/AnselmF/sierra-config, and it's trivial to install.

Kategorie: edv

Letzte Ergänzungen