TUTORIAL / SCRIPT: How to share Internet connection with WiFi hotspot

Until a better solution is put together by Purism, you can share your internet connection (4G or ethernet) via the WiFi hotspot of the Librem 5, here is how I do it:

First activate your hotspot

Forwarding - The manual way

You have to get the network address of your hotspot with

ip r

You should have a line with dev wlan0 (if your hotspot use wlan0)

10.42.0.0/24 dev wlan0 proto kernel scope link src 10.42.0.1 metric 600

To activate the forwarding, with the wlan0 IP (here 10.42.0.0/24) :

sudo sysctl net.ipv4.ip_forward=1
sudo iptables-legacy -t nat -A POSTROUTING -s 10.42.0.0/24 ! -d 10.42.0.0/24 -j MASQUERADE

To disable:

sudo sysctl net.ipv4.ip_forward=0
sudo iptables-legacy -t nat -D POSTROUTING 1

The 1 after POSTROUTING corresponds to the rule number which can be listed with

sudo iptables-legacy -n -t nat --list --line-numbers | grep MASQUERADE
1 MASQUERADE all – 10.42.0.0/24 !10.42.0.0/24

Forwarding - The semi-automatic scripted way

I made a script to activate or deactivate the IPv4 forwarding from the WAN to the WIFI when hotspot is activated

BE AWARE the script is not perfect, it badly handles the MASQUERADE rules if you have already configured one, consider it an simple ease-of-use until the good solution is available

Create a file in /home/purism/ named hotspot_bridge.sh containing the following code

#!/bin/bash                                                                                                                                                                                                              

ERROR="\e[31mError\e[0m:"

# Default interface for Wifi hotspot                                                                                                                                                                                     
dev_net_wifi=wlan0

# Check if activating or deactivating                                                                                                                                                                                    
verif=$(sudo iptables-legacy -n -t nat --list | grep MASQUERADE)
if [ "${verif}" != "" ] ; then
    # MASCARADE rule present, deactivate forwarding                                                                                                                                                                      
    sudo sysctl net.ipv4.ip_forward=0
    sudo iptables-legacy -t nat -D POSTROUTING 1
    [ -e /usr/share/applications/hotspot_bridge.desktop ] && sudo sed -i 's/network-wireless-signal-excellent-symbolic.svg/network-wireless-disabled-symbolic.svg/' /usr/share/applications/hotspot_bridge.desktop
    exit 0
fi
# MASCARADE rule not present, try to activate forwarding                                                                                                                                                                 

# Checking the icon
if [ -e /usr/share/applications/hotspot_bridge.desktop ] ; then
    # Wrong icon, putting the right one                                                                                                                                                                              
    verif=$(grep network-wireless-signal-excellent-symbolic.svg /usr/share/applications/hotspot_bridge.desktop)
    [ "${verif}" != "" ] && sudo sed -i 's/network-wireless-signal-excellent-symbolic.svg/network-wireless-disabled-symbolic.svg/' /usr/share/applications/hotspot_bridge.desktop
fi

# Check if WiFi interface is available                                                                                                                                                                                   
verif=$(ip link | grep "${dev_net_wifi}")
if [ "${verif}" == "" ] ; then
    echo -e "$ERROR Network interface '${dev_net_wifi}' not found"
    # Searching for an other wlan (taking first one)                                                                                                                                                                     
    dev_net_wifi=$(echo -e "${list_interface}" | grep -m1 wlan | awk '{ print $1 }')
    [ "${dev_net_wifi}" == "" ] && echo -e "$ERROR No wlan interface found" && exit 1
    echo "=> WLAN interface found : ${dev_net_wifi}"
fi

# Searching available route                                                                                                                                                                                              
verif=$(ip r | grep ^default)
[ "${verif}" == "" ] && echo -e "$ERROR No default route found on network interfaces" && exit 1

# Getting IP of WiFi hotspot                                                                                                                                                                                             
ip_wifi=$(ip r | grep -v ^default | grep -m1 "${dev_net_wifi}" | awk '{ print $1 }')
[ "${ip_wifi}" == "" ] && echo -e "$ERROR Could not determine WiFi IP for interface ${dev_net_wifi}" && exit 1

# Activating the forwarding                                                                                                                                                                                              
sudo sysctl net.ipv4.ip_forward=1
[ $? -ne 0 ] && echo -e "$ERROR Unable to activate forwarding" && exit 1

sudo iptables-legacy -t nat -A POSTROUTING -s "${ip_wifi}" ! -d "${ip_wifi}" -j MASQUERADE
if [ $? -ne 0 ] ; then
    sudo sysctl net.ipv4.ip_forward=0
    echo -e "$ERROR Unable to add POSTROUTING iptables rule"
    exit 1
fi

[ -e /usr/share/applications/hotspot_bridge.desktop ] && sudo sed -i 's/network-wireless-disabled-symbolic.svg/network-wireless-signal-excellent-symbolic.svg/' /usr/share/applications/hotspot_bridge.desktop

exit 0

After copy/paste and save, add the execute rights:

chmod +x hotspot_bridge.sh

First execution will activate the forwarding between interfaces
Second execution will deactivate the forwarding

If you want to confirm in what state you are, you can execute the following command, 1 = on, 0 = off

cat /proc/sys/net/ipv4/ip_forward

Icon shortcut

You can also create the following shortcut /usr/share/applications/hotspot_bridge.desktop using the script, it will add a Wifi icon called “Hotspot bridge”

[Desktop Entry]
Type=Application
Name=Hotspot bridge
GenericName=Hotspot bridge
Comment=Enable or disable bridge beteween network interface and hotspot
Icon=/usr/share/icons/Adwaita/scalable/status/network-wireless-disabled-symbolic.svg
Exec=/home/purism/hotspot_bridge.sh
Terminal=true
Categories=network;
Keywords=bridge;network;hotspot;wifi;

First tap will activate the forwarding between interfaces and the icon will change to an active WiFi picture
Second tap will deactivate the forwarding and the icon will change to a deactivated WiFi picture

I tried it with success when the Librem5 is connected with 4G or is connected with an ethernet cable
My laptop connected to the Librem 5 hotspot add access to Internet, nothing special to do on it

Let me know if it worked for you, or not :wink:
Or if you see some improvements to make !

Forwarding - The full-automatic scripted way

Here, an other solution from Loki, where the forwarding is triggered when hotspot is activated

10 Likes

The reason it does not work when you have both an active Ethernet and 4G connection is that traffic is getting routed through the Ethernet connection while you’re masquerading on the cellular interface.

NetworkManager is using it’s default routing priorities which is to favor Ethernet over wireless over cellular. Your script first checks for an IPv4 network on the cellular interface and, if found, masquerades on that interface regardless on whether or not there are other active networks with greater routing priorities.

I’d be inclined to masquerade on the hotspot network (which will almost certainly be 10.42.0.0/24) rather than by interface as it’s a single masquerade rule which will cover any active interface and will also handle, a little better, changing routes due to interfaces coming up and down.

I also think that the logic determining which, if any, WAN interface to use could be greatly simplified by looking at routes rather than links and/or addresses, assuming the default share network address of 10.42.0.0/24 is used for hotspots…

# pseudo-code
if [ ! -z "$(ip r | grep ^default)" ]
then
  sudo sysctl net.ipv4.ip_forward=1
  sudo iptables-legacy -t nat -A POSTROUTING -s 10.42.0.0/24 ! -d 10.42.0.0/24 -j MASQUERADE
  # anything else required when bringing up hotspot
else
  # no IPv4 routes available
fi

Essentially, if there is a default route then masquerade, ip r only lists IPv4 routes.

And if you need to get the current interface serving the default route…

dev_net_wan=$(ip r | grep ^default | awk '{print $5}')

Is it required to enable forwarding? I know that standard connection sharing does not work out the box on the Librem 5. However, after creating a shared connection on other interfaces all that is needed is the masquerade rule. I haven’t looked much into it but it did occur to me that perhaps it fails because NetworkManager is calling out to iptables rather than iptables-legacy for the masquerade rule? If that were the case, NetworkManager will already be enabling forwarding when you activate the hotspot.

You might want to consider some clean up on error rather than simply exiting. For example…

To get here, you have first enabled IPv4 forwarding, so if it errors now, the script exits with no masquerade rule and leaving forwarding enabled?

2 Likes

Very nice ! ip r simplify everything thanks !

I will update my post

1 Like

Do you have a better way to target the removing of the MASQUERADE rule we put ?
I feel like it could be better done, here I just delete the first one (If I got it right)

iptables-legacy -t nat -D POSTROUTING 1

Perhaps…

MASQRULE=$(sudo iptables-legacy -t nat -L --line-numbers | grep "MASQUERADE.*${ip_wifi}" | awk '{print $1}')
sudo iptables-legacy -t nat -D POSTROUTING ${MASQRULE}
1 Like

That’s a good solution, but it made me realize I need to get the WiFi IP before removing the rule, which fails if hotspot was disabled before the forwarding

I either use the static ip_wifi=10.42.0.0/24 everywhere but could end up with forwarding not working in some cases
Or use the dynamic way and mess up with the MASCARADE rules in some cases

I prefer the second case, so I just put a remark about this behavior

Here’s my take, this is a slightly different approach, this hooks into NetworkManager’s dispatcher and will get called every time there is a network interface state change. This means that this script will automatically run any time the WiFi hotspot is enabled or disabled.

This is just a quick and dirty test with very little sanity or error checking. I’ve given it a quick run through and it seems to work in it’s rather crude state. I’m quite limited on testing capability tho as the WiFi performance on my phone is quite poor and suffers from stability issues. The IP regex is quite lose and I haven’t bothered to check/trap if there is actually an IPv4 network to route to among other areas that could be improved.

I called the file “50-shared-masquerade” to install the script you have to set permissions to 755…

chmod 755 50-shared-masquerade

Then set ownership to root…

sudo chown root:root 50-shared-masquerade

And finally move into NetworkManager’s dispatcher directory…

sudo mv 50-shared-masquerade /etc/NetworkManager/dispatcher.d/

Then any time you enable or disable the hotspot the masquarade rules should automatically be set and removed as required.

Maybe some of this will be helpful to you, here’s the script…

EDIT: The script has been updated to handle any type of connection share, hotspot, shared via Ethernet etc., Multiple shared connections can be active simultaneously, enabling/disabling one connection will not interfere or disturb any others.

#!/bin/bash

STATUS=$2
CONNID=${CONNECTION_UUID}

[[ -z $(nmcli -t c s ${CONNID} | grep ipv4.method:shared) ]] && exit 0

NETWORKADDR=$(nmcli -t c s ${CONNID} | grep ipv4.addresses: | \
              awk -F ":" '{print $2}')

: ${NETWORKADDR:=10.42.0.0/24}

case ${STATUS} in
    up)
      iptables-legacy -t nat -A POSTROUTING -s ${NETWORKADDR} \
                           ! -d ${NETWORKADDR} -j MASQUERADE
      ;;

    down)
      for ACTCONN in $(nmcli -t -f STATE,UUID c s | grep ^activ \
                     | awk -F ":" '{print $2}')
      do
        [[ ! -z $(nmcli -t c s ${ACTCONN} \
                | grep ipv4.method:shared) ]] \
               && SHR=1
      done

      [[ -z ${SHR} ]] && sysctl net.ipv4.ip_forward=0

      iptables-legacy -t nat -D POSTROUTING -s ${NETWORKADDR} \
                           ! -d ${NETWORKADDR} -j MASQUERADE
      ;;
esac

exit 0

3 Likes

That’s nice ! I have added your post in the bottom of mine as a “full-automatic” solution

1 Like

thank you @fralb5 and @Loki , Ive been wanting to use this for a while! Will try it soon and report back.

Great to see the growing community coming up with more of these tutorials!

1 Like

I hadn’t considered it a full blown script as such more of a skeleton, but, as you’ve linked to it, I’ll put some more time into it and enhance it a little.

I did consider checking for valid IPv4 routes and bailing if none found, but I then considered that someone may enable the hotspot before enabling mobile data or plugging into Ehternet. In these cases the hotspot would have to then be toggled to bring it up properly so I think I’ll leave it as is for those cases.

To answer my own question, when the hotspot is enabled, IP forwarding is automatically enabled by the system. However, when the hotspot is disabled, IP forwarding remains enabled, I think this may be by design.

When enabling the hotspot it’s a good bet that you’ll want IP forwarding enabled, but when disabling the hotspot there may be other shared connections relying on IP forwarding, these would fail if IP forwarding was disabled with the hotspot. It’s not inconceivable that you could have both a WiFi hotspot and an Ethernet connection to the phone both sharing the cellular connection simultaneously.

It also occurred to me that the script could be less focused on handling the WiFi hotspot only and being more general to handle any shared connection.

I’ll hopefully get it updated a little later today.

I don’t think I am affected by this consideration - and I haven’t even tried hotspotting yet - however I am using ethernet with my Librem 5 (via USB-to-GbE dongle). So it is definitely worth considering what creative configurations customers might be using. :wink:

The script has been updated to handle some of the more creative configurations. It can now handle connections sharing on multiple interfaces simultaneously.

I had the cellular connection being shared via both a hotspot and via Ethernet over USB at the same time, enabling/disabling one or the other just sets/removes the masquerade rules for that specific connection without interfering with the other.

When disabling a shared connection, the script now checks any other remaining active connections and will only disable IP forwarding if no other shared connections are running.

2 Likes

Thank you for sharing this script, but unfortunately it doesn’t work for me. I am trying to connect a mac to after enabling the Wifi hotspot on the L5, at first it seems to connect but after some 20 seconds the mac pops up a new password entry for the wifi hotspot that I have already entered correctly. Sometimes I can get a webpage to partially load on the mac before the connection is dropped. The L5 is very close to the mac so there shouldn’t be any problems regarding the distance between the devices.

The script just configures the required NAT rules and enables IP forwarding. It does not handle anything to do with establishing the actual link/connection between devices which sounds like where the root of the issue you are seeing resides.

I did a little sanity checking and testing at the time the script was created and did test with a Mac (2014 Macbook Pro - MacOS v10.15.3), I don’t recall any stand out issues at that time.

For reference, on the Librem 5 side, it was tested with Librem 5 Evergreen: Amber-phone, 5.9 kernel. There have been kernel updates since then and not all of them have yielded positive results, so there may now be issues with some aspects of the WiFi hotspot feature that were not present previously. I am not sure if testing/evaluating the wireless software/driver updates or general performance when running in AP mode prior to releasing is something that is done.

If it’s connecting, then prompting for a password shortly afterwards, I’d guess that it is attempting to establish a connection on one band (either 2.4GHz or 5GHz) and either failing or dropping the connection and then attempting to connect to the other band. Although it’s a single wireless card and both bands will share the same SSID, they are two distinct networks hence prompting for the password for the second network.

What is the IP and subnet of your internal network and cellular data? By default the hotspot will be on the 10.42.0.0/24 network, while not likely I would double check that it’s not overlapping with any other network connection.

Other than, if you have any other WiFi enabled devices you could test with, it may be there is some hardware compatibility issues between the Librem 5 and Mac.

2 Likes

It is repeated over and over again.

I have an Evergreen with the latest updates, so it could be that.

I’ve tried tethering from the mac to another device and that works fine. Also connecting from the L5 to a wifi hotspot works fine.

I’ll try to check the IP and subnet. One thing that I was thinking that may be different is that I have a sim-card with limited data. It is visible when opening the software center to install updates. To install updates I have to click “check anyway”. Just thinking that it could be something with that to do, but then I guess that most people have subscriptions with limited data.

Another thing I’ve seen using the L5 is that sometimes it loses it’s data connection. In order to fix that I have to go into the APN settings and deactivate and reactivate the APN settings. Maybe the wifi hotspot is triggering this bug for some reason.

@Loki may have meant: use the Librem 5 as a WiFi hotspot and try to associate a device other than a Mac to the Librem 5’s WiFi hotspot.

I would suppose that the majority of Librem 5 customers already own a smartphone. So you could try to associate your existing smartphone to the Librem 5’s hotspot.

I doubt that would make a difference unless your provider actually blocks you from connecting to the mobile network when you are out of data - but that would be a bit dumb on the part of the provider since some customers will want to use their smartphone to top up with more data.

To be honest, I would expect to be able to associate with the Librem 5’s WiFi hotspot even when the mobile connection is broken i.e. of course forwarding won’t work and of course internet access won’t work, but you should still be able to associate. Maybe it hasn’t been done like that however.

You should be able to use your existing smartphone at least to scan for WAPs and the Librem 5 should show up. Or if you have another Linux computer that has WiFi client capability then the iwlist command is your friend.

1 Like

It’s a likely suspect for sure, one fairly significant difference from 5.9 to the current 5.12 kernel is that it’s using a completely different driver for the Redpine (wireless) card.

I just upgraded to the 5.12 kernel to test the hotspot feature with the current kernel, unfortunately it breaks everything for me, after restarting and toggling the WiFi/BT HKS to bring up the card, enabling WiFi in software (via G-C-C) caused phosh to croak, when it came back up I had no WiFi, Cellular (voice or data) or Bluetooth. I’ve gone back to the 5.9 kernel.

I can’t think of any reason for this but stranger things have happened. They are all individual interfaces and should be able to operate independent of each other. As @irvinewade suggests, you should be able to enable the hotspot feature and establish a connection between the Librem 5 and your Mac regardless of the state or availability of the cellular data.

From my previous testing, at one point I had a hotspot connection established and gateways on both the cellular and USB interfaces. Enabling/disabling the gateway interfaces had no affect on the stability of the hotspot connection.

1 Like

Nice. And this is why I want a Linux phone. Thanks for the post.

What’s “everything”? (And what’s G-C-C? I know I should know this one but … :slight_smile:)

I am using kernel 5.12.0-1-librem5 and enabling the WiFi Hotspot works fine for me.

It looks to me that once you put the WiFi card into AP mode, it can no longer be a client and therefore it can’t access any other WAPs and if you were currently connected in to it via WiFi then that session will die. (This is not unusual behaviour for a basic WiFi card.)

Anyway, having enabled the Hotspot I was able to associate my desktop to the phone via WiFi and (after loosening the SSH server config on the Librem 5) SSH in from the desktop to the phone.

I chose not to enable IP forwarding or NAT, so I did not expect to be able to access the internet from my desktop via the Librem 5 (and that would have been messy anyway because the desktop is still on the wired network).

For the record, the phone gave itself IP address 10.42.0.1 and the DHCP range appears to be 10.42.0.10 - 10.42.0.254

I didn’t seem to have much success associating my iPhone with the Librem 5 hotspot. The iPhone can see the SSID but gives an error (either incorrect password or something else). Don’t know what’s happening there.

It looks as if the Librem 5 is advertising an additional authentication suite that my desktop does not recognise. Maybe the iPhone does recognise it and is trying to use it but one or both ends does not support it correctly.

“everything” in this case was (almost) all things comms/networking. Celluar, WiFi and BT all died. The cellular modem issue was possibly related to phosh croaking, the others simply did not function at all.

G-C-C (probably more accurate to use g-c-c) = gnome-control-center, essentially the settings app in PureOS. I have found using the term “g-c-c” rather than “settings” tends to avoid the follow up question of “which settings?”

1 Like