6

I want my Raspberry Pi to be used as access point or as client connected to my internet router but not both together. So I want to switch between these two modes with one simple command without rebooting.
How can I do this?

Ingo
  • 40,606
  • 15
  • 76
  • 189

3 Answers3

8

Access point and client mode are both running as services so we should use systemd-networkd to switch off one service and switch on the other. With its options we are able to do it without rebooting. For reference I use Raspbian Stretch Lite 2019-04-08 full upgraded with sudo apt update && sudo apt full-upgrade && sudo reboot done at 2019-04-14.

Setup systemd-networkd

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

# disable debian networking and dhcpcd
rpi ~$ sudo -Es
rpi ~# systemctl mask networking.service dhcpcd.service
rpi ~# sudo mv /etc/network/interfaces /etc/network/interfaces~
rpi ~# sed -i '1i resolvconf=NO' /etc/resolvconf.conf

# enable systemd-networkd
rpi ~# systemctl enable systemd-networkd.service systemd-resolved.service
rpi ~# ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

Setup wpa_supplicant as wifi client with wlan0

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

rpi ~# 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="TestNet"
    psk="verySecretPwassword"
}
EOF

rpi ~# chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
rpi ~# systemctl disable wpa_supplicant.service
rpi ~# systemctl enable wpa_supplicant@wlan0.service

Setup wpa_supplicant as access point with ap0

Create this configuration file:

rpi ~# cat > /etc/wpa_supplicant/wpa_supplicant-ap0.conf <<EOF
country=DE
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="RPiNet"
    mode=2
    key_mgmt=WPA-PSK
    proto=RSN WPA
    psk="anotherPassword"
    frequency=2412
}
EOF

rpi ~# chmod 600 /etc/wpa_supplicant/wpa_supplicant-ap0.conf

Configure interfaces

Create these two configuration files:

rpi ~# cat > /etc/systemd/network/08-wlan0.network <<EOF
[Match]
Name=wlan0
[Network]
DHCP=yes
EOF

rpi ~# cat > /etc/systemd/network/12-ap0.network <<EOF
[Match]
Name=ap0
[Network]
Address=192.168.4.1/24
DHCPServer=yes
[DHCPServer]
DNS=84.200.69.80 1.1.1.1
EOF

Modify service for access point to use ap0

ap0 is a virtual interface and it must be created and deleted with start/stop of the service. It is also required to modify dependencies. This cannot be done with a drop in file, so we have to modify the full service. In addition this service conflicts with the client connection service with wlan0. We set a dependency Conflicts= so we do not have to care about stopping the other service. Do it with:

rpi ~# systemctl disable wpa_supplicant@ap0.service
rpi ~# systemctl edit --full wpa_supplicant@ap0.service

Modify/insert only these lines: Requires=, After=, Conflicts=, ExecStartPre= and ExecStopPost= as shown. Leave all other untouched, save it and quit the editor:

[Unit]
Description=WPA supplicant daemon (interface-specific version)
Requires=sys-subsystem-net-devices-wlan0.device
After=sys-subsystem-net-devices-wlan0.device
Conflicts=wpa_supplicant@wlan0.service
Before=network.target
Wants=network.target

# NetworkManager users will probably want the dbus version instead.

[Service]
Type=simple
ExecStartPre=/sbin/iw dev wlan0 interface add ap0 type __ap
ExecStart=/sbin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant-%I.conf -Dnl80211,wext -i%I
ExecStopPost=/sbin/iw dev ap0 del

[Install]
Alias=multi-user.target.wants/wpa_supplicant@%i.service

Now you can determine in which mode the RasPi should start after bootup. Just enable that service and disable the other one. If I want to start with client connection:

rpi ~$ sudo systemctl enable wpa_supplicant@wlan0.service
rpi ~$ sudo systemctl disable wpa_supplicant@ap0.service

Reboot.

You should then be able to switch the service with:

rpi ~$ sudo systemctl start wpa_supplicant@ap0.service
rpi ~$ sudo systemctl start wpa_supplicant@wlan0.service

No need to stop a service.


If you want to make the pi change between access point and client mode automatically, so that the pi provides an access point only if there is no known SSID nearby, then it isn't possible with this setup. The wpa_supplicant client service must always run so it can detect an available hotspot nearby. You can only switch on/off the access point in addition to the client service. So you have first to setup a Access point as WiFi repeater, optional with bridge or Access point as WiFi repeater with additional WiFi-dongle. Then you could use wpa_cli running as daemon with option -a to detect a connection to a hotspot and switch on/off the access point on the RasPi. A generic example of doing this you can find at Run a script when wifi is connected to a particular wifi network.

refefences:
[1] Howto migrate from networking to systemd-networkd with dynamic failover

Ingo
  • 40,606
  • 15
  • 76
  • 189
  • 1
    Is there an easy way to make the pi change between ap and client mode automatically, so that the pi provides an access point only if there is no known SSID nearby? – jake Apr 11 '19 at 00:40
  • @jake I have updated the answer with the last paragraph. Is that easy because we know how to do it? – Ingo Apr 11 '19 at 08:48
  • @ingo The new last paragraph suggest you MUST have a client connection to have the option of switching on the access point. I'm not sure you mean this as the rest of the answer does not mention it. Will starting the access point fail if there is no router and so no client? – theo-brown Jun 11 '19 at 19:19
  • @avidreader610 Sorry, the wording was unclear. I didn't mean a connection, instead running the service. I have corrected the answer. – Ingo Jun 12 '19 at 07:44
  • 1
    The line 'ExecStartPre=/sbin/iw dev wlan0 interface add ap0 type __ap' causes an error in my case. The help page of iw tells me that supported types are managed, ibss, monitor, mesh, wds. The value __ap is not supported. What am I doing wrong? I am running iw version 4.9 – Christoph Bimminger Oct 19 '19 at 01:05
  • Hi @ChristophBimminger, it is difficult to answer a question in comments. I need some more information about your setup. Can you please open a new question about this? Then we have more possibilities to interact. – Ingo Oct 19 '19 at 08:48
  • @PhilippNagel Thank you very much for the bounty :-) – Ingo Jan 21 '20 at 19:54
3

I would have commented but don't have enough reputation.

Ingo's answer almost worked for me. However there was a weird bug where the virtual interface was not removed sometimes. Apparently (source: https://github.com/seemoo-lab/nexmon/issues/221) this can happen because the broadcom driver crashes when the pi is started up without wifi.

The solution is to, after switching from ap to wlan, run the following command twice: sudo modprobe -r brcmfmac && sudo modprobe brcmfmac

That restarts the driver, and the virtual interface is/can be removed.

Tigris
  • 31
  • 3
  • Thanks for the helpful hint to restart the driver without reboot, +1. I have found that updated firmware is somewhat more stable. You can simply change the firmware version as shown at [Access point as WiFi router/repeater, optional with bridge](https://raspberrypi.stackexchange.com/a/89804/79866) under **IMPORTANT UPDATE**. It would very interesting for me if that also help you. What firmware version you are running? Check with `dpkg --list firmware-brcm80211`. – Ingo Sep 09 '20 at 20:57
  • @Ingo even after changing the firmware version the issue remains. When I run the command, I see I currently have the version 1:20190114-1+rpt4 installed, yet I still need to reboot the driver to get it working. – Tigris Nov 25 '20 at 08:36
3

Based on the answer by Ingo, I went and made a script to do this job.

https://github.com/Autodrop3d/raspiApWlanScripts

The gist is that there's one script to run that'll setup the Pi for reboot-less AP/STA switching and then there are helper scripts that'll actually do the switching for you.

jjfs85
  • 31
  • 1
  • I like the "Impartant notes" (assuming not a typo). Is there a summary of the files used/changed/created by the process? Just so I can back up what's on here. I have an idea but am also still noobish. – RufusVS Oct 04 '19 at 17:39