0

We're using a forked version of pi-gen (https://github.com/RPi-Distro/pi-gen) to build custom RPi images. As part of the build, we're trying to set the RPi up as an Access point as WiFi router/repeater with additional WiFi-dongle (thanks @Ingo), and have added this step to one of our stages in RPi:

#!/bin/bash -e

# Disable classic networking
sudo systemctl mask networking.service dhcpcd.service
sudo mv /etc/network/interfaces /etc/network/interfaces~
sudo sed -i '1i resolvconf=NO' /etc/resolvconf.conf

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

# Configure wpa_supplicant for wlan0 as access point
sudo cat > /etc/wpa_supplicant/wpa_supplicant-wlan0.conf <<EOF
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="${AP_WPA_ESSID}"
    mode=2
    key_mgmt=WPA-PSK
    psk="${AP_WPA_PASSWORD}"
    frequency=2412
}
EOF

sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan0.conf
sudo systemctl disable wpa_supplicant.service
sudo systemctl enable wpa_supplicant@wlan0.service

# Configure wpa_supplicant for wlan1 as client
sudo cat > /etc/wpa_supplicant/wpa_supplicant-wlan1.conf <<EOF
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="${CLIENT_WPA_ESSID}"
    psk="${CLIENT_WPA_PASSWORD}"
}
EOF

sudo chmod 600 /etc/wpa_supplicant/wpa_supplicant-wlan1.conf
sudo systemctl enable wpa_supplicant@wlan1.service

env SYSTEMD_EDITOR=tee sudo -E systemctl edit --system wpa_supplicant@wlan1.service <<EOF
[Service]
ExecStartPre=/sbin/iptables -t nat -A POSTROUTING -o wlan1 -j MASQUERADE
ExecStopPost=-/sbin/iptables -t nat -D POSTROUTING -o wlan1 -j MASQUERADE
EOF

# Configure interfaces
sudo cat > /etc/systemd/network/08-wlan0.network <<EOF
[Match]
Name=wlan0
[Network]
Address=192.168.4.1/24
IPForward=yes
DHCPServer=yes
[DHCPServer]
DNS=1.1.1.1 8.8.8.8
EOF

sudo cat > /etc/systemd/network/12-wlan1.network <<EOF
[Match]
Name=wlan1
[Network]
DHCP=yes
EOF

When we run the new image, we're getting the following error during the boot:

[ TIME ] Timed out waiting for device /subsystem/net/devices/wlan1.
[DEPEND] Dependency failed for WPA … (interface-specific version).

What dependency are we missing?

UPDATE 1

Following the pi-gen convention, I'm now "installing" the systemd files:

#!/bin/bash -e

install -v -m 600 files/wpa_supplicant-wlan0.conf       "${ROOTFS_DIR}/etc/wpa_supplicant/"
install -v -m 600 files/wpa_supplicant-wlan1.conf       "${ROOTFS_DIR}/etc/wpa_supplicant/"

install -v -m 600 files/08-wlan0.network                "${ROOTFS_DIR}/etc/systemd/network/"
install -v -m 600 files/12-wlan1.network                "${ROOTFS_DIR}/etc/systemd/network/"

# Disable classic networking
on_chroot << EOF
    sudo systemctl mask networking.service dhcpcd.service
    sudo mv /etc/network/interfaces /etc/network/interfaces~
    sudo sed -i '1i resolvconf=NO' /etc/resolvconf.conf

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

    sudo systemctl disable wpa_supplicant.service
    sudo systemctl enable wpa_supplicant@wlan0.service
    sudo systemctl enable wpa_supplicant@wlan1.service
EOF

....but I'm not sure what to do with the systemctl edit steps.

UPDATE 2

Made the switch to using instructions in Access point as WiFi router/repeater, optional with bridge and have updated the pi-gen scripts as follows:

00-run.sh:

#!/bin/bash -e

install -v -m 644 files/hostapd.service                 "${ROOTFS_DIR}/etc/systemd/system/"

on_chroot << EOF
    systemctl unmask hostapd
    systemctl enable hostapd

    # Disable classic networking
    systemctl mask networking.service dhcpcd.service
    mv /etc/network/interfaces /etc/network/interfaces~
    sed -i '1i resolvconf=NO' /etc/resolvconf.conf

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

install -v -m 644 files/hostapd.conf                    "${ROOTFS_DIR}/etc/hostapd/"

on_chroot << EOF
    sed -i 's/^#DAEMON_CONF=.*$/DAEMON_CONF="\/etc\/hostapd\/hostapd.conf"/' /etc/default/hostapd
EOF

install -v -m 644 files/wpa_supplicant-wlan0.conf       "${ROOTFS_DIR}/etc/wpa_supplicant/"

on_chroot << EOF
    systemctl disable wpa_supplicant.service
    systemctl enable wpa_supplicant@wlan0.service
EOF

install -d                                              "${ROOTFS_DIR}/etc/systemd/system/wpa_supplicant@wlan0.service.d"
install -v -m 644 files/override.conf                   "${ROOTFS_DIR}/etc/systemd/system/wpa_supplicant@wlan0.service.d/"

install -v -m 644 files/08-wlan0.network                "${ROOTFS_DIR}/etc/systemd/network/"
install -v -m 644 files/12-ap0.network                  "${ROOTFS_DIR}/etc/systemd/network/"

files/hostapd.service:

[Unit]
Description=Advanced IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator
#After=network.target
Wants=wpa_supplicant@wlan0.service

[Service]
Type=forking
PIDFile=/run/hostapd.pid
Restart=on-failure
RestartSec=2
Environment=DAEMON_CONF=/etc/hostapd/hostapd.conf
EnvironmentFile=-/etc/default/hostapd
ExecStartPre=/sbin/iw dev wlan0 interface add ap0 type __ap
ExecStart=/usr/sbin/hostapd -B -P /run/hostapd.pid -B $DAEMON_OPTS ${DAEMON_CONF}
ExecStopPost=-/sbin/iw dev ap0 del

[Install]
WantedBy=multi-user.target

files/hostapd.conf:

interface=ap0
driver=nl80211
ssid=RPiWiFi
country_code=GB
hw_mode=g
channel=1
auth_algs=1
wpa=2
wpa_passphrase=pass1234
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

files/wpa_supplicant-wlan0.conf:

country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="OfficeWiFi"
    psk="1234pass"
    key_mgmt=WPA-PSK
}

files/override.conf:

[Unit]
BindsTo=hostapd.service
After=hostapd.service

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

files/08-wlan0.network:

[Match]
Name=wlan0
[Network]
IPForward=yes
DHCP=yes

files/12-ap0.network:

[Match]
Name=ap0
[Network]
Address=192.168.4.1/24
DHCPServer=yes
[DHCPServer]
DNS=1.1.1.1 8.8.8.8

...but we're getting the following error with wpa_supplicant@wlan0.service

Nov 28 12:52:10 raspberrypi wpa_supplicant[350]: Could not set interface wlan0 flags (UP): Name not unique on network
Nov 28 12:52:10 raspberrypi wpa_supplicant[350]: nl80211: Could not set interface 'wlan0' UP
Nov 28 12:52:10 raspberrypi wpa_supplicant[350]: nl80211: deinit ifname=wlan0 disabled_11b_rates=0
Nov 28 12:52:10 raspberrypi wpa_supplicant[350]: Could not set interface wlan0 flags (UP): Name not unique on network
Nov 28 12:52:10 raspberrypi wpa_supplicant[350]: WEXT: Could not set interface 'wlan0' UP
Nov 28 12:52:10 raspberrypi wpa_supplicant[350]: wlan0: Failed to initialize driver interface
Nov 28 12:52:10 raspberrypi systemd[1]: wpa_supplicant@wlan0.service: Main process exited, code=exited, status=255/EXCEPTION
Nov 28 12:52:10 raspberrypi systemd[1]: wpa_supplicant@wlan0.service: Failed with result 'exit-code'.
Nov 28 12:52:10 raspberrypi systemd[1]: Failed to start WPA supplicant daemon (interface-specific version).

UPDATE 3

Had another chance to take a look at this. The above error appears to be because both the wlan0 and ap0 network interfaces have the same MAC address:

$ ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 74:da:38:c9:b1:15 brd ff:ff:ff:ff:ff:ff
3: ap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
    link/ether 74:da:38:c9:b1:15 brd ff:ff:ff:ff:ff:ff

Can I set the hwaddress for each network interface ahead of time? Or is it an issue with the USB/WiFi dongle? What USB/WiFi dongle is best for this setup?

| improve this question | | | | |
2

The problem is that your script does not run with root rights. You took the commands as given in the tutorial and where needed you prepend them with sudo. This does not work with redirection > and << because redirection then is related to sudo and not to cat as intended. If you look at the tutorial you will find as very first command

rpi ~$ sudo -Es

This opens a shell running with root rights. All following commands on the command line now are executed as root. Check with whoami.

The solution is to remove all sudo calls within the script and run the script itself with sudo, for example:

rpi ~$ sudo setup-ap.sh

If this is not possible then you have to ensure that all commands within the script that need root rights, run in its own environment. There are some technics to ensure it. You can use sudo bash -c '<commands>', e.g.:

rpi ~$ sudo bash -c 'echo "hello world" > out.tst'

or practical:

rpi ~$ sudo bash -c 'cat > /etc/systemd/network/12-wlan1.network <<EOF
[Match]
Name=wlan1
[Network]
DHCP=yes
EOF'

Have attention to single and double quotes with nesting. They have different meanings in bash. And please note that every command opens a separate shell with complete environment so for performance it is much better to execute the whole script as root.

Using systemctl edit as in

rpi ~# systemctl edit wpa_supplicant@wlan1.service

will create a so called drop in file that extends the original service. It is documented in man systemd.unit with Example 2. Overriding vendor settings at the end. The example creates the drop in file direct without using systemctl edit. You can just do it the same way with scripting. If unsure about the additional directories and files to create you can just create them one time with systemctl edit and show what it has done with

rpi ~$ systemctl cat wpa_supplicant@wlan1.service
| improve this answer | | | | |
  • Thanks for the quick response! ...really appreciate it. pi-gen has a way to copy/install systemd files (github.com/RPi-Distro/pi-gen/blob/master/stage2/02-net-tweaks/…) that should help with the permissions issue. I've updated my script to use that approach, but I'm not sure what to do with the systemctl edit steps. Can the contents of that EOF be included in a file that I can install using pi-gen? – timborden Nov 6 '19 at 16:16
  • @timborden I have updated the answer at the end about scripting systemctl edit. About your update: I don't know pi-gen but I see you are still using sudo? Is it really needed within on_chroot? – Ingo Nov 6 '19 at 17:04
  • Thanks again for taking the time. I've been through a few iterations with the pi-gen scripts and are very close (the access point is broadcasting, but the RPi is not connecting to the office WiFi). I've updated the question, if you've got time to take a look, it would be greatly appreciated. – timborden Nov 28 '19 at 13:53
  • I had a look at it but cannot say much because I don't know pi-gen and its installation routines. At a first glance it doesn't look bad but I don't oversee its dynamic: when is what installed and started. The setup Access point as WiFi router/repeater, optional with bridge have to meet a very important condition: starting the services for ap0, hostapd and wpa_supplicant strict in this order as described in section "♦ Details". Typical are conflicts with interfaces if it isn't given. You should check the starting order. – Ingo Nov 28 '19 at 19:09
  • Thanks for taking a look, appreciate it. I'll double check the order. – timborden Nov 29 '19 at 16:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.