From 2fe705507f4241c50bff882e31b0dff6121094e0 Mon Sep 17 00:00:00 2001 From: Alvin Schiller <103769832+AlvinSchiller@users.noreply.github.com> Date: Sun, 4 Feb 2024 20:37:32 +0100 Subject: [PATCH] NetworkManager Support (#2218) * reworked autohotspot configuration option * updated autohotspot creation (copied changes from v2) * fix placeholder prefix/suffix (%%) * moved files in subdir for dhcpcd * renamed setup_autohotspot file * added switch for network settings * added autohotspot based on NetworkManager * update function names * fixed duplicate variables * fix var check * handle CI run for autohotspot setup * changed network management check for ci * fixed timer service name * renamed script. delete obsolete file * fix syntax * fix timer service unit definition * move is is_service_enabled to helper class * extracted konstant and fixed formatting * fix indentation * added shebang again * some refactorings in autohotspot script * fix checks * fix for local vars and arrays. refactor nw_profiles. * refactored var value and log output * refactor device and ssid checks * refactore force_hotspot option * refactor is_active_ap check and bugfixes * update log output * made timer reenablement configurable * phoniebox header added * moved check to helper. removed obsolete code * removed ip configuration. changed ip * add note for static ip conf with autohotspot * harmonize logging and opts * changed dhcpcd timer from cron to systemd. add seperate daemon service for wpa-supplicant handling * fix wifi after restart if autohot spot is deactivated * add hostname to default hotspot ssid * updated autohotspot docs * fix static ip for NetworkManager. fix ipv6 disablement * fix boot file paths * some fixes * pull config file backup to helpers * combine service is-enabled calls * update network related docs * Update autohotspot.md Aligned some language and typos * Update installation.md Aligning wording and removing typos --------- Co-authored-by: pabera <1260686+pabera@users.noreply.github.com> --- ci/ci-debian.Dockerfile | 4 +- ci/installation/run_install_common.sh | 2 +- ci/installation/run_install_faststartup.sh | 2 + ci/installation/run_install_libzmq_local.sh | 1 + .../run_install_webapp_download.sh | 2 + ci/installation/run_install_webapp_local.sh | 1 + documentation/builders/autohotspot.md | 114 ++---- documentation/builders/installation.md | 15 +- installation/includes/00_constants.sh | 3 +- installation/includes/01_default_config.sh | 6 +- installation/includes/02_helpers.sh | 93 ++++- installation/routines/customize_options.sh | 124 ++++-- installation/routines/optimize_boot_time.sh | 140 ++++--- installation/routines/set_raspi_config.sh | 12 +- installation/routines/setup_autohotspot.sh | 117 ++---- .../setup_autohotspot_NetworkManager.sh | 98 +++++ .../routines/setup_autohotspot_dhcpcd.sh | 185 +++++++++ .../autohotspot/NetworkManager/autohotspot | 353 ++++++++++++++++++ .../NetworkManager/autohotspot.service | 11 + .../NetworkManager/autohotspot.timer | 10 + resources/autohotspot/autohotspot | 193 ---------- resources/autohotspot/autohotspot.service | 11 - resources/autohotspot/autohotspot.timer | 3 - resources/autohotspot/dhcpcd/autohotspot | 228 +++++++++++ .../dhcpcd/autohotspot-daemon.service | 10 + .../autohotspot/dhcpcd/autohotspot.service | 11 + .../autohotspot/dhcpcd/autohotspot.timer | 10 + resources/autohotspot/dhcpcd/dnsmasq.conf | 7 + resources/autohotspot/dhcpcd/hostapd | 20 + .../autohotspot/{ => dhcpcd}/hostapd.conf | 8 +- src/cli_client/pbc.c | 32 +- .../components/hostif/linux/__init__.py | 52 ++- 32 files changed, 1327 insertions(+), 551 deletions(-) create mode 100644 installation/routines/setup_autohotspot_NetworkManager.sh create mode 100644 installation/routines/setup_autohotspot_dhcpcd.sh create mode 100644 resources/autohotspot/NetworkManager/autohotspot create mode 100644 resources/autohotspot/NetworkManager/autohotspot.service create mode 100644 resources/autohotspot/NetworkManager/autohotspot.timer delete mode 100644 resources/autohotspot/autohotspot delete mode 100644 resources/autohotspot/autohotspot.service delete mode 100644 resources/autohotspot/autohotspot.timer create mode 100644 resources/autohotspot/dhcpcd/autohotspot create mode 100644 resources/autohotspot/dhcpcd/autohotspot-daemon.service create mode 100644 resources/autohotspot/dhcpcd/autohotspot.service create mode 100644 resources/autohotspot/dhcpcd/autohotspot.timer create mode 100644 resources/autohotspot/dhcpcd/dnsmasq.conf create mode 100644 resources/autohotspot/dhcpcd/hostapd rename resources/autohotspot/{ => dhcpcd}/hostapd.conf (66%) diff --git a/ci/ci-debian.Dockerfile b/ci/ci-debian.Dockerfile index 5228d83d5..d4348ecdf 100644 --- a/ci/ci-debian.Dockerfile +++ b/ci/ci-debian.Dockerfile @@ -8,8 +8,8 @@ ENV TERM=xterm DEBIAN_FRONTEND=noninteractive ENV CI_RUNNING=true # create RPi configs to test installation -RUN touch /boot/config.txt -RUN echo "logo.nologo" > /boot/cmdline.txt +RUN mkdir -p /boot && touch /boot/config.txt && echo "logo.nologo" > /boot/cmdline.txt +RUN mkdir -p /boot/firmware && touch /boot/firmware/config.txt && echo "logo.nologo" > /boot/firmware/cmdline.txt RUN echo "--- install packages (1) ---" \ && apt-get update \ diff --git a/ci/installation/run_install_common.sh b/ci/installation/run_install_common.sh index b8c641580..0b73ae791 100644 --- a/ci/installation/run_install_common.sh +++ b/ci/installation/run_install_common.sh @@ -17,7 +17,7 @@ export ENABLE_WEBAPP_PROD_DOWNLOAD=true # n - use static ip # n - deactivate ipv6 # y - setup autohotspot -# n - use custom password +# n - change default configuration # n - deactivate bluetooth # n - disable on-chip audio # - - mpd overwrite config (only with existing installation) diff --git a/ci/installation/run_install_faststartup.sh b/ci/installation/run_install_faststartup.sh index 134aeca71..2a98a1869 100644 --- a/ci/installation/run_install_faststartup.sh +++ b/ci/installation/run_install_faststartup.sh @@ -11,11 +11,13 @@ SCRIPT_DIR="$(dirname "$SOURCE")" LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" + # Run installation (in interactive mode) # y - start setup # y - use static ip # y - deactivate ipv6 # n - setup autohotspot +# - - change default configuration (only with autohotspot = y) # y - deactivate bluetooth # y - disable on-chip audio # - - mpd overwrite config (only with existing installation) diff --git a/ci/installation/run_install_libzmq_local.sh b/ci/installation/run_install_libzmq_local.sh index 335cb24a1..7ce6e14ac 100644 --- a/ci/installation/run_install_libzmq_local.sh +++ b/ci/installation/run_install_libzmq_local.sh @@ -17,6 +17,7 @@ export BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE=true # n - use static ip # n - deactivate ipv6 # n - setup autohotspot +# - - change default configuration (only with autohotspot = y) # n - deactivate bluetooth # n - disable on-chip audio # - - mpd overwrite config (only with existing installation) diff --git a/ci/installation/run_install_webapp_download.sh b/ci/installation/run_install_webapp_download.sh index ded27ec54..ee72588ef 100644 --- a/ci/installation/run_install_webapp_download.sh +++ b/ci/installation/run_install_webapp_download.sh @@ -11,11 +11,13 @@ SCRIPT_DIR="$(dirname "$SOURCE")" LOCAL_INSTALL_SCRIPT_PATH="${INSTALL_SCRIPT_PATH:-${SCRIPT_DIR}/../../installation}" LOCAL_INSTALL_SCRIPT_PATH="${LOCAL_INSTALL_SCRIPT_PATH%/}" + # Run installation (in interactive mode) # y - start setup # n - use static ip # n - deactivate ipv6 # n - setup autohotspot +# - - change default configuration (only with autohotspot = y) # n - deactivate bluetooth # n - disable on-chip audio # - - mpd overwrite config (only with existing installation) diff --git a/ci/installation/run_install_webapp_local.sh b/ci/installation/run_install_webapp_local.sh index 7af16df3a..bd7ce8def 100644 --- a/ci/installation/run_install_webapp_local.sh +++ b/ci/installation/run_install_webapp_local.sh @@ -17,6 +17,7 @@ export ENABLE_WEBAPP_PROD_DOWNLOAD=false # n - use static ip # n - deactivate ipv6 # n - setup autohotspot +# - - change default configuration (only with autohotspot = y) # n - deactivate bluetooth # n - disable on-chip audio # - - mpd overwrite config (only with existing installation) diff --git a/documentation/builders/autohotspot.md b/documentation/builders/autohotspot.md index ecf996f81..5a62a37ca 100644 --- a/documentation/builders/autohotspot.md +++ b/documentation/builders/autohotspot.md @@ -1,107 +1,63 @@ # Auto-Hotspot -The Auto-Hotspot function allows the Jukebox to switch between its -connection between a known WiFi and an automatically generated hotspot -so that you can still access via SSH or Web App. +The Auto-Hotspot function enables the Jukebox to switch its connection between a known WiFi network and an automatically generated hotspot, allowing access via SSH or Web App. > [!IMPORTANT] -> Please configure the WiFi connection to your home access point before enabling these feature! - -To create a hotspot and allow clients to connect -[hostapd](http://w1.fi/hostapd/) and [dnsmasq](https://thekelleys.org.uk/dnsmasq/doc.html). +> Please configure the WiFi connection to your home access point before enabling this feature! ## How to connect -When the Jukebox is not able to connect to a known WiFi it will create a -hotspot named `Phoniebox_Hotspot`. You will be able to connect to this -hotspot using the given password in the installation or the default -password: `PlayItLoud!` - -### Web App - -After connecting to the `Phoniebox_Hotspot` you are able to connect to -the Web App accessing the website [10.0.0.5](http://10.0.0.5/). +When the Jukebox cannot connect to a known WiFi, it will automatically create a hotspot. +You can connect to this hotspot using the password set during installation. +Afterwards, you can access the Web App or connect via SSH as before, using the IP from the configuration. -### ssh - -After connecting to the `Phoniebox_Hotspot` you are able to connect via -ssh to your Jukebox - -``` bash -ssh @10.0.0.5 -``` - -## Changing basic configuration of the hotspot - -The whole hotspot configuration can be found at -`/etc/hostapd/hostapd.conf`. - -The following parameters are relevant: - -- `ssid` for the displayed hotspot name -- `wpa_passphrase` for the password of the hotspot -- `country_code` the country you are currently in - -``` bash -$ cat /etc/hostapd/hostapd.conf - -#2.4GHz setup wifi 80211 b,g,n -interface=wlan0 -driver=nl80211 -ssid=Phoniebox_Hotspot -hw_mode=g -channel=8 -wmm_enabled=0 -macaddr_acl=0 -auth_algs=1 -ignore_broadcast_ssid=0 -wpa=2 -wpa_passphrase==PlayItLoud! -wpa_key_mgmt=WPA-PSK -wpa_pairwise=CCMP TKIP -rsn_pairwise=CCMP - -#80211n - Change GB to your WiFi country code -country_code=DE -ieee80211n=1 -ieee80211d=1 +The default configuration is +``` text +* SSID : Phoniebox_Hotspot_ +* Password : PlayItLoud! +* WiFi Country Code : DE +* IP : 10.0.0.1 ``` ## Disabling automatism -Auto-Hotspot can be enabled or disabled using the Web App. +Auto-Hotspot can be enabled or disabled using the Web App or RPC Commands. + +> [!NOTE] +> Disabling the Auto-Hotspot will run the WiFi check again and maintain the last connection state until reboot. > [!IMPORTANT] -> Disabling or enabling will keep the last state. +> If you disable this feature, you will lose access to the Jukebox if you are not near a known WiFi after reboot! ## Troubleshooting -### Phoniebox is not connecting to the known WiFi - -The script will fall back to the hotspot so you still have some type of -connection. - -Check your password in `/etc/wpa_supplicant/wpa_supplicant.conf`. - ### AutoHotspot functionality is not working -You can check the output of the script by running the following script: +Check the `autohotspot.service` status +``` bash +sudo systemctl status autohotspot.service +``` +and logs ``` bash -$ sudo /usr/bin/autohotspot +sudo journalctl -u autohotspot.service -n 50 ``` -### You need to add a new wifi network to the Raspberry Pi +### Jukebox is not connecting to the known WiFi + +The script will fall back to the hotspot, ensuring you still have some type of connection. + +Check your WiFi configuration. -Because it is in Auto-Hotspot mode, you won\'t be able to scan for new -wifi signals. +### You need to add a new WiFi network to the Raspberry Pi -You will need to add a new network to -`/etc/wpa_supplicant/wpa_supplicant.conf` manually. Enter the following -details replacing mySSID and myPassword with your details. If your WiFi -has a hidden SSID then include the line `scan_ssid=1`. +#### Using the command line +Connect to the hotspot and open a terminal. Use the [raspi-config](https://www.raspberrypi.com/documentation/computers/configuration.html#wireless-lan) tool to add the new WiFi. ## Resources -[Raspberry Pi - Auto WiFi Hotspot Switch - Direct -Connection](https://www.raspberryconnect.com/projects/65-raspberrypi-hotspot-accesspoints/158-raspberry-pi-auto-wifi-hotspot-switch-direct-connection) +* [Raspberry Connect - Auto WiFi Hotspot Switch](https://www.raspberryconnect.com/projects/65-raspberrypi-hotspot-accesspoints/158-raspberry-pi-auto-wifi-hotspot-switch-direct-connection) +* [Raspberry Pi - Configuring networking](https://www.raspberrypi.com/documentation/computers/configuration.html#using-the-command-line) +* [dhcpcd / wpa_supplicant]() + * [hostapd](http://w1.fi/hostapd/) + * [dnsmasq](https://thekelleys.org.uk/dnsmasq/doc.html) diff --git a/documentation/builders/installation.md b/documentation/builders/installation.md index 1d4b18470..7cd321b7a 100644 --- a/documentation/builders/installation.md +++ b/documentation/builders/installation.md @@ -11,7 +11,6 @@ Before you can install the Phoniebox software, you need to prepare your Raspberr 2. Download the [Raspberry Pi Imager](https://www.raspberrypi.com/software/) and run it 3. Click on "Raspberry Pi Device" and select "No filtering" 4. As operating system select **Raspberry Pi OS (other)** and then **Raspberry Pi OS Lite (Legacy, 32-bit)** (no desktop environment). *64-bit is currently not supported*. - * Bookworm support is partly broken, see [here](#workaround-for-network-related-features-on-bookworm). * For Pi 4 and newer also check [this](#workaround-for-64-bit-kernels-pi-4-and-newer). 5. Select your Micro SD card (your card will be formatted) 6. After you click `Next`, a prompt will ask you if you like to customize the OS settings @@ -81,21 +80,21 @@ You will need a terminal, like PuTTY for Windows or the Terminal app for Mac to ### Pre-install preparation / workarounds -#### Workaround for network related features on Bookworm +#### Network management since Bookworm
-With Bookworm the network settings have changed. Now "NetworkManager" is used instead of "dhcpcd". -This breaks breaks network related features like "Static IP", "Wifi Setup" and "Autohotspot". -Before running the installation, the network config has to be changed via raspi-config, to use the "old" dhcpcd network settings. +With Bookworm, network management has changed. Now, "NetworkManager" is used instead of "dhcpcd". +Both methods are supported during installation, but "NetworkManager" is recommended as it is simpler to set up and use. +For Bullseye, this can also be activated, though it requires a manual process before running the installation. :warning: -If the settings are changed, your network will reset and Wifi will not be configured, so you lose ssh access via wireless connection. -So make sure you use a wired connection or perform the following steps in a local terminal with a connected monitor and keyboard. +If the settings are changed, your network will reset, and WiFi will not be configured, causing you to lose SSH access via wireless connection. +Therefore, make sure you use a wired connection or perform the following steps in a local terminal with a connected monitor and keyboard. Change network config * run `sudo raspi-config` * select `6 - Advanced Options` * select `AA - Network Config` -* select `dhcpcd` +* select `NetworkManager` If you need Wifi, add the information now * select `1 - System Options` diff --git a/installation/includes/00_constants.sh b/installation/includes/00_constants.sh index 89299989c..574febed3 100644 --- a/installation/includes/00_constants.sh +++ b/installation/includes/00_constants.sh @@ -1,7 +1,6 @@ -RPI_BOOT_CONFIG_FILE="/boot/config.txt" -RPI_BOOT_CMDLINE_FILE="/boot/cmdline.txt" SHARED_PATH="${INSTALLATION_PATH}/shared" SETTINGS_PATH="${SHARED_PATH}/settings" +SYSTEMD_PATH="/etc/systemd/system" SYSTEMD_USR_PATH="/usr/lib/systemd/user" VIRTUAL_ENV="${INSTALLATION_PATH}/.venv" # Do not change this directory! It must match MPDs expectation where to find the user configuration diff --git a/installation/includes/01_default_config.sh b/installation/includes/01_default_config.sh index ec7b67b66..a3115fee6 100644 --- a/installation/includes/01_default_config.sh +++ b/installation/includes/01_default_config.sh @@ -4,8 +4,11 @@ BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE=${BUILD_LIBZMQ_WITH_DRAFTS_ON_DEVICE:-"false" ENABLE_STATIC_IP=true DISABLE_IPv6=true ENABLE_AUTOHOTSPOT=false -AUTOHOTSPOT_CHANGE_PASSWORD=false +AUTOHOTSPOT_PROFILE="Phoniebox_Hotspot" +AUTOHOTSPOT_SSID="$AUTOHOTSPOT_PROFILE" AUTOHOTSPOT_PASSWORD="PlayItLoud!" +AUTOHOTSPOT_IP="10.0.0.1" +AUTOHOTSPOT_COUNTRYCODE="DE" DISABLE_BLUETOOTH=true DISABLE_SSH_QOS=true DISABLE_BOOT_SCREEN=true @@ -18,7 +21,6 @@ ENABLE_SAMBA=true ENABLE_WEBAPP=true ENABLE_KIOSK_MODE=false DISABLE_ONBOARD_AUDIO=false -DISABLE_ONBOARD_AUDIO_BACKUP="${RPI_BOOT_CONFIG_FILE}.backup.audio_on_$(date +%d.%m.%y_%H.%M.%S)" # Always try to use GIT with SSH first, and on failure drop down to HTTPS GIT_USE_SSH=${GIT_USE_SSH:-"true"} diff --git a/installation/includes/02_helpers.sh b/installation/includes/02_helpers.sh index 9cd51c824..be496b1b9 100644 --- a/installation/includes/02_helpers.sh +++ b/installation/includes/02_helpers.sh @@ -88,16 +88,17 @@ get_debian_version_number() { echo "$VERSION_ID" } -get_boot_config_path() { +_get_boot_file_path() { + local filename="$1" if [ "$(is_raspbian)" = true ]; then local debian_version_number=$(get_debian_version_number) # Bullseye and lower if [ "$debian_version_number" -le 11 ]; then - echo "/boot/config.txt" + echo "/boot/${filename}" # Bookworm and higher elif [ "$debian_version_number" -ge 12 ]; then - echo "/boot/firmware/config.txt" + echo "/boot/firmware/${filename}" else echo "unknown" fi @@ -106,6 +107,14 @@ get_boot_config_path() { fi } +get_boot_config_path() { + echo $(_get_boot_file_path "config.txt") +} + +get_boot_cmdline_path() { + echo $(_get_boot_file_path "cmdline.txt") +} + validate_url() { local url=$1 wget --spider ${url} >/dev/null 2>&1 @@ -119,6 +128,70 @@ download_from_url() { return $? } +get_string_length() { + local string="$1" + # "-n" option is needed otherwise an additional linebreak char is added by echo + echo -n ${string} | wc -m +} + +_get_service_enablement() { + local service="$1" + local option="${2:+$2 }" # optional, dont't quote in 'systemctl' call! + + if [[ -z "${service}" ]]; then + exit_on_error "ERROR: at least one parameter value is missing!" + fi + + local actual_enablement=$(systemctl is-enabled ${option}${service} 2>/dev/null) + + echo "$actual_enablement" +} + +is_service_enabled() { + local service="$1" + local option="$2" + local actual_enablement=$(_get_service_enablement $service $option) + + if [[ "$actual_enablement" == "enabled" ]]; then + echo true + else + echo false + fi +} + +is_dhcpcd_enabled() { + echo $(is_service_enabled "dhcpcd.service") +} + +is_NetworkManager_enabled() { + echo $(is_service_enabled "NetworkManager.service") +} + +# create flag file if files does no exist (*.remove) or copy present conf to backup file (*.orig) +# to correctly handling de-/activation of corresponding feature +config_file_backup() { + local config_file="$1" + local config_flag_file="${config_file}.remove" + local config_orig_file="${config_file}.orig" + if [ ! -f "${config_file}" ]; then + sudo touch "${config_flag_file}" + elif [ ! -f "${config_orig_file}" ] && [ ! -f "${config_flag_file}" ]; then + sudo cp "${config_file}" "${config_orig_file}" + fi +} + +# revert config files backed up with `config_file_backup` +config_file_revert() { + local config_file="$1" + local config_flag_file="${config_file}.remove" + local config_orig_file="${config_file}.orig" + if [ -f "${config_flag_file}" ]; then + sudo rm "${config_flag_file}" "${config_file}" + elif [ -f "${config_orig_file}" ]; then + sudo mv "${config_orig_file}" "${config_file}" + fi +} + ### Verify helpers print_verify_installation() { log "\n @@ -220,7 +293,7 @@ verify_file_contains_string() { exit_on_error "ERROR: at least one parameter value is missing!" fi - if [[ ! $(grep -iw "${string}" "${file}") ]]; then + if [[ ! $(sudo grep -iw "${string}" "${file}") ]]; then exit_on_error "ERROR: '${string}' not found in '${file}'" fi log " CHECK" @@ -235,7 +308,7 @@ verify_file_contains_string_once() { exit_on_error "ERROR: at least one parameter value is missing!" fi - local file_contains_string_count=$(grep -oiw "${string}" "${file}" | wc -l) + local file_contains_string_count=$(sudo grep -oiw "${string}" "${file}" | wc -l) if [ "$file_contains_string_count" -lt 1 ]; then exit_on_error "ERROR: '${string}' not found in '${file}'" elif [ "$file_contains_string_count" -gt 1 ]; then @@ -247,7 +320,7 @@ verify_file_contains_string_once() { verify_service_state() { local service="$1" local desired_state="$2" - local option="${3:+$3 }" # optional, dont't quote in next call! + local option="${3:+$3 }" # optional, dont't quote in next call! log " Verify service '${option}${service}' is '${desired_state}'" if [[ -z "${service}" || -z "${desired_state}" ]]; then @@ -264,14 +337,14 @@ verify_service_state() { verify_service_enablement() { local service="$1" local desired_enablement="$2" - local option="${3:+$3 }" # optional, dont't quote in next call! + local option="$3" log " Verify service ${option}${service} is ${desired_enablement}" if [[ -z "${service}" || -z "${desired_enablement}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" fi - local actual_enablement=$(systemctl is-enabled ${option}${service}) + local actual_enablement=$(_get_service_enablement $service $option) if [[ ! "${actual_enablement}" == "${desired_enablement}" ]]; then exit_on_error "ERROR: service ${option}${service} is not ${desired_enablement} (state: ${actual_enablement})." fi @@ -281,14 +354,14 @@ verify_service_enablement() { verify_optional_service_enablement() { local service="$1" local desired_enablement="$2" - local option="${3:+$3 }" # optional, dont't quote in next call! + local option="$3" log " Verify service ${option}${service} is ${desired_enablement}" if [[ -z "${service}" || -z "${desired_enablement}" ]]; then exit_on_error "ERROR: at least one parameter value is missing!" fi - local actual_enablement=$(systemctl is-enabled ${option}${service}) 2>/dev/null + local actual_enablement=$(_get_service_enablement $service $option) if [[ -z "${actual_enablement}" ]]; then log " INFO: optional service ${option}${service} is not installed." elif [[ "${actual_enablement}" == "static" ]]; then diff --git a/installation/routines/customize_options.sh b/installation/routines/customize_options.sh index c903df189..de1dd5a19 100644 --- a/installation/routines/customize_options.sh +++ b/installation/routines/customize_options.sh @@ -49,51 +49,98 @@ Do you want to disable IPv6? [Y/n]" } _option_autohotspot() { - # ENABLE_AUTOHOTSPOT - clear_c - print_c "---------------------- AUTOHOTSPOT ---------------------- + # ENABLE_AUTOHOTSPOT + clear_c + print_c "---------------------- AUTOHOTSPOT ---------------------- When enabled, this service spins up a WiFi hotspot when the Phoniebox is unable to connect to a known WiFi. This way you can still access it. -Do you want to enable an Autohotpot? [y/N]" - read -r response - case "$response" in - [yY][eE][sS]|[yY]) - ENABLE_AUTOHOTSPOT=true - ;; - *) - ;; - esac +Note: +Static IP configuration cannot be enabled with +WiFi hotspot and will be disabled, if selected before. - if [ "$ENABLE_AUTOHOTSPOT" = true ]; then - print_c "Do you want to set a custom Password? (default: ${AUTOHOTSPOT_PASSWORD}) [y/N] " - read -r response_pw_q - case "$response_pw_q" in +Do you want to enable an Autohotspot? [y/N]" + read -r response + case "$response" in [yY][eE][sS]|[yY]) - while [ $(echo ${response_pw}|wc -m) -lt 8 ] - do - print_c "Please type the new password (at least 8 character)." - read -r response_pw - done - AUTOHOTSPOT_PASSWORD="${response_pw}" - ;; + ENABLE_AUTOHOTSPOT=true + ;; *) - ;; - esac + ;; + esac + + if [ "$ENABLE_AUTOHOTSPOT" = true ]; then + #add hostname to default SSID to prevent collision + local local_hostname=$(hostname) + AUTOHOTSPOT_SSID="${AUTOHOTSPOT_SSID}_${local_hostname}" + AUTOHOTSPOT_SSID="${AUTOHOTSPOT_SSID:0:32}" + + local response_autohotspot + while [[ $response_autohotspot != "n" ]] + do + print_c " +--- Current configuration for Autohotpot +SSID : $AUTOHOTSPOT_SSID +Password : $AUTOHOTSPOT_PASSWORD +WiFi Country Code : $AUTOHOTSPOT_COUNTRYCODE +IP : $AUTOHOTSPOT_IP +Do you want to change this values? [y/N]" + read -r response_autohotspot + case "$response_autohotspot" in + [yY][eE][sS]|[yY]) + local response_ssid="" + local response_ssid_length=0 + while [[ $response_ssid_length -lt 1 || $response_ssid_length -gt 32 ]] + do + print_c "Please type the hotspot ssid (must be between 1 and 32 characters long):" + read -r response_ssid + response_ssid_length=$(get_string_length ${response_ssid}) + done + + local response_pw="" + local response_pw_length=0 + while [[ $response_pw_length -lt 8 || $response_pw_length -gt 63 ]] + do + print_c "Please type the new password (must be between 8 and 63 characters long):" + read -r response_pw + response_pw_length=$(get_string_length ${response_pw}) + done + + local response_country_code="" + local response_country_code_length=0 + while [[ $response_country_code_length -ne 2 ]] + do + print_c "Please type the WiFi country code (e.g. DE, GB, CZ or US):" + read -r response_country_code + response_country_code="${response_country_code^^}" # to Uppercase + response_country_code_length=$(get_string_length ${response_country_code}) + done + + AUTOHOTSPOT_SSID="${response_ssid}" + AUTOHOTSPOT_PASSWORD="${response_pw}" + AUTOHOTSPOT_COUNTRYCODE="${response_country_code}" + ;; + *) + response_autohotspot=n + ;; + esac + done - if [ "$ENABLE_STATIC_IP" = true ]; then - print_c "Wifi hotspot cannot be enabled with static IP. Disabling static IP configuration." - ENABLE_STATIC_IP=false - log "ENABLE_STATIC_IP=${ENABLE_STATIC_IP}" - fi - fi + if [ "$ENABLE_STATIC_IP" = true ]; then + ENABLE_STATIC_IP=false + echo "ENABLE_STATIC_IP=${ENABLE_STATIC_IP}" + fi + fi - log "ENABLE_AUTOHOTSPOT=${ENABLE_AUTOHOTSPOT}" - if [ "$ENABLE_AUTOHOTSPOT" = true ]; then - log "AUTOHOTSPOT_PASSWORD=${AUTOHOTSPOT_PASSWORD}" - fi + echo "ENABLE_AUTOHOTSPOT=${ENABLE_AUTOHOTSPOT}" + if [ "$ENABLE_AUTOHOTSPOT" = true ]; then + echo "AUTOHOTSPOT_SSID=${AUTOHOTSPOT_SSID}" + echo "AUTOHOTSPOT_PASSWORD=${AUTOHOTSPOT_PASSWORD}" + echo "AUTOHOTSPOT_COUNTRYCODE=${AUTOHOTSPOT_COUNTRYCODE}" + echo "AUTOHOTSPOT_IP=${AUTOHOTSPOT_IP}" + fi } _option_bluetooth() { @@ -275,11 +322,10 @@ the on-chip audio. It will make the ALSA sound configuration easier. If you are planning to only use Bluetooth speakers, leave the on-chip audio enabled! -(This will touch your boot configuration in -${RPI_BOOT_CONFIG_FILE}. +(This will touch your boot configuration file. We will do our best not to mess anything up. However, -a backup copy will be written to -${DISABLE_ONBOARD_AUDIO_BACKUP} ) +a backup copy will be written. Please check the install +log after for further details.) Disable Pi's on-chip audio (headphone / jack output)? [y/N]" read -r response diff --git a/installation/routines/optimize_boot_time.sh b/installation/routines/optimize_boot_time.sh index bb6f71902..e3761c31d 100644 --- a/installation/routines/optimize_boot_time.sh +++ b/installation/routines/optimize_boot_time.sh @@ -4,8 +4,8 @@ OPTIMIZE_DHCP_CONF="/etc/dhcpcd.conf" OPTIMIZE_BOOT_CMDLINE_OPTIONS="consoleblank=1 logo.nologo quiet loglevel=0 plymouth.enable=0 vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fastboot noatime nodiratime noram" +OPTIMIZE_BOOT_CMDLINE_OPTIONS_IPV6="ipv6.disable=1" OPTIMIZE_DHCP_CONF_HEADER="## Jukebox DHCP Config" -OPTIMIZE_IPV6_CONF_HEADER="## Jukebox IPV6 Config" OPTIMIZE_BOOT_CONF_HEADER="## Jukebox Boot Config" _optimize_disable_irrelevant_services() { @@ -26,6 +26,24 @@ _optimize_disable_irrelevant_services() { sudo systemctl disable apt-daily-upgrade.timer } +_add_options_to_cmdline() { + local options="$1" + + local cmdlineFile=$(get_boot_cmdline_path) + if [ ! -s "${cmdlineFile}" ];then + sudo tee "${cmdlineFile}" <<-EOF +${options} +EOF + else + for option in $options + do + if ! grep -qiw "$option" "${cmdlineFile}" ; then + sudo sed -i "s/$/ $option/" "${cmdlineFile}" + fi + done + fi +} + # TODO: If false, actually make sure bluetooth is enabled _optimize_handle_bluetooth() { if [ "$DISABLE_BLUETOOTH" = true ] ; then @@ -37,58 +55,52 @@ _optimize_handle_bluetooth() { # TODO: Allow options to enable/disable wifi, Dynamic/Static IP etc. _optimize_static_ip() { - # Static IP Address and DHCP optimizations - if [ "$ENABLE_STATIC_IP" = true ] ; then - print_lc " Set static IP address" - if grep -q "${OPTIMIZE_DHCP_CONF_HEADER}" "$OPTIMIZE_DHCP_CONF"; then - log " Skipping. Already set up!" - else - # DHCP has not been configured - log " ${CURRENT_INTERFACE} is the default network interface" - log " ${CURRENT_GATEWAY} is the Router Gateway address" - log " Using ${CURRENT_IP_ADDRESS} as the static IP for now" - - sudo tee -a $OPTIMIZE_DHCP_CONF <<-EOF + # Static IP Address and DHCP optimizations + if [[ $(is_dhcpcd_enabled) == true ]]; then + if [ "$ENABLE_STATIC_IP" = true ] ; then + print_lc " Set static IP address" + if grep -q "${OPTIMIZE_DHCP_CONF_HEADER}" "$OPTIMIZE_DHCP_CONF"; then + log " Skipping. Already set up!" + else + # DHCP has not been configured + log " ${CURRENT_INTERFACE} is the default network interface" + log " ${CURRENT_GATEWAY} is the Router Gateway address" + log " Using ${CURRENT_IP_ADDRESS} as the static IP for now" + + sudo tee -a $OPTIMIZE_DHCP_CONF <<-EOF ${OPTIMIZE_DHCP_CONF_HEADER} interface ${CURRENT_INTERFACE} static ip_address=${CURRENT_IP_ADDRESS}/24 static routers=${CURRENT_GATEWAY} static domain_name_servers=${CURRENT_GATEWAY} +noarp EOF + fi + fi fi - fi } # TODO: Allow both Enable and Disable +# Disable ipv6 thoroughly on the system with kernel parameter _optimize_ipv6_arp() { - if [ "$DISABLE_IPv6" = true ] ; then - print_lc " Disabling IPV6" - if grep -q "${OPTIMIZE_IPV6_CONF_HEADER}" "$OPTIMIZE_DHCP_CONF"; then - log " Skipping. Already set up!" - else - sudo tee -a $OPTIMIZE_DHCP_CONF <<-EOF - -${OPTIMIZE_IPV6_CONF_HEADER} -noarp -ipv4only -noipv6 - -EOF + if [ "$DISABLE_IPv6" = true ] ; then + print_lc " Disabling IPV6" + _add_options_to_cmdline "${OPTIMIZE_BOOT_CMDLINE_OPTIONS_IPV6}" fi - fi } # TODO: Allow both Enable and Disable _optimize_handle_boot_screen() { + local configFile=$(get_boot_config_path) if [ "$DISABLE_BOOT_SCREEN" = true ] ; then log " Disable RPi rainbow screen" - if grep -q "${OPTIMIZE_BOOT_CONF_HEADER}" "$RPI_BOOT_CONFIG_FILE"; then + if grep -q "${OPTIMIZE_BOOT_CONF_HEADER}" "$configFile"; then log " Skipping. Already set up!" else - sudo tee -a $RPI_BOOT_CONFIG_FILE <<-EOF + sudo tee -a $configFile <<-EOF ${OPTIMIZE_BOOT_CONF_HEADER} disable_splash=1 @@ -103,25 +115,40 @@ _optimize_handle_boot_logs() { if [ "$DISABLE_BOOT_LOGS_PRINT" = true ] ; then log " Disable boot logs" - if [ ! -s "${RPI_BOOT_CMDLINE_FILE}" ];then - sudo tee "${RPI_BOOT_CMDLINE_FILE}" <<-EOF -${OPTIMIZE_BOOT_CMDLINE_OPTIONS} -EOF - else - for option in $OPTIMIZE_BOOT_CMDLINE_OPTIONS - do - if ! grep -qiw "$option" "${RPI_BOOT_CMDLINE_FILE}" ; then - sudo sed -i "s/$/ $option/" "${RPI_BOOT_CMDLINE_FILE}" - fi - done - fi + _add_options_to_cmdline "${OPTIMIZE_BOOT_CMDLINE_OPTIONS}" fi } +get_nm_active_profile() +{ + local active_profile=$(nmcli -g DEVICE,CONNECTION device status | grep "^${CURRENT_INTERFACE}" | cut -d':' -f2) + echo "$active_profile" +} + +_optimize_static_ip_NetworkManager() { + if [[ $(is_NetworkManager_enabled) == true ]]; then + if [ "$ENABLE_STATIC_IP" = true ] ; then + print_lc " Set static IP address" + log " ${CURRENT_INTERFACE} is the default network interface" + log " ${CURRENT_GATEWAY} is the Router Gateway address" + log " Using ${CURRENT_IP_ADDRESS} as the static IP for now" + local active_profile=$(get_nm_active_profile) + sudo nmcli connection modify "$active_profile" ipv4.method manual ipv4.address "${CURRENT_IP_ADDRESS}/24" ipv4.gateway "$CURRENT_GATEWAY" ipv4.dns "$CURRENT_GATEWAY" + #else + # for future deactivation + #sudo nmcli connection modify "$active_profile" ipv4.method auto ipv4.address "" ipv4.gateway "" ipv4.dns "" + fi + fi +} + _optimize_check() { print_verify_installation + local cmdlineFile=$(get_boot_cmdline_path) + local configFile=$(get_boot_config_path) + + verify_optional_service_enablement keyboard-setup.service disabled verify_optional_service_enablement triggerhappy.service disabled verify_optional_service_enablement triggerhappy.socket disabled @@ -137,33 +164,44 @@ _optimize_check() { fi if [ "$ENABLE_STATIC_IP" = true ] ; then - verify_file_contains_string_once "${OPTIMIZE_DHCP_CONF_HEADER}" "${OPTIMIZE_DHCP_CONF}" - verify_file_contains_string "${CURRENT_INTERFACE}" "${OPTIMIZE_DHCP_CONF}" - verify_file_contains_string "${CURRENT_IP_ADDRESS}" "${OPTIMIZE_DHCP_CONF}" - verify_file_contains_string "${CURRENT_GATEWAY}" "${OPTIMIZE_DHCP_CONF}" + if [[ $(is_dhcpcd_enabled) == true ]]; then + verify_file_contains_string_once "${OPTIMIZE_DHCP_CONF_HEADER}" "${OPTIMIZE_DHCP_CONF}" + verify_file_contains_string "${CURRENT_INTERFACE}" "${OPTIMIZE_DHCP_CONF}" + verify_file_contains_string "${CURRENT_IP_ADDRESS}" "${OPTIMIZE_DHCP_CONF}" + verify_file_contains_string "${CURRENT_GATEWAY}" "${OPTIMIZE_DHCP_CONF}" + fi + + if [[ $(is_NetworkManager_enabled) == true ]]; then + local active_profile=$(get_nm_active_profile) + local active_profile_path="/etc/NetworkManager/system-connections/${active_profile}.nmconnection" + verify_files_exists "${active_profile_path}" + verify_file_contains_string "${CURRENT_IP_ADDRESS}" "${active_profile_path}" + verify_file_contains_string "${CURRENT_GATEWAY}" "${active_profile_path}" + fi fi if [ "$DISABLE_IPv6" = true ] ; then - verify_file_contains_string_once "${OPTIMIZE_IPV6_CONF_HEADER}" "${OPTIMIZE_DHCP_CONF}" + verify_file_contains_string_once "${OPTIMIZE_BOOT_CMDLINE_OPTIONS_IPV6}" "${cmdlineFile}" fi if [ "$DISABLE_BOOT_SCREEN" = true ] ; then - verify_file_contains_string_once "${OPTIMIZE_BOOT_CONF_HEADER}" "${RPI_BOOT_CONFIG_FILE}" + verify_file_contains_string_once "${OPTIMIZE_BOOT_CONF_HEADER}" "${configFile}" fi if [ "$DISABLE_BOOT_LOGS_PRINT" = true ] ; then for option in $OPTIMIZE_BOOT_CMDLINE_OPTIONS do - verify_file_contains_string_once $option "${RPI_BOOT_CMDLINE_FILE}" + verify_file_contains_string_once $option "${cmdlineFile}" done fi } _run_optimize_boot_time() { _optimize_disable_irrelevant_services + _optimize_handle_boot_screen + _optimize_handle_boot_logs _optimize_handle_bluetooth _optimize_static_ip + _optimize_static_ip_NetworkManager _optimize_ipv6_arp - _optimize_handle_boot_screen - _optimize_handle_boot_logs _optimize_check } diff --git a/installation/routines/set_raspi_config.sh b/installation/routines/set_raspi_config.sh index 7f39a0ba5..ef4707c91 100644 --- a/installation/routines/set_raspi_config.sh +++ b/installation/routines/set_raspi_config.sh @@ -17,13 +17,15 @@ _run_set_raspi_config() { # On-board audio if [ "$DISABLE_ONBOARD_AUDIO" == true ]; then + local configFile=$(get_boot_config_path) log " Disable on-chip BCM audio" - if grep -q -E "^dtparam=([^,]*,)*audio=(on|true|yes|1).*" "${RPI_BOOT_CONFIG_FILE}" ; then - log " Backup ${RPI_BOOT_CONFIG_FILE} --> ${DISABLE_ONBOARD_AUDIO_BACKUP}" - sudo cp "${RPI_BOOT_CONFIG_FILE}" "${DISABLE_ONBOARD_AUDIO_BACKUP}" - sudo sed -i "s/^\(dtparam=\([^,]*,\)*\)audio=\(on\|true\|yes\|1\)\(.*\)/\1audio=off\4/g" "${RPI_BOOT_CONFIG_FILE}" + if grep -q -E "^dtparam=([^,]*,)*audio=(on|true|yes|1).*" "${configFile}" ; then + local configFile_backup="${configFile}.backup.audio_on_$(date +%d.%m.%y_%H.%M.%S)" + log " Backup ${configFile} --> ${configFile_backup}" + sudo cp "${configFile}" "${configFile_backup}" + sudo sed -i "s/^\(dtparam=\([^,]*,\)*\)audio=\(on\|true\|yes\|1\)\(.*\)/\1audio=off\4/g" "${configFile}" else - log " On board audio seems to be off already. Not touching ${RPI_BOOT_CONFIG_FILE}" + log " On board audio seems to be off already. Not touching ${configFile}" fi fi } diff --git a/installation/routines/setup_autohotspot.sh b/installation/routines/setup_autohotspot.sh index a083b3fcf..47b72757a 100644 --- a/installation/routines/setup_autohotspot.sh +++ b/installation/routines/setup_autohotspot.sh @@ -1,119 +1,46 @@ #!/usr/bin/env bash -# inspired by -# https://www.raspberryconnect.com/projects/65-raspberrypi-hotspot-accesspoints/158-raspberry-pi-auto-wifi-hotspot-switch-direct-connection - - -AUTOHOTSPOT_HOSTAPD_CONF_FILE="/etc/hostapd/hostapd.conf" -AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE="/etc/default/hostapd" -AUTOHOTSPOT_DNSMASQ_CONF_FILE="/etc/dnsmasq.conf" -AUTOHOTSPOT_DHCPD_CONF_FILE="/etc/dhcpcd.conf" - +AUTOHOTSPOT_INTERFACES_CONF_FILE="/etc/network/interfaces" AUTOHOTSPOT_TARGET_PATH="/usr/bin/autohotspot" +AUTOHOTSPOT_SERVICE="autohotspot.service" +AUTOHOTSPOT_SERVICE_PATH="${SYSTEMD_PATH}/${AUTOHOTSPOT_SERVICE}" +AUTOHOTSPOT_TIMER="autohotspot.timer" +AUTOHOTSPOT_TIMER_PATH="${SYSTEMD_PATH}/${AUTOHOTSPOT_TIMER}" _get_interface() { # interfaces may vary WIFI_INTERFACE=$(iw dev | grep "Interface"| awk '{ print $2 }') - WIFI_REGION=$(iw reg get | grep country | head -n 1 | awk '{ print $2}' | cut -d: -f1) # fix for CI runs on docker if [ "${CI_RUNNING}" == "true" ]; then if [ -z "${WIFI_INTERFACE}" ]; then WIFI_INTERFACE="CI TEST INTERFACE" fi - if [ -z "${WIFI_REGION}" ]; then - WIFI_REGION="CI TEST REGION" - fi fi } -_install_packages() { - sudo apt-get -y install hostapd dnsmasq iw - - # disable services. We want to start them manually - sudo systemctl unmask hostapd - sudo systemctl disable hostapd - sudo systemctl disable dnsmasq -} - -_configure_hostapd() { - local HOSTAPD_CUSTOM_FILE="${INSTALLATION_PATH}"/resources/autohotspot/hostapd.conf - - sed -i "s/WIFI_INTERFACE/${WIFI_INTERFACE}/g" "${HOSTAPD_CUSTOM_FILE}" - sed -i "s/AUTOHOTSPOT_PASSWORD/${AUTOHOTSPOT_PASSWORD}/g" "${HOSTAPD_CUSTOM_FILE}" - sed -i "s/WIFI_REGION/${WIFI_REGION}/g" "${HOSTAPD_CUSTOM_FILE}" - sudo cp "${HOSTAPD_CUSTOM_FILE}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" - - sudo sed -i "s@^#DAEMON_CONF=.*@DAEMON_CONF=\"${AUTOHOTSPOT_HOSTAPD_CONF_FILE}\"@g" "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" -} - -_configure_dnsmasq() { - sudo tee -a "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" <<-EOF -#AutoHotspot Config -#stop DNSmasq from using resolv.conf -no-resolv -#Interface to use -interface=${WIFI_INTERFACE} -bind-interfaces -dhcp-range=10.0.0.50,10.0.0.150,12h -EOF -} - -_other_configuration() { - sudo mv /etc/network/interfaces /etc/network/interfaces.bak - sudo touch /etc/network/interfaces - echo nohook wpa_supplicant | sudo tee -a "${AUTOHOTSPOT_DHCPD_CONF_FILE}" -} - -_install_service_and_timer() { - sudo cp "${INSTALLATION_PATH}"/resources/autohotspot/autohotspot.service /etc/systemd/system/autohotspot.service - sudo systemctl enable autohotspot.service - local cron_autohotspot_file="/etc/cron.d/autohotspot" - sudo cp "${INSTALLATION_PATH}"/resources/autohotspot/autohotspot.timer "${cron_autohotspot_file}" - sudo sed -i "s|%%USER%%|${CURRENT_USER}|g" "${cron_autohotspot_file}" +_get_last_ip_segment() { + local ip="$1" + echo $ip | cut -d'.' -f1-3 } -_install_autohotspot_script() { - sudo cp "${INSTALLATION_PATH}"/resources/autohotspot/autohotspot "${AUTOHOTSPOT_TARGET_PATH}" - sudo chmod +x "${AUTOHOTSPOT_TARGET_PATH}" -} - - -_autohotspot_check() { - print_verify_installation - - verify_apt_packages hostapd dnsmasq iw - - verify_service_enablement hostapd.service disabled - verify_service_enablement dnsmasq.service disabled - verify_service_enablement autohotspot.service enabled - - verify_files_exists "/etc/cron.d/autohotspot" - verify_files_exists "${AUTOHOTSPOT_TARGET_PATH}" - - verify_file_contains_string "${WIFI_INTERFACE}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" - verify_file_contains_string "${AUTOHOTSPOT_PASSWORD}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" - verify_file_contains_string "${WIFI_REGION}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" - verify_file_contains_string "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" - - verify_file_contains_string "${WIFI_INTERFACE}" "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" - verify_file_contains_string "nohook wpa_supplicant" "${AUTOHOTSPOT_DHCPD_CONF_FILE}" -} - -_run_setup_autohotspot() { - _install_packages - _get_interface - _configure_hostapd - _configure_dnsmasq - _other_configuration - _install_autohotspot_script - _install_service_and_timer - _autohotspot_check -} setup_autohotspot() { if [ "$ENABLE_AUTOHOTSPOT" == true ] ; then - run_with_log_frame _run_setup_autohotspot "Install AutoHotspot" + local installed=false + if [[ $(is_dhcpcd_enabled) == true || "${CI_RUNNING}" == "true" ]]; then + run_with_log_frame _run_setup_autohotspot_dhcpcd "Install AutoHotspot" + installed=true + fi + + if [[ $(is_NetworkManager_enabled) == true || "${CI_RUNNING}" == "true" ]]; then + run_with_log_frame _run_setup_autohotspot_NetworkManager "Install AutoHotspot" + installed=true + fi + + if [[ "$installed" != true ]]; then + exit_on_error "ERROR: No network service available" + fi fi } diff --git a/installation/routines/setup_autohotspot_NetworkManager.sh b/installation/routines/setup_autohotspot_NetworkManager.sh new file mode 100644 index 000000000..66e777f1b --- /dev/null +++ b/installation/routines/setup_autohotspot_NetworkManager.sh @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +AUTOHOTSPOT_NETWORKMANAGER_RESOURCES_PATH="${INSTALLATION_PATH}/resources/autohotspot/NetworkManager" +AUTOHOTSPOT_NETWORKMANAGER_CONNECTIONS_PATH="/etc/NetworkManager/system-connections" + +_install_packages_NetworkManager() { + sudo apt-get -y install iw +} + +_install_autohotspot_NetworkManager() { + # configure interface conf + config_file_backup "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" + sudo rm "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" + sudo touch "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" + + # create service to trigger hotspot + local ip_without_last_segment=$(_get_last_ip_segment $AUTOHOTSPOT_IP) + sudo cp "${AUTOHOTSPOT_NETWORKMANAGER_RESOURCES_PATH}"/autohotspot "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%WIFI_INTERFACE%%|${WIFI_INTERFACE}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_PROFILE%%|${AUTOHOTSPOT_PROFILE}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_SSID%%|${AUTOHOTSPOT_SSID}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_PASSWORD%%|${AUTOHOTSPOT_PASSWORD}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_IP%%|${AUTOHOTSPOT_IP}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%IP_WITHOUT_LAST_SEGMENT%%|${ip_without_last_segment}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_TIMER_NAME%%|${AUTOHOTSPOT_TIMER}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo chmod +x "${AUTOHOTSPOT_TARGET_PATH}" + + sudo cp "${AUTOHOTSPOT_NETWORKMANAGER_RESOURCES_PATH}"/autohotspot.service "${AUTOHOTSPOT_SERVICE_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_SCRIPT%%|${AUTOHOTSPOT_TARGET_PATH}|g" "${AUTOHOTSPOT_SERVICE_PATH}" + + sudo cp "${AUTOHOTSPOT_NETWORKMANAGER_RESOURCES_PATH}"/autohotspot.timer "${AUTOHOTSPOT_TIMER_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_SERVICE%%|${AUTOHOTSPOT_SERVICE}|g" "${AUTOHOTSPOT_TIMER_PATH}" + + + sudo systemctl unmask "${AUTOHOTSPOT_SERVICE}" + sudo systemctl unmask "${AUTOHOTSPOT_TIMER}" + sudo systemctl disable "${AUTOHOTSPOT_SERVICE}" + sudo systemctl enable "${AUTOHOTSPOT_TIMER}" +} + +_uninstall_autohotspot_NetworkManager() { + # clear autohotspot configurations made from past installation + + # stop services and clear services + if systemctl list-unit-files "${AUTOHOTSPOT_SERVICE}" >/dev/null 2>&1 ; then + sudo systemctl stop "${AUTOHOTSPOT_TIMER}" + sudo systemctl disable "${AUTOHOTSPOT_TIMER}" + sudo systemctl stop "${AUTOHOTSPOT_SERVICE}" + sudo systemctl disable "${AUTOHOTSPOT_SERVICE}" + sudo rm "${AUTOHOTSPOT_SERVICE_PATH}" + sudo rm "${AUTOHOTSPOT_TIMER_PATH}" + fi + + if [ -f "${AUTOHOTSPOT_TARGET_PATH}" ]; then + sudo rm "${AUTOHOTSPOT_TARGET_PATH}" + fi + + sudo rm -f "${AUTOHOTSPOT_NETWORKMANAGER_CONNECTIONS_PATH}/${AUTOHOTSPOT_PROFILE}*" + + # remove config files + config_file_revert "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" +} + +_autohotspot_check_NetworkManager() { + print_verify_installation + + verify_apt_packages iw + + verify_service_enablement "${AUTOHOTSPOT_SERVICE}" disabled + verify_service_enablement "${AUTOHOTSPOT_TIMER}" enabled + + verify_files_exists "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" + + local ip_without_last_segment=$(_get_last_ip_segment $AUTOHOTSPOT_IP) + verify_files_exists "${AUTOHOTSPOT_TARGET_PATH}" + verify_file_contains_string "wdev0='${WIFI_INTERFACE}'" "${AUTOHOTSPOT_TARGET_PATH}" + verify_file_contains_string "ap_profile_name='${AUTOHOTSPOT_PROFILE}'" "${AUTOHOTSPOT_TARGET_PATH}" + verify_file_contains_string "ap_ssid='${AUTOHOTSPOT_SSID}'" "${AUTOHOTSPOT_TARGET_PATH}" + verify_file_contains_string "ap_pw='${AUTOHOTSPOT_PASSWORD}'" "${AUTOHOTSPOT_TARGET_PATH}" + verify_file_contains_string "ap_ip='${AUTOHOTSPOT_IP}" "${AUTOHOTSPOT_TARGET_PATH}" #intentional "open end" + verify_file_contains_string "ap_gate='${ip_without_last_segment}" "${AUTOHOTSPOT_TARGET_PATH}" #intentional "open end" + verify_file_contains_string "timer_service_name='${AUTOHOTSPOT_TIMER}'" "${AUTOHOTSPOT_TARGET_PATH}" + + verify_files_exists "${AUTOHOTSPOT_SERVICE_PATH}" + verify_file_contains_string "ExecStart=${AUTOHOTSPOT_TARGET_PATH}" "${AUTOHOTSPOT_SERVICE_PATH}" + + verify_files_exists "${AUTOHOTSPOT_TIMER_PATH}" + verify_file_contains_string "Unit=${AUTOHOTSPOT_SERVICE}" "${AUTOHOTSPOT_TIMER_PATH}" +} + +_run_setup_autohotspot_NetworkManager() { + log "Install AutoHotspot NetworkManager" + _install_packages_NetworkManager + _get_interface + _uninstall_autohotspot_NetworkManager + _install_autohotspot_NetworkManager + _autohotspot_check_NetworkManager +} diff --git a/installation/routines/setup_autohotspot_dhcpcd.sh b/installation/routines/setup_autohotspot_dhcpcd.sh new file mode 100644 index 000000000..9ca92016c --- /dev/null +++ b/installation/routines/setup_autohotspot_dhcpcd.sh @@ -0,0 +1,185 @@ +#!/usr/bin/env bash + +# inspired by +# https://www.raspberryconnect.com/projects/65-raspberrypi-hotspot-accesspoints/158-raspberry-pi-auto-wifi-hotspot-switch-direct-connection + +AUTOHOTSPOT_HOSTAPD_CONF_FILE="/etc/hostapd/hostapd.conf" +AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE="/etc/default/hostapd" +AUTOHOTSPOT_DNSMASQ_CONF_FILE="/etc/dnsmasq.conf" +AUTOHOTSPOT_DHCPCD_CONF_FILE="/etc/dhcpcd.conf" +AUTOHOTSPOT_DHCPCD_CONF_NOHOOK_WPA_SUPPLICANT="nohook wpa_supplicant" + +AUTOHOTSPOT_SERVICE_DAEMON="autohotspot-daemon.service" +AUTOHOTSPOT_SERVICE_DAEMON_PATH="${SYSTEMD_PATH}/${AUTOHOTSPOT_SERVICE_DAEMON}" + +AUTOHOTSPOT_DHCPCD_RESOURCES_PATH="${INSTALLATION_PATH}/resources/autohotspot/dhcpcd" + +_install_packages_dhcpcd() { + sudo apt-get -y install hostapd dnsmasq iw + + # disable services. We want to start them manually + sudo systemctl unmask hostapd + sudo systemctl disable hostapd + sudo systemctl stop hostapd + sudo systemctl unmask dnsmasq + sudo systemctl disable dnsmasq + sudo systemctl stop dnsmasq +} + +_install_autohotspot_dhcpcd() { + # configure interface conf + config_file_backup "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" + sudo rm "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" + sudo touch "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" + + + # configure DNS + config_file_backup "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + + local ip_without_last_segment=$(_get_last_ip_segment $AUTOHOTSPOT_IP) + sudo cp "${AUTOHOTSPOT_DHCPCD_RESOURCES_PATH}"/dnsmasq.conf "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + sudo sed -i "s|%%WIFI_INTERFACE%%|${WIFI_INTERFACE}|g" "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + sudo sed -i "s|%%IP_WITHOUT_LAST_SEGMENT%%|${ip_without_last_segment}|g" "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + + + # configure hostapd conf + config_file_backup "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + + sudo cp "${AUTOHOTSPOT_DHCPCD_RESOURCES_PATH}"/hostapd.conf "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + sudo sed -i "s|%%WIFI_INTERFACE%%|${WIFI_INTERFACE}|g" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + sudo sed -i "s|%%AUTOHOTSPOT_SSID%%|${AUTOHOTSPOT_SSID}|g" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + sudo sed -i "s|%%AUTOHOTSPOT_PASSWORD%%|${AUTOHOTSPOT_PASSWORD}|g" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + sudo sed -i "s|%%AUTOHOTSPOT_COUNTRYCODE%%|${AUTOHOTSPOT_COUNTRYCODE}|g" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + + + # configure hostapd daemon + config_file_backup "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" + + sudo cp "${AUTOHOTSPOT_DHCPCD_RESOURCES_PATH}"/hostapd "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" + sudo sed -i "s|%%HOSTAPD_CONF%%|${AUTOHOTSPOT_HOSTAPD_CONF_FILE}|g" "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" + + + # configure dhcpcd conf + config_file_backup "${AUTOHOTSPOT_DHCPCD_CONF_FILE}" + if [ ! -f "${AUTOHOTSPOT_DHCPCD_CONF_FILE}" ]; then + sudo touch "${AUTOHOTSPOT_DHCPCD_CONF_FILE}" + sudo chown root:netdev "${AUTOHOTSPOT_DHCPCD_CONF_FILE}" + sudo chmod 664 "${AUTOHOTSPOT_DHCPCD_CONF_FILE}" + fi + + if [[ ! $(grep -w "${AUTOHOTSPOT_DHCPCD_CONF_NOHOOK_WPA_SUPPLICANT}" ${AUTOHOTSPOT_DHCPCD_CONF_FILE}) ]]; then + sudo bash -c "echo ${AUTOHOTSPOT_DHCPCD_CONF_NOHOOK_WPA_SUPPLICANT} >> ${AUTOHOTSPOT_DHCPCD_CONF_FILE}" + fi + + # create service to trigger hotspot + sudo cp "${AUTOHOTSPOT_DHCPCD_RESOURCES_PATH}"/autohotspot "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%WIFI_INTERFACE%%|${WIFI_INTERFACE}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_IP%%|${AUTOHOTSPOT_IP}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_SERVICE_DAEMON%%|${AUTOHOTSPOT_SERVICE_DAEMON}|g" "${AUTOHOTSPOT_TARGET_PATH}" + sudo chmod +x "${AUTOHOTSPOT_TARGET_PATH}" + + sudo cp "${AUTOHOTSPOT_DHCPCD_RESOURCES_PATH}"/autohotspot-daemon.service "${AUTOHOTSPOT_SERVICE_DAEMON_PATH}" + sudo sed -i "s|%%WIFI_INTERFACE%%|${WIFI_INTERFACE}|g" "${AUTOHOTSPOT_SERVICE_DAEMON_PATH}" + + sudo cp "${AUTOHOTSPOT_DHCPCD_RESOURCES_PATH}"/autohotspot.service "${AUTOHOTSPOT_SERVICE_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_SCRIPT%%|${AUTOHOTSPOT_TARGET_PATH}|g" "${AUTOHOTSPOT_SERVICE_PATH}" + + sudo cp "${AUTOHOTSPOT_DHCPCD_RESOURCES_PATH}"/autohotspot.timer "${AUTOHOTSPOT_TIMER_PATH}" + sudo sed -i "s|%%AUTOHOTSPOT_SERVICE%%|${AUTOHOTSPOT_SERVICE}|g" "${AUTOHOTSPOT_TIMER_PATH}" + + sudo systemctl enable "${AUTOHOTSPOT_SERVICE_DAEMON}" + sudo systemctl disable "${AUTOHOTSPOT_SERVICE}" + sudo systemctl enable "${AUTOHOTSPOT_TIMER}" +} + + +_uninstall_autohotspot_dhcpcd() { + # clear autohotspot configurations made from past installation + + # remove old crontab entries from previous versions + local cron_autohotspot_file="/etc/cron.d/autohotspot" + if [ -f "${cron_autohotspot_file}" ]; then + sudo rm -f "${cron_autohotspot_file}" + fi + + # stop and clear services + if systemctl list-unit-files "${AUTOHOTSPOT_SERVICE}" >/dev/null 2>&1 ; then + sudo systemctl stop hostapd + sudo systemctl stop dnsmasq + sudo systemctl stop "${AUTOHOTSPOT_TIMER}" + sudo systemctl disable "${AUTOHOTSPOT_TIMER}" + sudo systemctl stop "${AUTOHOTSPOT_SERVICE}" + sudo systemctl disable "${AUTOHOTSPOT_SERVICE}" + sudo systemctl disable "${AUTOHOTSPOT_SERVICE_DAEMON}" + sudo rm "${AUTOHOTSPOT_SERVICE_PATH}" + sudo rm "${AUTOHOTSPOT_TIMER_PATH}" + sudo rm "${AUTOHOTSPOT_SERVICE_DAEMON_PATH}" + fi + + if [ -f "${AUTOHOTSPOT_TARGET_PATH}" ]; then + sudo rm "${AUTOHOTSPOT_TARGET_PATH}" + fi + + # remove config files + config_file_revert "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + config_file_revert "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + config_file_revert "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" + config_file_revert "${AUTOHOTSPOT_DHCPCD_CONF_FILE}" + config_file_revert "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" +} + + +_autohotspot_check_dhcpcd() { + print_verify_installation + + verify_apt_packages hostapd dnsmasq iw + + verify_service_enablement hostapd.service disabled + verify_service_enablement dnsmasq.service disabled + verify_service_enablement "${AUTOHOTSPOT_SERVICE_DAEMON}" enabled + verify_service_enablement "${AUTOHOTSPOT_SERVICE}" disabled + verify_service_enablement "${AUTOHOTSPOT_TIMER}" enabled + + verify_files_exists "${AUTOHOTSPOT_INTERFACES_CONF_FILE}" + + local ip_without_last_segment=$(_get_last_ip_segment $AUTOHOTSPOT_IP) + verify_files_exists "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + verify_file_contains_string "${WIFI_INTERFACE}" "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + verify_file_contains_string "dhcp-range=${ip_without_last_segment}" "${AUTOHOTSPOT_DNSMASQ_CONF_FILE}" + + verify_files_exists "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + verify_file_contains_string "interface=${WIFI_INTERFACE}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + verify_file_contains_string "ssid=${AUTOHOTSPOT_SSID}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + verify_file_contains_string "wpa_passphrase=${AUTOHOTSPOT_PASSWORD}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + verify_file_contains_string "country_code=${AUTOHOTSPOT_COUNTRYCODE}" "${AUTOHOTSPOT_HOSTAPD_CONF_FILE}" + + verify_files_exists "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" + verify_file_contains_string "DAEMON_CONF=\"${AUTOHOTSPOT_HOSTAPD_CONF_FILE}\"" "${AUTOHOTSPOT_HOSTAPD_DAEMON_CONF_FILE}" + + verify_files_exists "${AUTOHOTSPOT_DHCPCD_CONF_FILE}" + verify_file_contains_string "${AUTOHOTSPOT_DHCPCD_CONF_NOHOOK_WPA_SUPPLICANT}" "${AUTOHOTSPOT_DHCPCD_CONF_FILE}" + + verify_files_exists "${AUTOHOTSPOT_TARGET_PATH}" + verify_file_contains_string "wifidev=\"${WIFI_INTERFACE}\"" "${AUTOHOTSPOT_TARGET_PATH}" + verify_file_contains_string "hotspot_ip=${AUTOHOTSPOT_IP}" "${AUTOHOTSPOT_TARGET_PATH}" + verify_file_contains_string "daemon_service=\"${AUTOHOTSPOT_SERVICE_DAEMON}\"" "${AUTOHOTSPOT_TARGET_PATH}" + + + verify_files_exists "${AUTOHOTSPOT_SERVICE_DAEMON_PATH}" + verify_file_contains_string "\-i \"${WIFI_INTERFACE}\"" "${AUTOHOTSPOT_SERVICE_DAEMON_PATH}" + + verify_files_exists "${AUTOHOTSPOT_SERVICE_PATH}" + verify_file_contains_string "ExecStart=${AUTOHOTSPOT_TARGET_PATH}" "${AUTOHOTSPOT_SERVICE_PATH}" + + verify_files_exists "${AUTOHOTSPOT_TIMER_PATH}" + verify_file_contains_string "Unit=${AUTOHOTSPOT_SERVICE}" "${AUTOHOTSPOT_TIMER_PATH}" +} + +_run_setup_autohotspot_dhcpcd() { + log "Install AutoHotspot dhcpcd" + _install_packages_dhcpcd + _get_interface + _uninstall_autohotspot_dhcpcd + _install_autohotspot_dhcpcd + _autohotspot_check_dhcpcd +} diff --git a/resources/autohotspot/NetworkManager/autohotspot b/resources/autohotspot/NetworkManager/autohotspot new file mode 100644 index 000000000..992190376 --- /dev/null +++ b/resources/autohotspot/NetworkManager/autohotspot @@ -0,0 +1,353 @@ +#!/bin/bash +#version 0.8 +#date 12 Dec 2023 +#Copyright Graeme Richards - RaspberryConnect.com +#Released under the GPL3 Licence (https://www.gnu.org/licenses/gpl-3.0.en.html) + +#Script to automatically switch to an Access Point when no Wifi connection is available +#Developed on a Raspberry Pi PiOS Bookworm for use with Network Manager + +#Additions where made for the Phoniebox project +#https://github.com/MiczFlor/RPi-Jukebox-RFID + +#Device Names +wdev0='%%WIFI_INTERFACE%%' #wifi device that AP will work on + +#AP setup +ap_profile_name='%%AUTOHOTSPOT_PROFILE%%' +ap_ssid='%%AUTOHOTSPOT_SSID%%' +ap_pw='%%AUTOHOTSPOT_PASSWORD%%' +ap_ip='%%AUTOHOTSPOT_IP%%/24' +ap_gate='%%IP_WITHOUT_LAST_SEGMENT%%.254' + +timer_service_name='%%AUTOHOTSPOT_TIMER_NAME%%' + +#If wifi is disabled in Network Manager, then enable it automatically. +#if set to 'false' then wifi will stay off and no AccessPoint will be generated or Network Connection will be available. +re_enable_wifi=false + +#If true, check if timer is active. Will have been disabled if arg -a used. +re_enable_timer=false + +#************************************* +#*****No user editable lines below**** + +NO_SSID='NoSSid' + +profiles=() #Currently Available Profiles +active="" #The active connection +active_ap=false #is the active profile an AP y/n +nw_profile=() #saved NW Profiles +ap_profile=() #The saved AP profiles +ssidChk=("$NO_SSID") +force_hotspot=false + +#Function is NM installed and running +check_prerequisite() { + if systemctl -all list-unit-files NetworkManager.service | grep "could not be found" >/dev/null 2>&1 ;then + if systemctl -all list-unit-files dhcpcd.service | grep "(running)" >/dev/null 2>&1 ;then + echo "This script is not compatible with the network setup." + echo "Please use the dhcpcd version" + else + echo "Network Manager is not managing the Wifi on this device" + echo "Unable to continue." + fi + exit 1 + else + local isnm="$( systemctl status NetworkManager | grep '(running)' )" + if echo "$isnm" | grep -v "(running)" ;then >/dev/null 2>&1; #NM not running + echo "Network Manager is required but is not the active system network service" + echo "Unable to continue." + exit 1 + fi + fi +} + +#Function get all wifi profiles +saved_profiles() +{ + ap_profile=() + nw_profile=() + local n="$(nmcli -t -f TYPE,NAME,AUTOCONNECT-PRIORITY con show)" #Capture Output + n="$(awk 1 ORS=':' <(echo "$n"))" #Replaces LF with : Delimeter + local profiles=() + readarray -d ':' -t profiles < <(printf "%s" "$n") #Change to array output + if [ ! -z "$profiles" ]; then + for (( c=0; c<=${#profiles[@]}; c+=3 )) #array of profiles + do + if [ ! -z "${profiles[$c+1]}" ] ; then + local conn="$(nmcli con show "${profiles[$c+1]}" | grep 'wireless.mode')" #show mode infurstructure, AP + local mode=() + readarray -d ':' -t mode < <(printf "%s" "$conn") + local mode2="$(echo "${mode[1]}" | sed 's/[[:blank:]]//g')" + if [ "$mode2" = "ap" ]; then + ap_profile+=("${profiles[$c+1]}") + echo "AP Profile: ${profiles[$c+1]}" + elif [ "$mode2" = "infrastructure" ]; then + nw_profile+=("${profiles[$c+1]}") + echo "NW Profile: ${profiles[$c+1]}" + fi + fi + done + fi +} + +#Function what is the current active wifi +active_wifi() +{ + local act="$(nmcli -t -f TYPE,NAME,DEVICE con show --active | grep "$wdev0")" #List of active devices + act="$(awk 1 ORS=':' <(echo "$act"))" #Replaces LF with : Delimeter + local active_name=() + readarray -d ':' -t active_name < <(printf "%s" "$act") #Change to array output + if [ ! -z "$active_name" ]; then + active="${active_name[1]}" + else + active="" + fi +} + +#Function is the current Connection an AP +is_active_ap() +{ + active_ap=false + if [ ! -z "$active" ] ; then + for i in "${ap_profile[@]}" + do + if [[ $i == "$active" ]]; then + active_ap=true + break + fi + done + fi +} + +#Function IW SSID scan +nearby_ssids_iw() +{ + if [ ${#nw_profile[@]} -eq 0 ]; then #only scan if NW profiles exists# + return + fi + + #Check to see what SSID's and MAC addresses are in range + echo "SSID availability check" + local i=0; j=0 + while [ $i -eq 0 ] + do + local scanreply=$(iw dev "$wdev0" scan ap-force 2>&1) + local ssidreply=$(echo "$scanreply" | egrep "^BSS|SSID:") + if [ $j -ge 5 ]; then + ssidreply="" + i=1 + elif [ -z "$ssidreply" ] ; then + echo "Error scan SSID's, try $j: $scanreply" + j=$((j + 1)) + sleep 2 + else + #success + i=1 + fi + done + + ssidChk=() + for profile in "${nw_profile[@]}" + do + echo "Assessing profile: ${profile}" + local idssid=$(nmcli -t con show "${profile}" | grep "wireless.ssid") + if (echo "$ssidreply" | grep -F -- "${idssid:21}" ) >/dev/null 2>&1 + then + echo "Valid SSID detected, assessing Wifi status" + ssidChk+="${profile}" + fi + done + + if [ "${#ssidChk[@]}" -eq 0 ]; then + echo "No Valid SSID detected" + ssidChk+="$NO_SSID" + fi +} + +check_device() +{ + echo "Device availability check" + local j=0 + while [ true ] #wait for wifi if busy, usb wifi is slower. + do + if [ $j -ge 5 ]; then + echo "No wifi device '$wdev0' connected" + exit 1 + elif (nmcli device show "$wdev0" 2>&1 >/dev/null) ; then + echo "Wifi device '$wdev0' available" + if (rfkill list wifi -rno HARD,SOFT | grep -i "unblocked.*unblocked") >/dev/null 2>&1 ; then + return + else + if [[ $re_enable_wifi = true ]] ; then + nmcli radio wifi on + echo "Wifi has been re-activated" + sleep 10 #delay to allow wifi to initialise + return + else + echo "Wifi is deactivated" + exit 0 + fi + fi + else + j=$((j + 1)) + sleep 2 + fi + done +} + +#Activate AP profile +start_ap() +{ + local ex=0 + for i in "${ap_profile[@]}" + do + if [[ $i == "$ap_profile_name" ]]; then + ex=1 #known saved AP profile is available + break + fi + done + if [ $ex -eq 0 ];then + ap_new_profile #if known AP profile not found, create it + fi + nmcli con up "$ap_profile_name" >/dev/null 2>&1 + sleep 3 #give time for ap to be setup + active_wifi + is_active_ap + if [ "$active_ap" = true ]; then + echo "Access Point started" + local curip="$(nmcli -t con show $active | grep IP4.ADDRESS)" + readarray -d ':' -t ipid < <(printf "%s" "$curip") + local showip="$(echo "${ipid[1]}" | sed 's/[[:blank:]]//g')" + if [ ! -z $showip ]; then + echo "AP on IP Address ${showip::-3}" + fi + else + echo "AP failed to be created." + fi +} + +#Activate NW profile +start_nw() +{ + if [ "$active_ap" = true ]; then + echo "The active profile is $active. Shutting down" + nmcli con down "$active" >/dev/null 2>&1 + fi + + local active_nw="" + for i in "${nw_profile[@]}" + do + echo "Checking: $i" + con="$(nmcli con up $i)" + if ( echo "$con" | grep 'Connection successfully activated' ) >/dev/null 2>&1; then + echo "Connection was good" + active_wifi + active_nw="$active" + elif ( echo "$con" | grep 'Connection activation failed' ) >/dev/null 2>&1; then + echo "Unable to make a connection. Check the password is ok for the ssid ${nw_profile[$c]}" + active_nw="" + else + echo "Unable to confirm the connection status" + active_nw="" + fi + if [ ! -z "$active_nw" ] ;then + echo "A valid connection has been made with $i" + break + fi + done + + if [ -z "$active_nw" ] ;then + echo "A network connection has not been made with any known ssid. Activating access point" + start_ap + fi +} + +#Function Create AP profile +ap_new_profile() +{ + echo "Create a AP profile ${ap_profile_name}" + nmcli device wifi hotspot ifname $wdev0 con-name "$ap_profile_name" ssid "$ap_ssid" band bg password "$ap_pw" >/dev/null 2>&1 + nmcli con mod "$ap_profile_name" ipv4.method shared ipv4.addr "$ap_ip" ipv4.gateway "$ap_gate" >/dev/null 2>&1 + ap_profile+=("$ap_profile_name") +} + +#Main +check_prerequisite +check_device + +while getopts "aht" opt; do + case $opt in + a ) + force_hotspot=true + ;; + t ) + re_enable_timer=true + ;; + h ) + sc="$(basename $0)" + echo -e "\nby default the $sc script will setup a connection to a WiFi network where a profile exists" + echo "otherwise an Access Point called $ap_ssid will be created. Using ip address $ap_ip" + echo "The local wifi signals will be check every 2 minutes. If a known SSID comes into range" + echo "the Access Point will be shutdown and a connection to the Wifi network will be made." + echo "using sudo $sc -a will activate the Access Point regardless of any existing WiFi profile" + echo "and stop the timed checks. Use sudo $sc to return to normal use." + exit + ;; + * ) + echo "option not valid" + exit + ;; + esac +done + +saved_profiles #get list of saved profile +active_wifi +is_active_ap +echo -e "The active profile is $active\n" + +if [ "$force_hotspot" = true ]; then + if [ ! "$active_ap" = true ]; then + systemctl stop "$timer_service_name" + start_ap + elif [ ! "$active" = "$ap_profile_name" ]; then #Other AP is running, swap to this one + nmcli con down "$active" + start_ap + else + echo "Access Point $active is already running" + fi +else + if [ ! -z "$active" ]; then #Active Profile Yes + if [ "$active_ap" = true ]; then #Yes it's an AP profile + nearby_ssids_iw #scan for nearby SSID's + if [ "${ssidChk[0]}" != "$NO_SSID" ]; then #known ssid in range + start_nw + elif [ ! "$active" = "$ap_profile_name" ]; then #Other AP is running, swap to this one + nmcli con down "$active" + start_ap + fi + fi + else #no active profile + nearby_ssids_iw #scan for nearby SSID's + if [ "${ssidChk[0]}" != "$NO_SSID" ]; then #known ssid in range + start_nw + else + start_ap + fi + fi + + if [[ $re_enable_timer = true ]] ; then + #check if timer is active. Will have been disabled if arg -a used. + tup="$(systemctl list-timers | grep '${timer_service_name}')" + if [ -z "$tup" ];then + systemctl start "$timer_service_name" + echo "Reactivated timer" + fi + fi +fi + +active_wifi +is_active_ap +echo -e "\nThe Wifi profile in use is: $active" +echo -e "Is this a local access point? $active_ap\n" diff --git a/resources/autohotspot/NetworkManager/autohotspot.service b/resources/autohotspot/NetworkManager/autohotspot.service new file mode 100644 index 000000000..ff808cd9e --- /dev/null +++ b/resources/autohotspot/NetworkManager/autohotspot.service @@ -0,0 +1,11 @@ +[Unit] +Description=Automatically generates an wifi hotspot when a valid SSID is not in range +After=multi-user.target +Requires=network-online.target + +[Service] +Type=simple +ExecStart=%%AUTOHOTSPOT_SCRIPT%% + +[Install] +WantedBy=multi-user.target diff --git a/resources/autohotspot/NetworkManager/autohotspot.timer b/resources/autohotspot/NetworkManager/autohotspot.timer new file mode 100644 index 000000000..dc7427170 --- /dev/null +++ b/resources/autohotspot/NetworkManager/autohotspot.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer to run the %%AUTOHOTSPOT_SERVICE%% every 2 mins + +[Timer] +OnBootSec=0min +OnCalendar=*:0/2 +Unit=%%AUTOHOTSPOT_SERVICE%% + +[Install] +WantedBy=timers.target diff --git a/resources/autohotspot/autohotspot b/resources/autohotspot/autohotspot deleted file mode 100644 index 92cb7eebc..000000000 --- a/resources/autohotspot/autohotspot +++ /dev/null @@ -1,193 +0,0 @@ -#!/bin/bash -#version 0.961-N/HS - -#You may share this script on the condition a reference to RaspberryConnect.com -#must be included in copies or derivatives of this script. - -#A script to switch between a wifi network and a non internet routed Hotspot -#Works at startup or with a seperate timer or manually without a reboot -#Other setup required find out more at -#http://www.raspberryconnect.com - -wifidev="wlan0" #device name to use. Default is wlan0. -#use the command: iw dev ,to see wifi interface name - -IFSdef=$IFS -cnt=0 -#These four lines capture the wifi networks the RPi is setup to use -wpassid=$(awk '/ssid="/{ print $0 }' /etc/wpa_supplicant/wpa_supplicant.conf | awk -F'ssid=' '{ print $2 }' | sed 's/\r//g'| awk 'BEGIN{ORS=","} {print}' | sed 's/\"/''/g' | sed 's/,$//') -IFS="," -ssids=($wpassid) -IFS=$IFSdef #reset back to defaults - - -#Note:If you only want to check for certain SSIDs -#Remove the # in in front of ssids=('mySSID1'.... below and put a # infront of all four lines above -# separated by a space, eg ('mySSID1' 'mySSID2') -#ssids=('mySSID1' 'mySSID2' 'mySSID3') - -#Enter the Routers Mac Addresses for hidden SSIDs, seperated by spaces ie -#( '11:22:33:44:55:66' 'aa:bb:cc:dd:ee:ff' ) -mac=() - -ssidsmac=("${ssids[@]}" "${mac[@]}") #combines ssid and MAC for checking - -createAdHocNetwork() -{ - echo "Creating Hotspot" - ip link set dev "$wifidev" down - ip a add 10.0.0.5/24 brd + dev "$wifidev" - ip link set dev "$wifidev" up - dhcpcd -k "$wifidev" >/dev/null 2>&1 - systemctl start dnsmasq - systemctl start hostapd -} - -KillHotspot() -{ - echo "Shutting Down Hotspot" - ip link set dev "$wifidev" down - systemctl stop hostapd - systemctl stop dnsmasq - ip addr flush dev "$wifidev" - ip link set dev "$wifidev" up - dhcpcd -n "$wifidev" >/dev/null 2>&1 -} - -ChkWifiUp() -{ - echo "Checking WiFi connection ok" - sleep 20 #give time for connection to be completed to router - if ! wpa_cli -i "$wifidev" status | grep 'ip_address' >/dev/null 2>&1 - then #Failed to connect to wifi (check your wifi settings, password etc) - echo 'Wifi failed to connect, falling back to Hotspot.' - wpa_cli terminate "$wifidev" >/dev/null 2>&1 - createAdHocNetwork - fi -} - - -chksys() -{ - #After some system updates hostapd gets masked using Raspbian Buster, and above. This checks and fixes - #the issue and also checks dnsmasq is ok so the hotspot can be generated. - #Check Hostapd is unmasked and disabled - if systemctl -all list-unit-files hostapd.service | grep "hostapd.service masked" >/dev/null 2>&1 ;then - systemctl unmask hostapd.service >/dev/null 2>&1 - fi - if systemctl -all list-unit-files hostapd.service | grep "hostapd.service enabled" >/dev/null 2>&1 ;then - systemctl disable hostapd.service >/dev/null 2>&1 - systemctl stop hostapd >/dev/null 2>&1 - fi - #Check dnsmasq is disabled - if systemctl -all list-unit-files dnsmasq.service | grep "dnsmasq.service masked" >/dev/null 2>&1 ;then - systemctl unmask dnsmasq >/dev/null 2>&1 - fi - if systemctl -all list-unit-files dnsmasq.service | grep "dnsmasq.service enabled" >/dev/null 2>&1 ;then - systemctl disable dnsmasq >/dev/null 2>&1 - systemctl stop dnsmasq >/dev/null 2>&1 - fi -} - - -FindSSID() -{ -#Check to see what SSID's and MAC addresses are in range -ssidChk=('NoSSid') -i=0; j=0 -until [ $i -eq 1 ] #wait for wifi if busy, usb wifi is slower. -do - ssidreply=$((iw dev "$wifidev" scan ap-force | egrep "^BSS|SSID:") 2>&1) >/dev/null 2>&1 - #echo "SSid's in range: " $ssidreply - printf '%s\n' "${ssidreply[@]}" - echo "Device Available Check try " $j - if (($j >= 10)); then #if busy 10 times goto hotspot - echo "Device busy or unavailable 10 times, going to Hotspot" - ssidreply="" - i=1 - elif echo "$ssidreply" | grep "No such device (-19)" >/dev/null 2>&1; then - echo "No Device Reported, try " $j - NoDevice - elif echo "$ssidreply" | grep "Network is down (-100)" >/dev/null 2>&1 ; then - echo "Network Not available, trying again" $j - j=$((j + 1)) - sleep 2 - elif echo "$ssidreply" | grep "Read-only file system (-30)" >/dev/null 2>&1 ; then - echo "Temporary Read only file system, trying again" - j=$((j + 1)) - sleep 2 - elif echo "$ssidreply" | grep "Invalid exchange (-52)" >/dev/null 2>&1 ; then - echo "Temporary unavailable, trying again" - j=$((j + 1)) - sleep 2 - elif echo "$ssidreply" | grep -v "resource busy (-16)" >/dev/null 2>&1 ; then - echo "Device Available, checking SSid Results" - i=1 - else #see if device not busy in 2 seconds - echo "Device unavailable checking again, try " $j - j=$((j + 1)) - sleep 2 - fi -done - -for ssid in "${ssidsmac[@]}" -do - if (echo "$ssidreply" | grep -F -- "$ssid") >/dev/null 2>&1 - then - #Valid SSid found, passing to script - echo "Valid SSID Detected, assesing Wifi status" - ssidChk=$ssid - return 0 - else - #No Network found, NoSSid issued" - echo "No SSid found, assessing WiFi status" - ssidChk='NoSSid' - fi -done -} - -NoDevice() -{ - #if no wifi device,ie usb wifi removed, activate wifi so when it is - #reconnected wifi to a router will be available - echo "No wifi device connected" - wpa_supplicant -B -i "$wifidev" -c /etc/wpa_supplicant/wpa_supplicant.conf >/dev/null 2>&1 - exit 1 -} - -chksys -FindSSID - -#Create Hotspot or connect to valid wifi networks -if [ "$ssidChk" != "NoSSid" ] -then - if systemctl status hostapd | grep "(running)" >/dev/null 2>&1 - then #hotspot running and ssid in range - KillHotspot - echo "Hotspot Deactivated, Bringing Wifi Up" - wpa_supplicant -B -i "$wifidev" -c /etc/wpa_supplicant/wpa_supplicant.conf >/dev/null 2>&1 - ChkWifiUp - elif { wpa_cli -i "$wifidev" status | grep 'ip_address'; } >/dev/null 2>&1 - then #Already connected - echo "Wifi already connected to a network" - else #ssid exists and no hotspot running connect to wifi network - echo "Connecting to the WiFi Network" - wpa_supplicant -B -i "$wifidev" -c /etc/wpa_supplicant/wpa_supplicant.conf >/dev/null 2>&1 - ChkWifiUp - fi -else #ssid or MAC address not in range - if systemctl status hostapd | grep "(running)" >/dev/null 2>&1 - then - echo "Hostspot already active" - elif { wpa_cli status | grep "$wifidev"; } >/dev/null 2>&1 - then - echo "Cleaning wifi files and Activating Hotspot" - wpa_cli terminate >/dev/null 2>&1 - ip addr flush "$wifidev" - ip link set dev "$wifidev" down - rm -r /var/run/wpa_supplicant >/dev/null 2>&1 - createAdHocNetwork - else #"No SSID, activating Hotspot" - createAdHocNetwork - fi -fi diff --git a/resources/autohotspot/autohotspot.service b/resources/autohotspot/autohotspot.service deleted file mode 100644 index 13d9101b4..000000000 --- a/resources/autohotspot/autohotspot.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Automatically generates an internet Hotspot when a valid ssid is not in range -After=multi-user.target - -[Service] -Type=oneshot -RemainAfterExit=yes -ExecStart=/usr/bin/autohotspot - -[Install] -WantedBy=multi-user.target diff --git a/resources/autohotspot/autohotspot.timer b/resources/autohotspot/autohotspot.timer deleted file mode 100644 index eb2acaebe..000000000 --- a/resources/autohotspot/autohotspot.timer +++ /dev/null @@ -1,3 +0,0 @@ -# cron timer for autohotspot -*/5 * * * * %%USER%% sudo /usr/bin/autohotspot 2>&1 | logger -t autohotspot -@reboot %%USER%% sudo /usr/bin/autohotspot 2>&1 | logger -t autohotspot diff --git a/resources/autohotspot/dhcpcd/autohotspot b/resources/autohotspot/dhcpcd/autohotspot new file mode 100644 index 000000000..a7388512e --- /dev/null +++ b/resources/autohotspot/dhcpcd/autohotspot @@ -0,0 +1,228 @@ +#!/usr/bin/env bash +#version 0.962-N/HS + +#You may share this script on the condition all references to RaspberryConnect.com +#must be included in copies or derivatives of this script. + +#A script to switch between a wifi network and a non internet routed Hotspot +#Works at startup or with a seperate timer or manually without a reboot +#Other setup required find out more at +#http://www.raspberryconnect.com + +#Additions where made for the Phoniebox project +#https://github.com/MiczFlor/RPi-Jukebox-RFID + +while getopts "a" opt; do + case $opt in + a ) + FORCE_HOTSPOT=true + ;; + * ) + echo "option not valid" + exit + ;; + esac +done + +NO_SSID='NoSSid' +ssidChk="$NO_SSID" + +wifidev="%%WIFI_INTERFACE%%" #device name to use. +#use the command: iw dev ,to see wifi interface name +hotspot_ip=%%AUTOHOTSPOT_IP%% +daemon_service="%%AUTOHOTSPOT_SERVICE_DAEMON%%" + +IFSdef=$IFS +cnt=0 +#These four lines capture the wifi networks the RPi is setup to use +wpassid=$(awk '/ssid="/{ print $0 }' /etc/wpa_supplicant/wpa_supplicant.conf | awk -F'ssid=' '{ print $2 }' | sed 's/\r//g'| awk 'BEGIN{ORS=","} {print}' | sed 's/\"/''/g' | sed 's/,$//') +IFS="," +ssids=($wpassid) +IFS=$IFSdef #reset back to defaults + + +#Note:If you only want to check for certain SSIDs +#Remove the # in in front of ssids=('mySSID1'.... below and put a # infront of all four lines above +# separated by a space, eg ('mySSID1' 'mySSID2') +#ssids=('mySSID1' 'mySSID2' 'mySSID3') + +#Enter the Routers Mac Addresses for hidden SSIDs, seperated by spaces ie +#( '11:22:33:44:55:66' 'aa:bb:cc:dd:ee:ff' ) +mac=() + +ssidsmac=("${ssids[@]}" "${mac[@]}") #combines ssid and MAC for checking + +CreateAdHocNetwork() +{ + echo "Creating Hotspot" + ip link set dev "$wifidev" down + ip a add "$hotspot_ip"/24 brd + dev "$wifidev" + ip link set dev "$wifidev" up + dhcpcd -k "$wifidev" >/dev/null 2>&1 + systemctl start dnsmasq + systemctl start hostapd +} + +KillHotspot() +{ + echo "Shutting Down Hotspot" + ip link set dev "$wifidev" down + systemctl stop hostapd + systemctl stop dnsmasq + ip addr flush dev "$wifidev" + ip link set dev "$wifidev" up + dhcpcd -n "$wifidev" >/dev/null 2>&1 +} + +CheckWifiUp() +{ + echo "Checking WiFi connection ok" + sleep 20 #give time for connection to be completed to router + if ! wpa_cli -i "$wifidev" status | grep 'ip_address' >/dev/null 2>&1 + then #Failed to connect to wifi (check your wifi settings, password etc) + echo 'Wifi failed to connect, falling back to Hotspot.' + wpa_cli terminate "$wifidev" >/dev/null 2>&1 + CreateAdHocNetwork + fi +} + +InitWPA() { + systemctl restart "$daemon_service" +} + +CheckServices() +{ + #After some system updates hostapd gets masked using Raspbian Buster, and above. This checks and fixes + #the issue and also checks dnsmasq is ok so the hotspot can be generated. + #Check Hostapd is unmasked and disabled + if (systemctl -all list-unit-files hostapd.service | grep "hostapd.service masked") >/dev/null 2>&1 ;then + systemctl unmask hostapd.service >/dev/null 2>&1 + fi + if (systemctl -all list-unit-files hostapd.service | grep "hostapd.service enabled") >/dev/null 2>&1 ;then + systemctl disable hostapd.service >/dev/null 2>&1 + systemctl stop hostapd >/dev/null 2>&1 + fi + #Check dnsmasq is disabled + if (systemctl -all list-unit-files dnsmasq.service | grep "dnsmasq.service masked") >/dev/null 2>&1 ;then + systemctl unmask dnsmasq >/dev/null 2>&1 + fi + if (systemctl -all list-unit-files dnsmasq.service | grep "dnsmasq.service enabled") >/dev/null 2>&1 ;then + systemctl disable dnsmasq >/dev/null 2>&1 + systemctl stop dnsmasq >/dev/null 2>&1 + fi +} + +CheckDevice() +{ + echo "Device availability check" + local j=0 + while [ true ] #wait for wifi if busy, usb wifi is slower. + do + + if [ $j -ge 5 ]; then + #if no wifi device,ie usb wifi removed, activate wifi so when it is + #reconnected wifi to a router will be available + echo "No wifi device '$wifidev' connected" + InitWPA + exit 1 + elif (iw dev "$wifidev" info 2>&1 >/dev/null) ; then + echo "Wifi device '$wifidev' available" + if (rfkill list wifi -rno HARD,SOFT | grep -i "unblocked.*unblocked") >/dev/null 2>&1 ; then + local wifidev_up=$(ip link show "$wifidev" up) + if [ -z "$wifidev_up" ]; then + echo "Wifi is down. Setting up" + ip link set dev "$wifidev" up + sleep 2 + fi + return + else + echo "Wifi is deactivated" + exit 0 + fi + else + j=$((j + 1)) + sleep 2 + fi + done +} + +FindSSID() +{ + if [ -n "$FORCE_HOTSPOT" ]; then return; fi + + #Check to see what SSID's and MAC addresses are in range + echo "SSID availability check" + local i=0; j=0 + while [ $i -eq 0 ] + do + scanreply=$(iw dev "$wifidev" scan ap-force 2>&1) + ssidreply=$(echo "$scanreply" | egrep "^BSS|SSID:") + if [ $j -ge 5 ]; then + ssidreply="" + i=1 + elif [ -z "$ssidreply" ] ; then + echo "Error scan SSID's, try $j: $scanreply" + j=$((j + 1)) + sleep 2 + else + #success + i=1 + fi + done + + for ssid in "${ssidsmac[@]}" + do + if (echo "$ssidreply" | grep "$ssid") >/dev/null 2>&1 + then + echo "Valid SSID detected, assessing Wifi status" + ssidChk=$ssid + break + fi + done + + if [ "$ssidChk" == "$NO_SSID" ]; then + echo "No Valid SSID detected" + fi +} + +CheckSSID() +{ + #Create Hotspot or connect to valid wifi networks + if [ "$ssidChk" != "$NO_SSID" ] + then + if systemctl status hostapd | grep "(running)" >/dev/null 2>&1 + then #hotspot running and ssid in range + KillHotspot + echo "Hotspot Deactivated, Bringing Wifi Up" + InitWPA + CheckWifiUp + elif { wpa_cli -i "$wifidev" status | grep 'ip_address'; } >/dev/null 2>&1 + then #Already connected + echo "Wifi already connected to a network" + else #ssid exists and no hotspot running connect to wifi network + echo "Connecting to the WiFi Network" + InitWPA + CheckWifiUp + fi + else #ssid or MAC address not in range + if systemctl status hostapd | grep "(running)" >/dev/null 2>&1 + then + echo "Hostspot already active" + elif { wpa_cli status | grep "$wifidev"; } >/dev/null 2>&1 + then + echo "Cleaning wifi files and Activating Hotspot" + wpa_cli terminate >/dev/null 2>&1 + ip addr flush "$wifidev" + ip link set dev "$wifidev" down + rm -r /var/run/wpa_supplicant >/dev/null 2>&1 + CreateAdHocNetwork + else #"No SSID, activating Hotspot" + CreateAdHocNetwork + fi + fi +} + +CheckServices +CheckDevice +FindSSID +CheckSSID diff --git a/resources/autohotspot/dhcpcd/autohotspot-daemon.service b/resources/autohotspot/dhcpcd/autohotspot-daemon.service new file mode 100644 index 000000000..5906a4840 --- /dev/null +++ b/resources/autohotspot/dhcpcd/autohotspot-daemon.service @@ -0,0 +1,10 @@ +[Unit] +Description=Daemon for regular network connection if no hotspot is created +After=multi-user.target + +[Service] +Type=simple +ExecStart=wpa_supplicant -i "%%WIFI_INTERFACE%%" -c /etc/wpa_supplicant/wpa_supplicant.conf + +[Install] +WantedBy=multi-user.target diff --git a/resources/autohotspot/dhcpcd/autohotspot.service b/resources/autohotspot/dhcpcd/autohotspot.service new file mode 100644 index 000000000..ff808cd9e --- /dev/null +++ b/resources/autohotspot/dhcpcd/autohotspot.service @@ -0,0 +1,11 @@ +[Unit] +Description=Automatically generates an wifi hotspot when a valid SSID is not in range +After=multi-user.target +Requires=network-online.target + +[Service] +Type=simple +ExecStart=%%AUTOHOTSPOT_SCRIPT%% + +[Install] +WantedBy=multi-user.target diff --git a/resources/autohotspot/dhcpcd/autohotspot.timer b/resources/autohotspot/dhcpcd/autohotspot.timer new file mode 100644 index 000000000..dc7427170 --- /dev/null +++ b/resources/autohotspot/dhcpcd/autohotspot.timer @@ -0,0 +1,10 @@ +[Unit] +Description=Timer to run the %%AUTOHOTSPOT_SERVICE%% every 2 mins + +[Timer] +OnBootSec=0min +OnCalendar=*:0/2 +Unit=%%AUTOHOTSPOT_SERVICE%% + +[Install] +WantedBy=timers.target diff --git a/resources/autohotspot/dhcpcd/dnsmasq.conf b/resources/autohotspot/dhcpcd/dnsmasq.conf new file mode 100644 index 000000000..da0ba46ef --- /dev/null +++ b/resources/autohotspot/dhcpcd/dnsmasq.conf @@ -0,0 +1,7 @@ +#AutoHotspot Config +#stop DNSmasq from using resolv.conf +no-resolv +#Interface to use +interface=%%WIFI_INTERFACE%% +bind-interfaces +dhcp-range=%%IP_WITHOUT_LAST_SEGMENT%%.100,%%IP_WITHOUT_LAST_SEGMENT%%.200,12h diff --git a/resources/autohotspot/dhcpcd/hostapd b/resources/autohotspot/dhcpcd/hostapd new file mode 100644 index 000000000..92798c162 --- /dev/null +++ b/resources/autohotspot/dhcpcd/hostapd @@ -0,0 +1,20 @@ +# Defaults for hostapd initscript +# +# See /usr/share/doc/hostapd/README.Debian for information about alternative +# methods of managing hostapd. +# +# Uncomment and set DAEMON_CONF to the absolute path of a hostapd configuration +# file and hostapd will be started during system boot. An example configuration +# file can be found at /usr/share/doc/hostapd/examples/hostapd.conf.gz +# +DAEMON_CONF="%%HOSTAPD_CONF%%" + +# Additional daemon options to be appended to hostapd command:- +# -d show more debug messages (-dd for even more) +# -K include key data in debug messages +# -t include timestamps in some debug messages +# +# Note that -B (daemon mode) and -P (pidfile) options are automatically +# configured by the init.d script and must not be added to DAEMON_OPTS. +# +#DAEMON_OPTS="" diff --git a/resources/autohotspot/hostapd.conf b/resources/autohotspot/dhcpcd/hostapd.conf similarity index 66% rename from resources/autohotspot/hostapd.conf rename to resources/autohotspot/dhcpcd/hostapd.conf index 8860368a4..4edc8f045 100644 --- a/resources/autohotspot/hostapd.conf +++ b/resources/autohotspot/dhcpcd/hostapd.conf @@ -1,7 +1,7 @@ #2.4GHz setup wifi 80211 b,g,n -interface=WIFI_INTERFACE +interface=%%WIFI_INTERFACE%% driver=nl80211 -ssid=Phoniebox_Hotspot +ssid=%%AUTOHOTSPOT_SSID%% hw_mode=g channel=8 wmm_enabled=0 @@ -9,12 +9,12 @@ macaddr_acl=0 auth_algs=1 ignore_broadcast_ssid=0 wpa=2 -wpa_passphrase=AUTOHOTSPOT_PASSWORD +wpa_passphrase=%%AUTOHOTSPOT_PASSWORD%% wpa_key_mgmt=WPA-PSK wpa_pairwise=CCMP TKIP rsn_pairwise=CCMP #80211n - Change GB to your WiFi country code -country_code=WIFI_REGION +country_code=%%AUTOHOTSPOT_COUNTRYCODE%% ieee80211n=1 ieee80211d=1 diff --git a/src/cli_client/pbc.c b/src/cli_client/pbc.c index 0b5cfb762..7f39c493e 100644 --- a/src/cli_client/pbc.c +++ b/src/cli_client/pbc.c @@ -44,7 +44,7 @@ #define MAX_PARAMS 16 int g_verbose = 0; -typedef struct +typedef struct { char object [MAX_STRLEN]; char package [MAX_STRLEN]; @@ -61,44 +61,44 @@ int send_zmq_request_and_wait_response(char * request, int request_len, char * r void *context = zmq_ctx_new (); void *requester = zmq_socket (context, ZMQ_REQ); int linger = 200; - + if (g_verbose) { int major, minor, patch; zmq_version (&major, &minor, &patch); printf ("Current ØMQ version is %d.%d.%d\n", major, minor, patch); } - + zmq_setsockopt(requester,ZMQ_LINGER,&linger,sizeof(linger)); zmq_setsockopt(requester,ZMQ_RCVTIMEO,&linger,sizeof(linger)); zmq_connect (requester, address); if (g_verbose) printf("connected to: %s",address); - + zmq_ret = zmq_send (requester, request, request_len, 0); if (zmq_ret > 0) { zmq_ret = zmq_recv (requester, response, max_response_len, 0); - + if (zmq_ret > 0) { - printf ("Received %s (%d Bytes)\n", response,zmq_ret); + printf ("Received %s (%d Bytes)\n", response,zmq_ret); ret = 0; } else { - printf ("zmq_recv rturned %d \n", zmq_ret); + printf ("zmq_recv rturned %d \n", zmq_ret); } } else { - if (g_verbose) printf ("zmq_send returned %d\n", zmq_ret); + if (g_verbose) printf ("zmq_send returned %d\n", zmq_ret); } zmq_close (requester); - zmq_ctx_destroy (context); + zmq_ctx_destroy (context); return (ret); } @@ -114,7 +114,7 @@ void * connect_and_send_request(t_request * tr) if (tr->num_params > 0) { sprintf(kwargs, "\"kwargs\":{"); - + for (n = 0;n < tr->num_params;) { strcat(kwargs,tr->params[n]); @@ -129,7 +129,7 @@ void * connect_and_send_request(t_request * tr) snprintf(json_request,MAX_REQEST_STRLEN,"{\"package\": \"%s\", \"plugin\": \"%s\", \"method\": \"%s\", %s\"id\":%d}",tr->package,tr->object,tr->method,kwargs,123); json_len = strlen(json_request); - + if (g_verbose) printf("Sending Request (%ld Bytes):\n%s\n",json_len,json_request); send_zmq_request_and_wait_response(json_request,json_len,json_response,MAX_REQEST_STRLEN,tr->address); @@ -177,7 +177,7 @@ int HandleOptions(int argc,char *argv[], t_request * tr) { int c; sprintf(tr->address,"tcp://localhost:5555"); - + const struct option long_options[] = { /* These options set a flag. */ @@ -213,7 +213,7 @@ int HandleOptions(int argc,char *argv[], t_request * tr) break; case 'p': strncpy (tr->package,optarg,MAX_STRLEN); - break; + break; case 'o': strncpy (tr->object,optarg,MAX_STRLEN); break; @@ -229,7 +229,7 @@ int HandleOptions(int argc,char *argv[], t_request * tr) case 'a': strncpy (tr->address,optarg,MAX_STRLEN); break; - + default: usage(); abort (); @@ -240,7 +240,7 @@ int HandleOptions(int argc,char *argv[], t_request * tr) if (optind < argc) { while (optind < argc) - { + { check_and_map_parameters_to_json(argv[optind++], tr); } } @@ -256,6 +256,6 @@ int main(int argc,char *argv[]) HandleOptions(argc,argv,&tr); connect_and_send_request(&tr); - + return 0; } diff --git a/src/jukebox/components/hostif/linux/__init__.py b/src/jukebox/components/hostif/linux/__init__.py index 32dfded08..6a6590ad6 100644 --- a/src/jukebox/components/hostif/linux/__init__.py +++ b/src/jukebox/components/hostif/linux/__init__.py @@ -238,7 +238,7 @@ def get_autohotspot_status(): if os.path.isfile("/etc/systemd/system/autohotspot.service"): status = 'inactive' - ret = subprocess.run(['systemctl', 'is-active', 'autohotspot'], + ret = subprocess.run(['systemctl', 'is-active', 'autohotspot.timer'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False, stdin=subprocess.DEVNULL) # 0 = active, 3 = inactive @@ -260,22 +260,21 @@ def get_autohotspot_status(): def stop_autohotspot(): """Stop auto hotspot functionality - Basically disabling the cronjob and running the script one last time manually + Stopping and disabling the timer and running the service one last time manually """ if os.path.isfile("/etc/systemd/system/autohotspot.service"): - cron_job = "/etc/cron.d/autohotspot" - subprocess.run(["sudo", "sed", "-i", r"s/^\*.*/#&/", cron_job], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) - subprocess.run(['sudo', '/usr/bin/systemctl', 'stop', 'autohotspot'], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) - subprocess.run(['sudo', '/usr/bin/systemctl', 'disable', 'autohotspot'], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) - ret = subprocess.run(['sudo', 'autohotspot'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - check=False) - if ret.returncode != 0: - msg = f"Error 'stop_autohotspot': {ret.stdout} (Code: {ret.returncode})" - logger.error(msg) - return {'error': {'code': -1, 'message': msg}} + # Stop timer + subprocess.run(['sudo', '/usr/bin/systemctl', 'stop', 'autohotspot.timer'], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) + # Prevent start after system restart + subprocess.run(['sudo', '/usr/bin/systemctl', 'disable', 'autohotspot.timer'], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) + # Prevent start after system restart (should always be disabled, but make sure) + subprocess.run(['sudo', '/usr/bin/systemctl', 'disable', 'autohotspot.service'], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) + + subprocess.run(['sudo', '/usr/bin/systemctl', 'start', 'autohotspot.service'], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) return 'inactive' else: @@ -285,24 +284,17 @@ def stop_autohotspot(): @plugin.register() def start_autohotspot(): - """start auto hotspot functionality + """Start auto hotspot functionality - Basically enabling the cronjob and running the script one time manually + Enabling and starting the timer (timer will start the service) """ if os.path.isfile("/etc/systemd/system/autohotspot.service"): - cron_job = "/etc/cron.d/autohotspot" - subprocess.run(["sudo", "sed", "-i", "-r", r"s/(^#)(\*[0-9]*)/\*/", cron_job], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) - subprocess.run(['sudo', '/usr/bin/systemctl', 'start', 'autohotspot'], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) - subprocess.run(['sudo', '/usr/bin/systemctl', 'enable', 'autohotspot'], - stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) - ret = subprocess.run(['sudo', 'autohotspot'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - check=False) - if ret.returncode != 0: - msg = f"Error 'start_autohotspot': {ret.stdout} (Code: {ret.returncode})" - logger.error(msg) - return {'error': {'code': -1, 'message': msg}} + # Enable start after system restart + subprocess.run(['sudo', '/usr/bin/systemctl', 'enable', 'autohotspot.timer'], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) + # Start timer (starts the service immediately) + subprocess.run(['sudo', '/usr/bin/systemctl', 'start', 'autohotspot.timer'], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=False) return 'active' else: