.
This commit is contained in:
392
ap.sh
Normal file
392
ap.sh
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# The script configures simultaneous AP and Managed Mode Wifi on Raspberry Pi
|
||||||
|
# Distribution Raspbian Buster
|
||||||
|
# works on:
|
||||||
|
# -Raspberry Pi Zero W
|
||||||
|
# -Raspberry Pi 3 B+
|
||||||
|
# -Raspberry Pi 3 A+
|
||||||
|
# Licence: GPLv3
|
||||||
|
# Author: Mickael Lehoux <mickael.lehoux@gmail.com>
|
||||||
|
# Repository: https://github.com/MkLHX/AP_STA_RPI_SAME_WIFI_CHIP
|
||||||
|
# Special thanks to: https://github.com/lukicdarkoo/rpi-wifi
|
||||||
|
|
||||||
|
# set -exv
|
||||||
|
|
||||||
|
# Error management
|
||||||
|
set -o errexit
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
|
||||||
|
DEFAULT='\033[0;39m'
|
||||||
|
WHITE='\033[0;02m'
|
||||||
|
RASPBERRY='\033[0;35m'
|
||||||
|
GREEN='\033[1;32m'
|
||||||
|
RED='\033[1;31m'
|
||||||
|
|
||||||
|
_welcome() {
|
||||||
|
VERSION="1.7.2"
|
||||||
|
echo -e "${RASPBERRY}\n"
|
||||||
|
echo -e " "
|
||||||
|
echo -e " /888888 /8888888 /888888 /88888888 /888888 "
|
||||||
|
echo -e " /88__ 88| 88__ 88 /88 /88__ 88|__ 88__//88__ 88"
|
||||||
|
echo -e "| 88 \ 88| 88 \ 88 | 88 | 88 \__/ | 88 | 88 \ 88"
|
||||||
|
echo -e "| 88888888| 8888888/ /88888888 | 888888 | 88 | 88888888"
|
||||||
|
echo -e "| 88__ 88| 88____/ |__ 88__/ \____ 88 | 88 | 88__ 88"
|
||||||
|
echo -e "| 88 | 88| 88 | 88 /88 \ 88 | 88 | 88 | 88"
|
||||||
|
echo -e "| 88 | 88| 88 |__/ | 888888/ | 88 | 88 | 88"
|
||||||
|
echo -e "|__/ |__/|__/ \______/ |__/ |__/ |__/"
|
||||||
|
echo -e " "
|
||||||
|
echo -e " version ${VERSION} "
|
||||||
|
echo -e " By https://github.com/MkLHX "
|
||||||
|
echo -e "${GREEN} "
|
||||||
|
echo -e "Manage AP + STA modes on Raspberry Pi with the same wifi chip\n\n "
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger() {
|
||||||
|
echo -e "${GREEN}"
|
||||||
|
echo "${1}"
|
||||||
|
echo -e "${DEFAULT}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_usage() {
|
||||||
|
cat 1>&2 <<EOF
|
||||||
|
Configures simultaneous AP and Managed Mode Wifi on Raspberry Pi
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
ap_sta_config.sh --ap <ap_ssid> [<ap_password>] --client <client_password> [<client_password>] --country <iso_3166_country_code>
|
||||||
|
|
||||||
|
# configure AP + STA
|
||||||
|
ap_sta_config.sh --ap ap_ssid ap_passphrases --client client_ssid client_passphrase --country FR
|
||||||
|
|
||||||
|
# configure AP + STA and change the wifi mode
|
||||||
|
ap_sta_config.sh --ap ap_ssid ap_passphrases --client client_ssid client_passphrase --country FR --hwmode b
|
||||||
|
|
||||||
|
# update the AP configuration
|
||||||
|
ap_sta_config.sh --ap ap_ssid ap_passphrases --ap-only
|
||||||
|
|
||||||
|
# update the STA (client) configuration
|
||||||
|
ap_sta_config.sh --client client_ssid client_passphrase --country FR --sta-only
|
||||||
|
|
||||||
|
# logs are written in /var/log/ap_sta_wifi folder
|
||||||
|
|
||||||
|
PARAMETERS:
|
||||||
|
-a, --ap AP SSID & password
|
||||||
|
-c, --client Client SSID & password
|
||||||
|
-i, --ip AP IP (by default ip pattern 192.168.10.x)
|
||||||
|
-cy, --country ISO3166 Country Code (by default FR)
|
||||||
|
-hw, --hwmode Mode Wi-Fi a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g (by default g)
|
||||||
|
|
||||||
|
FLAGS:
|
||||||
|
-ao, --ap-only Set only AP
|
||||||
|
-so, --sta-only Set only STA
|
||||||
|
-n, --no-internet Disable IP forwarding
|
||||||
|
-h, --help Show this help
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
POSITIONAL=()
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
key="$1"
|
||||||
|
|
||||||
|
case $key in
|
||||||
|
-c | --client)
|
||||||
|
CLIENT_SSID="$2"
|
||||||
|
CLIENT_PASSPHRASE="$3"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-a | --ap)
|
||||||
|
AP_SSID="$2"
|
||||||
|
AP_PASSPHRASE="$3"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-i | --ip)
|
||||||
|
ARG_AP_IP="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-cy | --country)
|
||||||
|
ARG_COUNTRY_CODE="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-hw | --hwmode)
|
||||||
|
ARG_WIFI_MODE="$2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-n | --no-internet)
|
||||||
|
NO_INTERNET="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-ao | --ap-only)
|
||||||
|
AP_ONLY="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-so | --sta-only)
|
||||||
|
STA_ONLY="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h | --help)
|
||||||
|
_usage
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
POSITIONAL+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
set -- "${POSITIONAL[@]}"
|
||||||
|
|
||||||
|
if [ $(id -u) != 0 ]; then
|
||||||
|
echo -e "${RED}"
|
||||||
|
echo "You need to be root to run this script! Please run 'sudo bash $0'"
|
||||||
|
echo -e "${DEFAULT}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check if crontabs are initialized
|
||||||
|
if [[ 1 -eq $(crontab -l | grep -cF "no crontab for root") ]]; then
|
||||||
|
echo -e ${RED}
|
||||||
|
echo "this script need to use crontab."
|
||||||
|
echo "you have to initialize and configure crontabs before run this script!"
|
||||||
|
echo "run 'sudo crontab -e'"
|
||||||
|
echo "select EDITOR nano or whatever"
|
||||||
|
echo "edit crontab by adding '# a comment line' or whatever"
|
||||||
|
echo "save and exit 'ctrl + s' & 'crtl + x'"
|
||||||
|
echo "restart the script 'sudo bash $0'"
|
||||||
|
echo -e "${DEFAULT}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
(test -v AP_SSID && test -v CLIENT_SSID && test -v ARG_COUNTRY_CODE) || (test -v AP_SSID && test -v AP_ONLY) || (test -v CLIENT_SSID && test -v ARG_COUNTRY_CODE && test -v STA_ONLY) || _usage
|
||||||
|
|
||||||
|
WIFI_MODE=${ARG_WIFI_MODE:-'g'}
|
||||||
|
COUNTRY_CODE=${ARG_COUNTRY_CODE:-'FR'}
|
||||||
|
AP_IP=${ARG_AP_IP:-'192.168.10.1'}
|
||||||
|
AP_IP_BEGIN=$(echo "${AP_IP}" | sed -e 's/\.[0-9]\{1,3\}$//g')
|
||||||
|
MAC_ADDRESS="$(cat /sys/class/net/wlan0/address)"
|
||||||
|
|
||||||
|
if ! test -v AP_ONLY; then
|
||||||
|
AP_ONLY="false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! test -v STA_ONLY; then
|
||||||
|
STA_ONLY="false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# welcome cli user
|
||||||
|
_welcome
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}" && test true == "${AP_ONLY}"; then
|
||||||
|
# Install dependencies
|
||||||
|
_logger "check if dependencies needed"
|
||||||
|
|
||||||
|
# keep order of dependencies installation
|
||||||
|
if [[ $(dpkg -l | grep -c cron) == 0 ]]; then
|
||||||
|
apt-get -y update
|
||||||
|
apt-get -y install cron
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $(dpkg -l | grep -c dhcpcd) == 0 ]]; then
|
||||||
|
apt-get -y update
|
||||||
|
apt-get -y install dhcpcd
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $(dpkg -l | grep -c hostapd) == 0 ]]; then
|
||||||
|
apt-get -y update
|
||||||
|
apt-get -y install hostapd
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $(dpkg -l | grep -c dnsmasq) == 0 ]]; then
|
||||||
|
apt-get -y update
|
||||||
|
apt-get -y install dnsmasq
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}"; then
|
||||||
|
# Populate `/etc/udev/rules.d/70-persistent-net.rules`
|
||||||
|
_logger "Populate /etc/udev/rules.d/70-persistent-net.rules"
|
||||||
|
bash -c 'cat > /etc/udev/rules.d/70-persistent-net.rules' <<EOF
|
||||||
|
SUBSYSTEM=="ieee80211", ACTION=="add|change", ATTR{macaddress}=="${MAC_ADDRESS}", KERNEL=="phy0", \
|
||||||
|
RUN+="/sbin/iw phy phy0 interface add ap0 type __ap", \
|
||||||
|
RUN+="/bin/ip link set ap0 address ${MAC_ADDRESS}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}"; then
|
||||||
|
# Populate `/etc/dnsmasq.conf`
|
||||||
|
_logger "Populate /etc/dnsmasq.conf"
|
||||||
|
bash -c 'cat > /etc/dnsmasq.conf' <<EOF
|
||||||
|
interface=lo,ap0
|
||||||
|
no-dhcp-interface=lo,wlan0
|
||||||
|
bind-interfaces
|
||||||
|
server=8.8.8.8
|
||||||
|
domain-needed
|
||||||
|
bogus-priv
|
||||||
|
dhcp-range=${AP_IP_BEGIN}.50,${AP_IP_BEGIN}.150,12h
|
||||||
|
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}"; then
|
||||||
|
# Populate `/etc/hostapd/hostapd.conf`
|
||||||
|
_logger "Populate /etc/hostapd/hostapd.conf"
|
||||||
|
bash -c 'cat > /etc/hostapd/hostapd.conf' <<EOF
|
||||||
|
ctrl_interface=/var/run/hostapd
|
||||||
|
ctrl_interface_group=0
|
||||||
|
interface=ap0
|
||||||
|
driver=nl80211
|
||||||
|
ssid=${AP_SSID}
|
||||||
|
hw_mode=${WIFI_MODE}
|
||||||
|
channel=11
|
||||||
|
wmm_enabled=0
|
||||||
|
macaddr_acl=0
|
||||||
|
auth_algs=1
|
||||||
|
wpa=2PASSPHRASE
|
||||||
|
$([ $AP_PASSPHRASE ] && echo "wpa_passphrase=${AP_PASSPHRASE}")
|
||||||
|
wpa_key_mgmt=WPA-PSK
|
||||||
|
wpa_pairwise=TKIP CCMP
|
||||||
|
rsn_pairwise=CCMP
|
||||||
|
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}"; then
|
||||||
|
# Populate `/etc/default/hostapd`
|
||||||
|
_logger "Populate /etc/default/hostapd"
|
||||||
|
bash -c 'cat > /etc/default/hostapd' <<EOF
|
||||||
|
DAEMON_CONF="/etc/hostapd/hostapd.conf"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test true != "${AP_ONLY}"; then
|
||||||
|
# Populate `/etc/wpa_supplicant/wpa_supplicant.conf`
|
||||||
|
_logger "Populate /etc/wpa_supplicant/wpa_supplicant.conf"
|
||||||
|
bash -c 'cat > /etc/wpa_supplicant/wpa_supplicant.conf' <<EOF
|
||||||
|
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
|
||||||
|
update_config=1
|
||||||
|
country=${COUNTRY_CODE}
|
||||||
|
network={
|
||||||
|
ssid="${CLIENT_SSID}"
|
||||||
|
$([ $CLIENT_PASSPHRASE ] && echo "psk=\"${CLIENT_PASSPHRASE}\"")
|
||||||
|
id_str="AP1"
|
||||||
|
scan_ssid=1
|
||||||
|
}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Populate `/etc/network/interfaces`
|
||||||
|
# TODO manage eth0 interface
|
||||||
|
# if current device is model B+ with ethernet port
|
||||||
|
# auto eth0
|
||||||
|
# allow-hotplug eth0
|
||||||
|
# iface eth0 inet manual
|
||||||
|
#
|
||||||
|
_logger "Populate /etc/network/interfaces"
|
||||||
|
bash -c 'cat > /etc/network/interfaces' <<EOF
|
||||||
|
source-directory /etc/network/interfaces.d
|
||||||
|
|
||||||
|
auto lo
|
||||||
|
auto ap0
|
||||||
|
auto wlan0
|
||||||
|
|
||||||
|
iface lo inet loopback
|
||||||
|
|
||||||
|
allow-hotplug ap0
|
||||||
|
iface ap0 inet static
|
||||||
|
address ${AP_IP}
|
||||||
|
netmask 255.255.255.0
|
||||||
|
# network ${AP_IP_BEGIN}.0
|
||||||
|
# broadcast ${AP_IP_BEGIN}.255
|
||||||
|
# gateway ${AP_IP}
|
||||||
|
hostapd /etc/hostapd/hostapd.conf
|
||||||
|
|
||||||
|
allow-hotplug wlan0
|
||||||
|
iface wlan0 inet manual
|
||||||
|
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
|
||||||
|
iface AP1 inet dhcp
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}"; then
|
||||||
|
# Populate `/bin/manage-ap0-iface.sh`
|
||||||
|
_logger "Populate /bin/manage-ap0-iface.sh"
|
||||||
|
bash -c 'cat > /bin/manage-ap0-iface.sh' <<EOF
|
||||||
|
#!/bin/bash
|
||||||
|
# check if hostapd service succes to start or not
|
||||||
|
# in our case, it cannot start when /var/run/hostapd/ap0 exist
|
||||||
|
# so we have to delete it
|
||||||
|
echo 'Check if hostapd.service is hang cause ap0 exist...'
|
||||||
|
hostapd_is_running=\$(service hostapd status | grep -c "Active: active (running)")
|
||||||
|
if test 1 -ne "\${hostapd_is_running}"; then
|
||||||
|
rm -rf /var/run/hostapd/ap0 | echo "ap0 interface does not exist, the faillure is elsewhere"
|
||||||
|
fi
|
||||||
|
|
||||||
|
EOF
|
||||||
|
chmod +x /bin/manage-ap0-iface.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}"; then
|
||||||
|
# Populate `/bin/rpi-wifi.sh`
|
||||||
|
_logger "Populate /bin/rpi-wifi.sh"
|
||||||
|
bash -c 'cat > /bin/rpi-wifi.sh' <<EOF
|
||||||
|
#!/bin/bash
|
||||||
|
echo 'Starting Wifi AP and STA client...'
|
||||||
|
ifdown --force wlan0
|
||||||
|
ifdown --force ap0
|
||||||
|
ifup ap0
|
||||||
|
ifup wlan0
|
||||||
|
$([ "${NO_INTERNET-}" != "true" ] && echo "sysctl -w net.ipv4.ip_forward=1")
|
||||||
|
$([ "${NO_INTERNET-}" != "true" ] && echo "iptables -t nat -A POSTROUTING -s ${AP_IP_BEGIN}.0/24 ! -d ${AP_IP_BEGIN}.0/24 -j MASQUERADE")
|
||||||
|
$([ "${NO_INTERNET-}" != "true" ] && echo "systemctl restart dnsmasq")
|
||||||
|
echo 'WPA Supplicant reconfigure in 5sec...'
|
||||||
|
sleep 5
|
||||||
|
wpa_cli -i wlan0 reconfigure
|
||||||
|
|
||||||
|
EOF
|
||||||
|
chmod +x /bin/rpi-wifi.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}"; then
|
||||||
|
# unmask and enable dnsmasq.service / hostapd.service
|
||||||
|
_logger "Unmask and enable dnsmasq.service / hostapd.service"
|
||||||
|
systemctl unmask dnsmasq.service hostapd.service
|
||||||
|
systemctl enable dnsmasq.service hostapd.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create ap sta log folder
|
||||||
|
mkdir -p /var/log/ap_sta_wifi
|
||||||
|
touch /var/log/ap_sta_wifi/ap0_mgnt.log
|
||||||
|
touch /var/log/ap_sta_wifi/on_boot.log
|
||||||
|
|
||||||
|
# Finish
|
||||||
|
if test true == "${STA_ONLY}"; then
|
||||||
|
wpa_cli -i wlan0 reconfigure
|
||||||
|
sleep 15
|
||||||
|
ifconfig wlan0 down # better way for docker
|
||||||
|
sleep 2
|
||||||
|
ifconfig wlan0 up # better way for docker
|
||||||
|
_logger "STA configuration is finished!"
|
||||||
|
elif test true == "${AP_ONLY}"; then
|
||||||
|
/bin/bash /bin/rpi-wifi.sh
|
||||||
|
_logger "AP configuration is finished!"
|
||||||
|
elif test true != "${STA_ONLY}" && test true != "${AP_ONLY}"; then
|
||||||
|
_logger "AP + STA configurations are finished!"
|
||||||
|
_logger "You need to reboot Raspbery Pi to apply changes.."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test true != "${STA_ONLY}"; then
|
||||||
|
_logger "Wait during wlan0 reconnecting to internet..."
|
||||||
|
sleep 15
|
||||||
|
curl https://raw.githubusercontent.com/MkLHX/AP_STA_RPI_SAME_WIFI_CHIP/master/ap_sta_cron.sh | bash -s --
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user