UPDATE: 2019-01-21
Because I get a question from time to time about this setup I decided to present an accepted answer at Switch between wifi client and access point without reboot.
Please refer to that answer because the following isn't maintained anymore!
According to your referenced link you are already using systemd-networkd. So I will start with configuring wlan0 as client connection. For reference I use Raspbian Stretch Lite 2018-06-27 full upgraded with sudo apt update && sudo apt full-upgrade && reboot
done at 2018-09-27.
Setup wpa_supplicant as wifi client with wlan0
Setup wpa_supplicant with this file and your settings and enable it.
rpi ~$ sudo -Es
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="[email protected]"
psk="verySecretPwassword"
}
EOF
rpi ~# chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
rpi ~# systemctl disable wpa_supplicant.service
rpi ~# systemctl enable [email protected]
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
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 84.200.70.40
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 [email protected]
rpi ~# systemctl edit --full [email protected]
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
[email protected]
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
Reboot.
Check with:
rpi ~$ sudo iw dev
rpi ~$ systemctl status [email protected]
You should then be able to:
rpi ~$ sudo systemctl start [email protected]
rpi ~$ sudo systemctl start [email protected]
No need to stop a service.
You may install this little helper to get faster random numbers for encryption:
rpi ~$ sudo apt install rng-tools
Troubleshooting
If you do not use Raspbian Stretch Lite 2018-06-27 full upgraded with sudo apt update && sudo apt full-upgrade && reboot
like me then you should download the image and try with it if you have a spare SD Card. This is to ensure it's not a problem with the hardware. If you use this version but have already done some installations and/or configurations it may be possible that you run into a common problem with configuring an access point.
If the physical interface, here it is wlan0, is occupied by a driver you may not be able to set an additional virtual interface ap0 on it. The error message is: command failed: Device or resource busy (-16)
. You can find this message in the journal. Look for messages like following with:
rpi ~$ journalctl -b -e
...
raspberrypi systemd[1]: Starting WPA supplicant daemon (interface-specific version)...
raspberrypi iw[641]: command failed: Device or resource busy (-16)
raspberrypi systemd[1]: [email protected]: Control process exited, code=exited status=240
raspberrypi systemd[1]: Failed to start WPA supplicant daemon (interface-specific version).
raspberrypi systemd[1]: [email protected]: Unit entered failed state.
raspberrypi systemd[1]: [email protected]: Failed with result 'exit-code'.
Here you see the line prefixed with: raspberrypi iw[641]:
. It is the line we are looking for. It is now up do you to find what service on your installation occupies the wifi device. You can test if the access point starts when you delete ap0 before:
rpi ~$ sudo iw dev ap0 del
rpi ~$ sudo systemctl start [email protected]
If it works you can add a line just before ExecStartPre=
in [email protected]. Consider the minus sign after the equal sign. It supresses error messages in case there is no ap0:
ExecStartPre=-/sbin/iw dev ap0 del
Now we have two ExecStartPre. You can try to set ap0 before any other service. This is done with this extra service, created with sudo systemctl edit --force --full interface-ap0.service
:
[Unit]
Description=Interface for the access point
Documentation=https://raspberrypi.stackexchange.com/q/89428/79866
Requires=sys-subsystem-net-devices-wlan0.device
After=sys-subsystem-net-devices-wlan0.device
Wants=network.target
Before=network.target
[email protected]
[Service]
Type=oneshot
ExecStart=/sbin/iw dev wlan0 interface add ap0 type __ap
[Install]
WantedBy=multi-user.target
Enable it:
rpi ~$ sudo systemctl enable interface-ap0.service
Reboot.
But interface-ap0.service may not help if the unknown service, occupying the wifi device, also starts Before=network.target. If you find the unknown service you can add a line Before=name-of-unknown.service
In the Unit section of interface-ap0.service.
Maybe you can find some hints with:
rpi ~$ systemctl list-dependencies