2

I have managed to setup my Raspberry Pi Zero W to work in both AP and Client mode simultaneously using this great guide.

Using wpa_cli -iwlan0 (no sudo), I am able to scan, connect and save networks dynamically (eventually programatically from Python).

For the AP, I have added the following two lines to /etc/hostapd/hostapd.conf to enable cli control through sudo hostapd_cli (strangely with sudo vs. wpa_cli which is without. Is that because of ctrl_interface_group=0?):

ctrl_interface=/var/run/hostapd ctrl_interface_group=0

Using sudo hostapd_cli disable I can turn off the AP without affecting the client. This does not bring down the interface, just the SSID I believe. Then, if I want to change the SSID and PSK etc. of the AP I can edit sudo nano /etc/hostapd/hostapd.conf. Then when I want to start the AP (with or without changing SSID/PSK), I use sudo systemctl restart hostapd.service. This gives and error but everything still works so I don't think that is an issue? Warning: The unit file, source configuration file or drop-ins of hostapd.service changed on disk. Run 'systemctl daemon-reload' to reload units. I'm not using sudo hostapd_cli enable as this gives an error and then causes issues, where restarting the service doesn't.

Like this there is very minimal client downtime since, as I understand, hostapd has full control of the interface and stopping hostapd.service brings down client mode.

Is this the best way to be doing all of this? Specifically with the AP part, I have not worked out a cleaner way to change the SSID and PSK without editing the file (e.g. by using hostapd_cli), is there one?

My main sticking point now is that when the pi boots, I want the AP to NOT be enabled. i.e. I want it to be as if the command sudo hostapd_cli disable has been run. I suppose I could run that command somewhere in the boot sequence but that means the SSID will likely come up for a short period and it would be much cleaner if it never enables in the first place. Any idea how I can stop the SSID from enabling on boot? I also tried disabled=1 in .conf but that crashed hostapd.

Edit: also very strangely, for some reason the AP works with bridge mode even though I did not follow the steps for that. Whilst this is great, I would like the option also of disabling it. Is that possible?

2 Answers2

3

I do not follow exactly all steps you have done because there are sophisticated dependencies between the services and interfaces. But here are some general thoughts that can explain your problems.

The ap0 interface is not an independent interface. It is only a virtual interface name of wlan0 and therefore it extremely depends on the status of wlan0. The all over all condition is the order to start the interfaces, otherwise the configuration will fail with error messages (interface already in use, crashing the driver and so on), as noted in section ♦ Details - General of my tutorial Access point as WiFi router/repeater, optional with bridge:

I've found that we have to setup this in sequence, otherwise, it won't work. If other applications bind to the wifi port it cannot be set.

  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

This order restricts the whole setup. It isn't possible to start hostapd when wpa_supplicant is running. You must first stop wpa_supplicant and then start hostapd and wpa_supplicant in this order. This is due to the WiFi driver brcmfmac.

These dependencies are managed by systemd-networkd and how it works you can see at the table in section ♦ Details - Conclusion. If you want to manage it by yourself with wpa_cli and hostapd_cli then you always have to have this order in mind and respect it. The only reason why it partially works for you is that you restart the services in the correct order with:

rpi ~$ sudo systemctl restart hostapd.service

Look at the table what it does. It also explains why the client connection interrupted a short time.

If you do not want to start the services on bootup then just disable the services:

rpi ~$ sudo systemctl disable hostapd.service
rpi ~$ sudo systemctl disable wpa_supplicant@wlan0.service

You can always start them manually with:

rpi ~$ sudo systemctl start hostapd.service

If you only want to execute a command after startup of the hostapd.service you can modify its drop in file:

rpi ~$ sudo systemctl edit hostapd.service

Then to the [Service] section add this statement:

ExecStartPost=/full/path/to/hostapd_cli disable

I don't know if this will work or may have problems with the starting order or may be too early to use.

Ingo
  • 40,606
  • 15
  • 76
  • 189
  • Thanks Ingo, I understand the dependency between the two. The main thing I want to do now is that on boot I want the AP SSID to be disabled as if the `sudo hostapd_cli disable` command has been run. There must be a point during boot that the enable command is run? Or else when the hostapd service is started, I want to run that disable command immediately after it...where would I incorporate that command? – Bassline Soup Jun 16 '20 at 12:03
  • @BasslineSoup I have updated the answer at the end. – Ingo Jun 16 '20 at 12:55
  • Thanks Ingo but I need the services to start, I just don't want the SSID to start. `sudo hostapd_cli disable` stops the SSID but the interfaces are still up – Bassline Soup Jun 16 '20 at 13:36
  • @BasslineSoup I have updated the answer at the end again. Please follow the answer, so I do not have always to comment this. – Ingo Jun 16 '20 at 14:10
  • Thanks Ingo - that worked. Any idea how to do the last part which is to stop the bridge? I followed your previous tutorials except for the bridge part, yet when I connect to a wifi network as a client, it then allows devices connected to the AP to access the same network. I want to stop that (and then later start as required). – Bassline Soup Jun 17 '20 at 15:20
  • @BasslineSoup If the answer helped you, it would be nice if you could accept it. Only accepting an answer will finish the question and it will not pop up again and again for years and annoing us with already having a solution. For the problem with dynamically managing the routing to the client connection you can use the linux firewall **nftables** (`apt show nftables`). – Ingo Jun 17 '20 at 16:43
  • Thanks Ingo, I was waiting for that final piece of information but will mark it now – Bassline Soup Jun 17 '20 at 16:46
  • The disable command in the drop in file seemed to work but now it seems to stop AP mode working altogether so I have commented it out. Any idea how to establish where to put that same command so it disables on boot but still allows it to work? – Bassline Soup Jul 03 '20 at 09:00
  • @BasslineSoup You edit the drop in file with `systemctl edit hostapd.service`. But there is no `disable` command in it. What do you mean? – Ingo Jul 03 '20 at 10:23
  • I edited hostapd.service to include `ExecStartPost=/usr/sbin/hostapd_cli disable` so that the Pi boots without AP enabled, but then `sudo systemctl restart hostapd.service` does not seem to bring the AP up enabled as it did before. I haven't dug into it deeply yet as someone is using the pi so just commented out the line in the drop in file and rebooted to get the AP to work for them, but thought it is probably something to do with the last sentence of your answer: that it might be too early for that disable command in the drop in. – Bassline Soup Jul 03 '20 at 15:32
  • I'm not sure if you can help with my [DNS issue] (https://raspberrypi.stackexchange.com/q/114401/120864) please? I think it is a resolved issue but don't know what to try without breaking what is working. Thanks – Bassline Soup Jul 17 '20 at 09:30
  • @BasslineSoup I see [you have answered it](https://raspberrypi.stackexchange.com/a/114409/79866). Does it solve the problem? – Ingo Jul 21 '20 at 17:44
  • Yes thanks, updated question – Bassline Soup Jul 22 '20 at 10:58
2

For anyone trying to do this, here is all of the info I have collected.

1. Setup Client and AP mode

Setup your pi using this great guide. Try just the client part in isolation first to see if that works and only then move on. Be sure to use a fresh install of Pi OS and specifically make sure you have not connected it to the wifi (using dhcpcd) as this can cause issues when you move forward. Fresh install and configuring via ssh is best. You can leave out the bridge section or do it if you want but as we'll see it works without.

2. Remove client credentials

Once you have the AP up and running, you can play with the client part (since you can connect to the AP and still control the pi). So, go back to wpa_supplicant-wlan0.conf and remove network={data} including the SSID and PSK within the braces. Might be good to reboot here and then the Pi will start without client connection.

3. Play with wpa_cli

To scan and connect to networks as a client, use wpa_cli -iwlan0 (no sudo). This runs wpa_cli in interactive mode on the correct interface. If you miss off the -iwlan0 it will not connect to the correct interface.

You can now scan and show scan_results. Now you can add_network which, if it is the first one you have added will be 0, but it will print the index back to you. Now if your network is 0 then you can set_network 0 ssid "MySSID" and also set_network 0 ask "MyPass123" being sure to use the correct quotes (Notes on Mac replaced the trailing quote with a curly one which can't be parsed).

Now you can enable_network 0 and it will attempt to connect. If the connection is successful, then you can save_config and this will save the credentials to wpa_supplicant-wlan0.conf, which you can check.

Now you can add a second network (e.g. phone hotspot) to see the behaviour with multiple networks in the same manner as above (but different network ID e.g. 1). When you enable_network 1 it will not actually connect, you need to select_network 1. This will disable all other networks which you don't really want so once you have selected network 1, you want to enable_network 0. This means that if the pi disconnects from one network, it will attempt to connect to the other enabled ones.

You can see a list of networks with list_network and remove_network if required. There's plenty of other commands that help will give you.

4. Playing with hostapd_cli

Now you have reconnected as a client, you can play with the AP without losing connectivity. Add to the hostapd.conf file the following two lines (you can do this in step 1 if you like). This will allow you to use hostapd_cli.

ctrl_interface=/var/run/hostapd
ctrl_interface_group=0

Also, if you don't want your AP to be available on boot, I don't, then you can add the following line to hostapd.service under the [Service] section

[Service]
...
...
...
ExecStartPost=/usr/sbin/hostapd_cli disable

Reboot to check if that worked

Now I am using three commands to manage the AP.

To disable at any time, you can run sudo hostapd_cli disable. This will not stop the hostapd service so will not affect the client. Note that if you did the step before and rebooted, it should be disabled from boot.

To alter the SSID, PSK or any other specifics of the AP, you can simply now edit hostapd.conf (or write a script to do so, I haven't yet had any success changing these credentials from hostapd_cli).

To start the AP (whether you've changed credentials or not) you can run sudo systemctl restart hostapd.service. Due to the dependencies between client and AP modes, this will also restart wpa/client mode so you will lose connectivity for a few seconds but then should regain both client and AP.

5. Bridge mode

I didn't actually do the bridge settings in the first guide I mentioned but for some reason it passes traffic between the virtual interfaces. This might be desirable but I want to be able to control it and apparently nftables (apt show nftables) is the way to go but I haven't had a chance to play with that yet.

I hope that helped someone.