Lozworld™
A whole world of Loz Gray

Raspberry Pi LTE router, wwan0 to eth0

09 December 2022

Recently there was maintenance in our area by our broadband service provider which meant tethering to our phones to enable us to work from home. Me being me I thought, “I know how I can solve this for the future – build an LTE router with a Raspberry Pi”. What follows is the outcome of a painful two months of tinkering on and off.

1. The kit

First things first, you’ll obviously need a spare Raspberry Pi. If you don’t already have one, good luck with that. Thankfully I had the Pi 4 that I’d built as a Retropi machine that, well, we all know how that goes: build it, set it up, tinker, store it in a drawer.

For the LTE modem, I initially bought the Waveshare SIM7600 USB dongle, for reasons unknown. After getting severely hacked off with it seemingly recognising the dongle at random, either directly plugged in or using the extension lead, I decided to… double down and buy the hat version. This connected without fail.

2. Basic setup

To set the pie up, I took the opportunity to test out the network install feature that is now part of the Pi bootloader. To sort that out it was nessessary for me to put a basic Lite image on an SD card, update the bootloader and set the boot order to Network Boot in the Advanced Options menu of raspi-config.

With this set up, its the usual dance of updating and upgrading as soon as you log into your Pi for the first time:

:~ $ sudo apt update && sudo apt upgrade -y

Then a brief soujorn into raspi-config to set up the serial interace:

1 Interface Options > I6 Serial Port > Login shell accessible over SSH: No > Serial port hardware enabled: Yes

Once done I moved on to setting up the folder and file for the public SSH key:

:~ $ mkdir ~/.ssh
:~ $ touch ~/.ssh/authorized_keys
:~ $ chmod 700 ~/.ssh
:~ $ chmod 600 ~/.ssh/authorized_keys
:~ $ ls -lna ~/.ssh
drwx------ .
-rw------- authorized_keys

After adding my public key to the authorized_keys file, I edited the /etc/ssh/sshd_config file – probably overkill in this instance, though good practice all the same:

Port $[ssh-port-number]
AddressFamily inet
[…]
LoginGraceTime 20
PermitRootLogin no
[…]
MaxAuthTries 3
[…]
PubkeyAuthentication yes
[…]
PasswordAuthentication no
PermitEmptyPasswords no
[…]
ChallengeResponseAuthentication no
[…]
KerberosAuthentication no
[…]
GSSAPIAuthentication no
[…]
AllowAgentForwarding no
[…]
X11Forwarding no
[…]
PermitUserEnvironment no
[…]
PermitTunnel no

Although some guides recommend it, setting AllowTcpForwarding to no will mean you can’t connect via Visual Studio Code.

Once configured, the service needed to be restarted:

:~ $ sudo systemctl restart sshd

Ordinarily at this point I would have installed then configured UFW and Fail2Ban however, as “most mobile carriers take care of firewalls”:https://www.reddit.com/r/AskNetsec/comments/ce0n03/firewall_needed_for_lte/, this was unnecessary.

The last step was disabling and uninstalling ModemManager which will by default try to manage the LTE modem:

:~ $ sudo systemctl unmask ModemManager.service # may not need this
:~ $ sudo systemctl disable ModemManager.service
:~ $ sudo apt remove modemmanager -y

3. Setting up the LTE modem

Getting the LTE modem to be recognised by the Pi is relatively hard work and thankfully the lovely people of the Raspberry Pi forums have solved this. In combination with a great article by Jeff Geerling, I was able to get the LTE interface up and running fairly painlessly, on boot.

There were three checks to do to make sure the modem was being seen by the Pi. The first was to check that it appeared as a USB device:

:~ $ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 1e0e:9001 Qualcomm / Option SimTech, Incorporated
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

The second was to check that it was appearing as a CDC device, cdc-wdm0:

:~ $ ls /dev/cdc*
/dev/cdc-wdm0

The last check is to make sure it was appearing as a network interface, at wwan0:

:~ $ ip a
[…]
4: wwan0: […]
[…]

With the checks complete, I could move on to installing the necessary software:

:~ $ sudo apt install libqmi-utils udhcpc -y

Once done, I quickly checked to make sure the modem was online:

:~ $ sudo qmicli -d /dev/cdc-wdm0 --dms-set-operating-mode='online'

After this, it was necessary to set the modem’s protocol to raw_ip:

:~ $ sudo ip link set wwan0 down
:~ $ echo 'Y' | sudo tee /sys/class/net/wwan0/qmi/raw_ip
:~ $ sudo ip link set wwan0 up

If you need to confirm the setting, you can run the following:

:~ $ sudo qmicli -d /dev/cdc-wdm0 --wda-get-data-format
[…]
               Link layer protocol: 'raw-ip'
[…]

Most guides now recommend you run a commnand to set the APN, username and password. For some reason the GiffGaff sim I was using did not require this. What was required was actually starting the device:

:~ $ sudo qmi-network /dev/cdc-wdm0 start

This brought me to the first moment of truth – trying to connect the device to the GiffGaff network. Running the following gave the LTE modem it’s default IP and route:

:~ $ sudo udhcpc -q -f -i wwan0

If everything was successful, running ip a again should display an IP address for wwan0, probably in the private 10.x.x.x range.

The connection was then tested by pinging Google:

:~ $ ping -I wwan0 www.google.com -c 3
[…]
--- www.google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 4006ms
rtt min/avg/max/mdev = 31.199/46.540/58.827/8.962 ms

As all of the above modem config is necessary after a reboot, the easiest way to have it come online automatically was to set up a config file in /etc/network/interfaces.d. From a lot (a lot) of reading, I gather that this is one of about 25 million ways of configuring networks on Linux, and not necessarily the most recent one. But whatever, it worked for me:

:~ $ sudo nano /etc/network/interfaces.d/wwan0
auto wwan0
iface wwan0 inet manual
  pre-up ifconfig wwan0 down
  pre-up echo Y > /sys/class/net/wwan0/qmi/raw_ip
  pre-up for _ in $(seq 1 10); do /usr/bin/test -c /dev/cdc-wdm0 && break; /bin/sleep 1; done
  pre-up for _ in $(seq 1 10); do /usr/bin/qmicli -d /dev/cdc-wdm0 --nas-get-signal-strength && break; /bin/sleep 1; done
  pre-up /usr/bin/qmi-network /dev/cdc-wdm0 start
  pre-up udhcpc -i wwan0
  post-down /usr/bin/qmi-network /dev/cdc-wdm0 stop

On rebooting, the LTE modem worked successfully, getting an IP address, and allowing pings to Google. This worked flawlessly for the hat, but this was always the stage where the dongle would randomly crap out – I never did figure out why.

4. Sharing the LTE connection with the ethernet port

This is where it got complicated, for two reasons. Firstly most guides are old, for pre-Buster versions of RaspberryPi OS. Secondly, most guides assume you want to share the Wifi connection, wlan, with the ethernet port, eth0, not wwan0 to eth0 as I was trying to do. Simply replacing wlan with wwan didn’t seem to work when I tried.

Thankfully I stumbled across a StackExchange post with a link to a script on Github that did work.

The first thing to do is install dnsmasq:

:~ $  sudo apt-get install dnsmasq

Having already configured the wwan0 interface, I just needed to configure the wlan and eth0 interfaces. The reason for configuring wlan was because I later went rogue and turned off dhcpcd as I was doing everything through /etc/network/interfaces.d/.

For the wlan0 interface:

:~ $ sudo nano /etc/network/interfaces.d/wlan0
allow-hotplug wlan0
iface wlan0 inet static
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
    metric 0
    address $[ip-address]
    netmask $[subnet]
    network $[ip]
    router $[router-ip-address]

Then for the eth0 interface:

:~ $ sudo nano /etc/network/interfaces.d/eth0
auto eth0
iface eth0 inet static
    metric 200
    address 192.168.2.1
    netmask 255.255.255.0
    network 192.168.2.0
    broadcast 192.168.2.255

It was also necessary to enable packet forwarding, by uncommenting net.ipv4.ip_forward=1:

:~ $ sudo nano /etc/sysctl.conf
[…]
net.ipv4.ip_forward=1
[…]

Downloading the script and making it executable with chmod +x was the last step – I placed the script in my home directory, updated the variables to use capitals, and the commands in it to use ip instead of ifconfig:

NETMASK="24"
[…]
sudo ip link set dev $ETH down
sudo ip link set dev $ETH up
sudo ip addr add $IP_ADDRESS/$NETMASK dev $

With all of that done, it was time to run the script and plug the laptop into the Pi ethernet port. Nervously I turned Wifi off, and… success – I was able to browse the web via the LTE connection on my Pi. Speeds were not great, but usable, though turning off iCloud Private Relay seemed to improve them. The big test will be plugging this into my network setup – we’ll see how that goes.

Recent

  • Raspberry Pi LTE router, wwan0 to eth0

    09 December 2022

  • Raspberry Pi 4b as an Ubuntu 21.10 USB gadget tethered to an iPad Pro

    12 December 2021

  • Running a distributed workshop in Miro

    23 May 2020

  • Devices all the way up: Notes on responsive design

    05 April 2016

  • Home
  • About
  • Contact
  • Feed

© Copyright Loz Gray, 2023