6

I'm currently trying to setup my Raspberry Pi Zero W as a WiFi repeater, but the kicker is that I don't want to use another USB WiFi card. First of all, is this even possible, and if it is, what steps would I need to follow to set this up?

There are plenty of tutorials on how to setup the Raspberry Pi to share the Internet connection received from the Ethernet port (https://thepi.io/how-to-use-your-raspberry-pi-as-a-wireless-access-point/), and a few tutorials on how to extend the WiFi connection by using a secondary USB WiFi card (https://scribles.net/creating-wireless-router-using-raspberry-pi-zero-w/).

However I haven't been able to find any on how to extend a WiFi signal using the one WiFi card?

slm
  • 163
  • 1
  • 10
Kieran Sonter
  • 63
  • 1
  • 1
  • 3

1 Answers1

11

This setup is DEPRECATED and no longer maintained!
Look at Access point as WiFi repeater, optional with bridge for a more flexible setup.


It is possible to use the wifi device on a Raspberry Pi as an access point and at the same time connect as client to another already established wlan. I have heard this is possible for RPi-0W, RPi-3B and RPi-3B+. But better you check it by yourself on your hardware with:

rpi ~$ sudo iw list | grep -A4 "valid interface combinations:"
valid interface combinations:
     * #{ managed } <= 1, #{ P2P-device } <= 1, #{ P2P-client, P2P-GO } <= 1,
       total <= 3, #channels <= 2
     * #{ managed } <= 1, #{ AP } <= 1, #{ P2P-client } <= 1, #{ P2P-device } <= 1,
       total <= 4, #channels <= 1

The important part is: #{ managed } <= 1, #{ AP } <= 1

But it is not possible to configure a Raspberry Pi as a clean repeater because for this you need to bridge the wlan client interface. On wifi this is done with WDS (Wireless Distribution System). For this you have to extend the ip header with one additional address field with sudo iw dev wlan0 set 4addr on. This is not supported by the wifi chip on the Raspberry Pi. For further information look at (3).

But you can use routing to connect the access point to the next wifi router. The only disadvantage is that you have different ip addresses on the network from the access point and from the next router.

Here is how to setup it. For reference I use a RPi3B+ with Raspbian Stretch Lite 2018-06-27. In this example I use

                 wifi                            wifi               wan
mobile-phone <.~.~.~.~.~.> (ap0)RPi(wlan0) <.~.~.~.~.~.~.> router <-----> INTERNET
            \               /          \                  /
           (dhcp)   192.168.50.1    192.168.10.2    192.168.10.1

I've found that we have to setup the needed services in a strict sequence, otherwise it won't work.

  1. create a virtual interface ap0 for the access point
  2. start access point daemon hostapd using interface ap0
  3. start wpa_supplicant for wifi client using interface wlan0

Starting services depending on others can be done very well with systemd. So I will use that and consequently its network management systemd-networkd. All commands can simply copied and pasted (including EOF) to your command line.


Step 1: setup systemd-networkd

For detailed information look at (1). Here only in short. Execute these commands:

pi@raspberrypi: ~$ sudo -Es
root@raspberrypi: ~# mkdir -p /var/log/journal
root@raspberrypi: ~# systemd-tmpfiles --create --prefix /var/log/journal #ignore warnings (*)

root@raspberrypi: ~# systemctl mask networking.service
root@raspberrypi: ~# systemctl mask dhcpcd.service
root@raspberrypi: ~# sudo mv /etc/network/interfaces /etc/network/interfaces~
root@raspberrypi: ~# sed -i '1i resolvconf=NO' /etc/resolvconf.conf

root@raspberrypi: ~# systemctl enable systemd-networkd.service
root@raspberrypi: ~# systemctl enable systemd-resolved.service
root@raspberrypi: ~# ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

(*) You will get one or two confusing warnings "...Cannot set file attribute..." This are not errors and doesn't matter in this case.

Create these files for interfaces wlan0 and ap0 with your settings:

root@raspberrypi:~ # cat > /etc/systemd/network/08-wlan0.network <<EOF
[Match]
Name=wlan0
[Network]
Address=192.168.10.2/24
Gateway=192.168.10.1
EOF

root@raspberrypi: ~# cat > /etc/systemd/network/12-ap0.network <<EOF
[Match]
Name=ap0
[Network]
Address=192.168.50.1/24
DHCPServer=yes
IPForward=yes
EOF

Setup wpa_supplicant with this file and your settings and enable it:

root@raspberrypi:~ # cat >/etc/wpa_supplicant/wpa_supplicant-wlan0.conf <<EOF
country=DE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="wlan@hoeft-online.de"
    psk="verySecretPw"
}
EOF

root@raspberrypi:~ # chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
root@raspberrypi:~ # systemctl disable wpa_supplicant.service
root@raspberrypi:~ # systemctl enable wpa_supplicant@wlan0.service
root@raspberrypi:~ # exit
pi@raspberrypi:~ $

reboot.

Then you should be connected to your existent wlan as normal. Interface wlan0 has state UP with an ip address 192.168.10.2. Check with ip addr and/or systemctl status wpa_supplicant@wlan0.service. You are able to ping www.google.com.

ap0 isn't set because the virtual interface isn't created yet.


Step 2: install hostapd

Hostapd is used to establish the access point. Install and stop it with:

pi@raspberrypi:~ $ sudo -Es
pi@raspberryrypi:~ # apt update
root@raspberrypi:~ # apt install rng-tools hostapd
root@raspberrypi:~ # systemctl stop hostapd

Create this file with your settings for ssid= and wpa_passphrase=:

root@raspberrypi:~ # cat > /etc/hostapd/hostapd.conf <<EOF
interface=ap0
driver=nl80211
ssid=RPiNet
hw_mode=g
channel=7
wmm_enabled=0
macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=2
wpa_passphrase=verySecretPw
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP
EOF

root@raspberrypi:~ # chmod 600 /etc/hostapd/hostapd.conf

Please use a passphrase that is long enough, I would say at least with 8 characters. It was told that 4 characters are to small and hostapd will refuse to accept connections. You will not find the access point RPiNet in your mobile phone (thanks to @Leo).

It should be said that a channel= must be in the conf but it is ignored. The wifi device can only work with one frequence (channel) so the channel of the access point is always set to the channel the RasPi is connected to the existent wlan.

Set DAEMON_CONF="/etc/hostapd/hostapd.conf" in /etc/default/hostapd with:

root@raspberrypi:~ # sed -i 's/^#DAEMON_CONF=.*$/DAEMON_CONF="\/etc\/hostapd\/hostapd.conf"/' /etc/default/hostapd

In /etc/init.d/hostapd in section INIT INFO you have to comment the line # Should-Start: $network. It should have two ## at first characters so it looks like:

## Should-Start:        $network

If we comment this line (with the second #) it will not come to play in this file. This network start is for old style SysV init system and conflicts with systemd. The network start is also managed by systemd and produces an error together with wpa_supplicant: "Found ordering cycle on hostapd.service/start" and prevents it to start. So we have to disable network start in /etc/init.d/hostapd.

hostapd can only start when the interface ap0 is created. We do this with a drop-in file (2) so we don't have to touch the original unit for hostapd.service.

root@raspberrypi:~ # systemctl edit hostapd.service

In the empty editor insert these statements, save it and quit the editor:

[Service]
ExecStartPre=/sbin/iw dev wlan0 interface add ap0 type __ap

Check with systemctl cat hostapd.service and/or systemctl status hostapd.service.


Step 3: start wpa_supplicant after hostpad

Here we only set a dependency. We also do it with a drop-in file:

root@raspberrypi:~ # systemctl edit wpa_supplicant@wlan0.service

In the empty editor insert these statements, save it and quit the editor:

[Unit]
After=hostapd.service

Reboot.

Then you should have interfaces ap0 and wlan0 state UP, each with an ip address. You should also see the access point, here RPiNet, in your mobile phone and it should get an ip address by connecting to the access point. Check with ip addr and/or systemctl status wpa_supplicant@wlan0.service.


Step 4: setup routing

Ip forwarding must be enabled for routing. That we have already done with IPForward in /etc/systemd/network/12-ap0.network so it sends all packages with unknown destination addresses, e.g. internet addresses to the next hop. That is the internet router 192.168.10.1.

We have to set a static route in the internet router so it can find the route for returning packages from the internet over the RasPi to the network from the access point 192.168.50.0/24. On most internet router you can set a static route but how to do that varies from model to model. It's up to you to find it out. For our example the gateway (next hop) is 192.168.10.2, destination network is 192.168.50.0/24 (or 192.168.50.0 netmask 255.255.255.0).

That means for the internet router: "send all packages belonging to subnet 192.168.50.0/24 (destination network) to the next router on my subnet, the RasPi access point 192.168.10.2 (gateway). It knows where to go on."

If you have setup your internet router then all is done.

The setup is finished.

Only if you have no access to the internet router you can fake it with NAT (network address translation) to tell it a lie that all packages are coming from your RasPi. Set this on your Raspberry Pi:

rpi ~$ sudo iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE

And delete it:

rpi ~$ sudo iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE

This is also a quick check after step 3 to test if everything works as it should before reconfiguring the internet router. Setting a NAT, then with your mobile phone connected to the access point you should be able to browse the internet.

To make NAT persistent, execute sudo systemctl edit wpa_supplicant@wlan0.service and append this in the editor:

[Service]
ExecStartPost=/sbin/iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
ExecStop=/sbin/iptables -t nat -D POSTROUTING -o wlan0 -j MASQUERADE

But this should only be the second choise because it's a hack and has limitations. With this you cannot connect from clients on the router wifi (192.168.10.0/24) to clients on the access point (192.168.50.0/24). Your internet router also uses NAT so we have a double NAT that's not good for performance.


refefences:
[1] Howto migrate from networking to systemd-networkd with dynamic failover
[2] man systemd.unit - Example 2. Overriding vendor settings
[3] Raspberry Pi WiFi to Ethernet Bridge for a server?

Ingo
  • 42,107
  • 20
  • 85
  • 197
  • In the last step "sudo ip route add 192.168.50.0/24 via 192.168.10.2 dev ethX" gives me an error "Cannot find device 'ethX'". Is there something I am missing? – Kieran Sonter Aug 24 '18 at 02:10
  • @KieranSonter Yes, you have overseen the sentence before: "On a Raspberry Pi it would look like this (don't set it on your RasPi access point!)*". This line is only an example how you would set a static routing if your router were a Raspberry Pi* or another linux machine. But you are not the first one who was confused by this example. So I have deleted it in the answer. – Ingo Aug 24 '18 at 08:00
  • Hi @KieranSonter, I'm just working again on this solution. Is it possible that you accept my answer? I need this for reference. If you can't accept it I would like to move this to a self answered question. – Ingo Sep 30 '18 at 12:18
  • Yeah sure mate! I believe I have done that now (it's just the little tick right?). This solution worked for me perfectly btw. – Kieran Sonter Oct 01 '18 at 20:19
  • @KieranSonter Yes, that was the right little tick :). Thank you. I'm glad that it help you and it works. – Ingo Oct 01 '18 at 21:35
  • Awesome answer, einfach toll! Now checking out the non- depreciation answer. There is wisfom here beyond the raspberry Pi's realm. It's such a common use case, I've been doing the same with assorted methods on a variety of devices for about 20 years now. It's pretty much the same, except that the router device gets smaller and smaller every year. Perhaps it won't get any smaller than the Pi-0 – hlecuanda Dec 30 '18 at 20:51