From 6c3bb9d62b3e43e7313cfae2c62ec1ca2040c6a7 Mon Sep 17 00:00:00 2001 From: Srikanth Muppandam Date: Fri, 6 Jun 2025 16:53:36 +0530 Subject: [PATCH] WiFi_Manual_IP: Refactor run.sh to use modular helpers, safe cleanup, and trap-based restore - Switch WiFi_Manual_IP/run.sh to only use modular helper functions from functestlib.sh. - Add 'trap' to always restore original udhcpc script on test exit, ensuring testbed is left clean. - Use wifi_write_wpa_conf for WPA config creation (eliminate code duplication). - Use ensure_udhcpc_script and restore_udhcpc_script for robust script handling. - Harden cleanup and error handling (all exits go through helpers). - Improved logging, POSIX and ShellCheck compliance. - No change in test semantics or interface. Signed-off-by: Srikanth Muppandam --- .../README_WiFi_Connectivity.md | 75 +++++ .../Connectivity/WiFi/WiFi_Dynamic_IP/run.sh | 75 +++++ .../WiFi/WiFi_Dynamic_IP/ssid_list.txt | 0 .../WiFi/WiFi_Firmware_Driver/run.sh | 68 ++++ .../Connectivity/WiFi/WiFi_Manual_IP/run.sh | 89 ++++++ .../WiFi/WiFi_Manual_IP/ssid_list.txt | 0 .../Connectivity/WiFi/WiFi_OnOff/run.sh | 61 ++++ Runner/utils/functestlib.sh | 297 ++++++++++++++++++ 8 files changed, 665 insertions(+) create mode 100644 Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/README_WiFi_Connectivity.md create mode 100755 Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/run.sh create mode 100755 Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/ssid_list.txt create mode 100755 Runner/suites/Connectivity/WiFi/WiFi_Firmware_Driver/run.sh create mode 100755 Runner/suites/Connectivity/WiFi/WiFi_Manual_IP/run.sh create mode 100755 Runner/suites/Connectivity/WiFi/WiFi_Manual_IP/ssid_list.txt create mode 100755 Runner/suites/Connectivity/WiFi/WiFi_OnOff/run.sh diff --git a/Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/README_WiFi_Connectivity.md b/Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/README_WiFi_Connectivity.md new file mode 100644 index 00000000..96c53a5b --- /dev/null +++ b/Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/README_WiFi_Connectivity.md @@ -0,0 +1,75 @@ +Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +SPDX-License-Identifier: BSD-3-Clause-Clear + +# WiFi Connectivity Validation + +## ๐Ÿ“‹ Overview + +This test validates WiFi functionality by: + +- Connecting to an access point (AP) using either `nmcli` or `wpa_supplicant`. +- Verifying IP acquisition via DHCP. +- Checking internet connectivity with a `ping` test. +- Handling systemd network service status. +- Supporting flexible SSID/password input via arguments, environment, or file. + +## โœ… SSID/PASSWORD Input Priority (Hybrid Approach) + +1. **Command-line arguments**: + ```sh + ./run.sh "MySSID" "MyPassword" + ``` + +2. **Environment variables**: + ```sh + SSID_ENV=MySSID PASSWORD_ENV=MyPassword ./run.sh + ``` + +3. **Fallback to `ssid_list.txt` file** (if above not set): + ```txt + MySSID MyPassword + ``` + +## โš™๏ธ Supported Tools + +- Primary: `nmcli` +- Fallback: `wpa_supplicant`, `udhcpc`, `ifconfig` + +Ensure these tools are available in the system before running the test. Missing tools are detected and logged as skipped/failure. + +## ๐Ÿงช Test Flow + +1. **Dependency check** โ€“ verifies necessary binaries are present. +2. **Systemd services check** โ€“ attempts to start network services if inactive. +3. **WiFi connect (nmcli or wpa_supplicant)** โ€“ based on tool availability. +4. **IP assignment check** โ€“ validates `ifconfig wlan0` output. +5. **Internet test** โ€“ pings `8.8.8.8` to confirm outbound reachability. +6. **Result logging** โ€“ writes `.res` file and logs all actions. + +## ๐Ÿงพ Output + +- `WiFi_Connectivity.res`: Contains `WiFi_Connectivity PASS` or `FAIL`. +- Logs are printed using `log_info`, `log_pass`, and `log_fail` from `functestlib.sh`. + +## ๐Ÿ“‚ Directory Structure + +``` +WiFi/ +โ”œโ”€โ”€ run.sh +โ”œโ”€โ”€ ssid_list.txt (optional) +โ”œโ”€โ”€ README.md +``` + +## ๐ŸŒ Integration (meta-qcom_PreMerge.yaml) + +Add this test with SSID parameters as follows: + +```yaml +- name: WiFi_Connectivity + path: Runner/suites/Connectivity/WiFi + timeout: + minutes: 5 + params: + SSID_ENV: "xxxx" + PASSWORD_ENV: "xxxx" +``` diff --git a/Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/run.sh b/Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/run.sh new file mode 100755 index 00000000..77517a31 --- /dev/null +++ b/Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/run.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# Robustly find and source init_env +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 1 +fi + +# shellcheck disable=SC1090 +if [ -z "$__INIT_ENV_LOADED" ]; then + . "$INIT_ENV" +fi + +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +TESTNAME="WiFi_Dynamic_IP" +#res_file="./$TESTNAME.res" +test_path=$(find_test_case_by_name "$TESTNAME") +cd "$test_path" || exit 1 + +log_info "-------------------------------------------------------------" +log_info "------------------- Starting $TESTNAME Test -----------------" + +# Credential extraction +creds=$(get_wifi_credentials "$1" "$2") || log_skip_exit "$TESTNAME" "WiFi: SSID and/or password missing. Skipping test." wifi_cleanup "" +SSID=$(echo "$creds" | awk '{print $1}') +PASSWORD=$(echo "$creds" | awk '{print $2}') +log_info "Using SSID='$SSID' and PASSWORD='[hidden]'" + +check_dependencies iw ping + +# If not a kernel-only/minimal build, systemd is checked, else skipped automatically +check_systemd_services systemd-networkd.service || log_fail_exit "$TESTNAME" "Network services check failed" wifi_cleanup "" + +WIFI_IFACE=$(get_wifi_interface) || log_fail_exit "$TESTNAME" "No WiFi interface found" wifi_cleanup "" +log_info "Using WiFi interface: $WIFI_IFACE" + +# nmcli with retry +if wifi_connect_nmcli "$WIFI_IFACE" "$SSID" "$PASSWORD"; then + IP=$(wifi_get_ip "$WIFI_IFACE") + [ -z "$IP" ] && log_fail_exit "$TESTNAME" "No IP after nmcli" wifi_cleanup "$WIFI_IFACE" + if retry_command "ping -I \"$WIFI_IFACE\" -c 3 -W 2 8.8.8.8 >/dev/null 2>&1" 3 3; then + log_pass_exit "$TESTNAME" "Internet connectivity verified via ping" wifi_cleanup "$WIFI_IFACE" + else + log_fail_exit "$TESTNAME" "Ping test failed after nmcli connection" wifi_cleanup "$WIFI_IFACE" + fi +fi + +# wpa_supplicant+udhcpc with retry +if wifi_connect_wpa_supplicant "$WIFI_IFACE" "$SSID" "$PASSWORD"; then + IP=$(wifi_get_ip "$WIFI_IFACE") + [ -z "$IP" ] && log_fail_exit "$TESTNAME" "No IP after wpa_supplicant" wifi_cleanup "$WIFI_IFACE" + if retry_command "ping -I \"$WIFI_IFACE\" -c 3 -W 2 8.8.8.8 >/dev/null 2>&1" 3 3; then + log_pass_exit "$TESTNAME" "Internet connectivity verified via ping" wifi_cleanup "$WIFI_IFACE" + else + log_fail_exit "$TESTNAME" "Ping test failed after wpa_supplicant connection" wifi_cleanup "$WIFI_IFACE" + fi +fi + +log_fail_exit "$TESTNAME" "All WiFi connection methods failed for $WIFI_IFACE (SSID: $SSID)" wifi_cleanup "$WIFI_IFACE" diff --git a/Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/ssid_list.txt b/Runner/suites/Connectivity/WiFi/WiFi_Dynamic_IP/ssid_list.txt new file mode 100755 index 00000000..e69de29b diff --git a/Runner/suites/Connectivity/WiFi/WiFi_Firmware_Driver/run.sh b/Runner/suites/Connectivity/WiFi/WiFi_Firmware_Driver/run.sh new file mode 100755 index 00000000..c75b6850 --- /dev/null +++ b/Runner/suites/Connectivity/WiFi/WiFi_Firmware_Driver/run.sh @@ -0,0 +1,68 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# Robustly find and source init_env +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 1 +fi + +# Only source if not already loaded (idempotent) +if [ -z "$__INIT_ENV_LOADED" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" +fi +# Always source functestlib.sh, using $TOOLS exported by init_env +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +TESTNAME="WiFi_Firmware_Driver" +test_path=$(find_test_case_by_name "$TESTNAME") +cd "$test_path" || exit 1 + +log_info "--------------------------------------------------------------------------" +log_info "-------------------Starting $TESTNAME Testcase----------------------------" +log_info "=== Test Initialization ===" + +# Paths for both targets +KODIAK_FW="/lib/firmware/ath11k/WCN6750/hw1.0/qcm6490/wpss.mbn" +LEMANS_FW="/lib/firmware/ath11k/WCN6855/hw2.1/amss.bin" + +# Check firmware presence +if [ -f "$KODIAK_FW" ]; then + log_info "Kodiak firmware detected: $KODIAK_FW" + RPROC_PATH="$(find /sys/class/remoteproc/ -maxdepth 1 -name 'remoteproc*' | grep -E '[3-9]$' | head -n1)" + [ -z "$RPROC_PATH" ] && log_fail_exit "$TESTNAME" "Remoteproc node not found for Kodiak" + state=$(cat "$RPROC_PATH/state" 2>/dev/null) + if [ "$state" != "running" ]; then + log_info "Starting remoteproc: $RPROC_PATH" + echo start > "$RPROC_PATH/state" + sleep 2 + state=$(cat "$RPROC_PATH/state" 2>/dev/null) + [ "$state" != "running" ] && log_fail_exit "$TESTNAME" "Failed to start remoteproc $RPROC_PATH" + fi + log_info "Remoteproc is running for Kodiak." +elif [ -f "$LEMANS_FW" ]; then + log_info "Lemans firmware detected: $LEMANS_FW" + if ! modprobe ath11k_pci; then + log_fail_exit "$TESTNAME" "Failed to load ath11k_pci module." + fi + lsmod | grep -q ath11k_pci || log_fail_exit "$TESTNAME" "ath11k_pci module not loaded." + log_info "ath11k_pci module loaded for Lemans." +else + log_skip_exit "$TESTNAME" "WiFi firmware not found for known targets." +fi + +log_pass_exit "$TESTNAME" "WiFi firmware and driver validation successful." diff --git a/Runner/suites/Connectivity/WiFi/WiFi_Manual_IP/run.sh b/Runner/suites/Connectivity/WiFi/WiFi_Manual_IP/run.sh new file mode 100755 index 00000000..c45101ab --- /dev/null +++ b/Runner/suites/Connectivity/WiFi/WiFi_Manual_IP/run.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# Robustly find and source init_env +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 1 +fi + +# Only source if not already loaded (idempotent) +if [ -z "$__INIT_ENV_LOADED" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" +fi +# Always source functestlib.sh, using $TOOLS exported by init_env +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +TESTNAME="WiFi_Manual_IP" +test_path=$(find_test_case_by_name "$TESTNAME") +cd "$test_path" || exit 1 + +log_info "--------------------------------------------------------------------------" +log_info "-------------------Starting $TESTNAME Testcase----------------------------" +log_info "=== Test Initialization ===" + +# Trap to always restore udhcpc script +trap 'restore_udhcpc_script' EXIT + +# Credential extraction (from arguments, env, or ssid_list.txt) +if ! CRED=$(get_wifi_credentials "$1" "$2") || [ -z "$CRED" ]; then + log_skip_exit "$TESTNAME" "WiFi: SSID and/or password missing. Skipping test." +fi + +SSID=$(echo "$CRED" | awk '{print $1}') +PASSWORD=$(echo "$CRED" | awk '{print $2}') +log_info "Using SSID='$SSID' and PASSWORD='[hidden]'" + +check_dependencies iw wpa_supplicant udhcpc ip + +WIFI_IF=$(get_wifi_interface) +[ -z "$WIFI_IF" ] && log_fail_exit "$TESTNAME" "No WiFi interface detected." + +UDHCPC_SCRIPT=$(ensure_udhcpc_script) +[ ! -x "$UDHCPC_SCRIPT" ] && log_fail_exit "$TESTNAME" "Failed to create udhcpc script." + +wifi_cleanup() { + killall -q wpa_supplicant 2>/dev/null + rm -f /tmp/wpa_supplicant.conf wpa.log + ip link set "$WIFI_IF" down 2>/dev/null +} + +# Generate WPA config using helper (no duplicate code!) +WPA_CONF="$(wifi_write_wpa_conf "$WIFI_IF" "$SSID" "$PASSWORD")" +if [ ! -f "$WPA_CONF" ]; then + log_fail_exit "$TESTNAME" "Failed to create WPA config" wifi_cleanup +fi + +killall -q wpa_supplicant 2>/dev/null +wpa_supplicant -B -i "$WIFI_IF" -c "$WPA_CONF" 2>&1 | tee wpa.log +sleep 4 + +# Run udhcpc with the script +udhcpc -i "$WIFI_IF" -s "$UDHCPC_SCRIPT" -n -q & +sleep 8 + +IP=$(ip addr show "$WIFI_IF" | awk '/inet / {print $2}' | cut -d/ -f1) +if [ -n "$IP" ]; then + log_info "WiFi got IP: $IP (manual DHCP via udhcpc)" + if ping -I "$WIFI_IF" -c 3 -W 2 8.8.8.8 >/dev/null 2>&1; then + log_pass_exit "$TESTNAME" "WiFi: Internet connectivity verified via ping" wifi_cleanup + else + log_fail_exit "$TESTNAME" "WiFi: Ping test failed after DHCP/manual IP" wifi_cleanup + fi +else + log_fail_exit "$TESTNAME" "Failed to acquire IP via udhcpc" wifi_cleanup +fi diff --git a/Runner/suites/Connectivity/WiFi/WiFi_Manual_IP/ssid_list.txt b/Runner/suites/Connectivity/WiFi/WiFi_Manual_IP/ssid_list.txt new file mode 100755 index 00000000..e69de29b diff --git a/Runner/suites/Connectivity/WiFi/WiFi_OnOff/run.sh b/Runner/suites/Connectivity/WiFi/WiFi_OnOff/run.sh new file mode 100755 index 00000000..84110348 --- /dev/null +++ b/Runner/suites/Connectivity/WiFi/WiFi_OnOff/run.sh @@ -0,0 +1,61 @@ +#!/bin/sh +# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# Robustly find and source init_env +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +INIT_ENV="" +SEARCH="$SCRIPT_DIR" +while [ "$SEARCH" != "/" ]; do + if [ -f "$SEARCH/init_env" ]; then + INIT_ENV="$SEARCH/init_env" + break + fi + SEARCH=$(dirname "$SEARCH") +done + +if [ -z "$INIT_ENV" ]; then + echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 + exit 1 +fi + +# Only source if not already loaded (idempotent) +if [ -z "$__INIT_ENV_LOADED" ]; then + # shellcheck disable=SC1090 + . "$INIT_ENV" +fi +# Always source functestlib.sh, using $TOOLS exported by init_env +# shellcheck disable=SC1090,SC1091 +. "$TOOLS/functestlib.sh" + +TESTNAME="WiFi_OnOff" +test_path=$(find_test_case_by_name "$TESTNAME") +cd "$test_path" || exit 1 + +log_info "-----------------------------------------------------------------------------------------" +log_info "-------------------Starting $TESTNAME Testcase----------------------------" +log_info "=== Test Initialization ===" + +check_dependencies ip iw + +wifi_iface="$(get_wifi_interface)" +if [ -z "$wifi_iface" ]; then + log_skip_exit "$TESTNAME" "No WiFi interface found. Skipping." "" +fi + +# Bring WiFi down +if bring_interface_up_down "$wifi_iface" down; then + log_info "Brought $wifi_iface down successfully." +else + log_fail_exit "$TESTNAME" "Failed to bring $wifi_iface down." "" +fi + +sleep 2 + +# Bring WiFi up +if bring_interface_up_down "$wifi_iface" up; then + log_info "Brought $wifi_iface up successfully." + log_pass_exit "$TESTNAME" "$wifi_iface toggled up/down successfully." "" +else + log_fail_exit "$TESTNAME" "Failed to bring $wifi_iface up after down." "" +fi diff --git a/Runner/utils/functestlib.sh b/Runner/utils/functestlib.sh index 68612bd7..005a195b 100755 --- a/Runner/utils/functestlib.sh +++ b/Runner/utils/functestlib.sh @@ -391,3 +391,300 @@ weston_start() { fi } +# Clean up WiFi test environment (reusable for other tests) +wifi_cleanup() { + iface="$1" + log_info "Cleaning up WiFi test environment..." + killall -q wpa_supplicant 2>/dev/null + rm -f /tmp/wpa_supplicant.conf nmcli.log wpa.log + if [ -n "$iface" ]; then + ip link set "$iface" down 2>/dev/null || ifconfig "$iface" down 2>/dev/null + fi +} + +# Extract credentials from args/env/file +get_wifi_credentials() { + ssid="$1" + pass="$2" + if [ -z "$ssid" ] || [ -z "$pass" ]; then + ssid="${SSID:-$ssid}" + pass="${PASSWORD:-$pass}" + fi + if [ -z "$ssid" ] || [ -z "$pass" ]; then + if [ -f "./ssid_list.txt" ]; then + read -r ssid pass _ < ./ssid_list.txt + fi + fi + ssid=$(echo "$ssid" | xargs) + pass=$(echo "$pass" | xargs) + if [ -z "$ssid" ] || [ -z "$pass" ]; then + return 1 + fi + printf '%s %s\n' "$ssid" "$pass" + return 0 +} + +# POSIX-compliant: Retry a shell command up to N times with delay +retry_command() { + cmd="$1" + retries="$2" + delay="$3" + i=1 + while [ "$i" -le "$retries" ]; do + if eval "$cmd"; then + return 0 + fi + log_warn "Attempt $i/$retries failed: $cmd" + i=$((i + 1)) + sleep "$delay" + done + return 1 +} + +# Connect using nmcli with retries (returns 0 on success) +wifi_connect_nmcli() { + iface="$1" + ssid="$2" + pass="$3" + if command -v nmcli >/dev/null 2>&1; then + log_info "Trying to connect using nmcli..." + retry_command "nmcli dev wifi connect \"$ssid\" password \"$pass\" ifname \"$iface\" 2>&1 | tee nmcli.log" 3 3 + return $? + fi + return 1 +} + +# Connect using wpa_supplicant+udhcpc with retries (returns 0 on success) +wifi_connect_wpa_supplicant() { + iface="$1" + ssid="$2" + pass="$3" + if command -v wpa_supplicant >/dev/null 2>&1 && command -v udhcpc >/dev/null 2>&1; then + log_info "Falling back to wpa_supplicant + udhcpc" + WPA_CONF="/tmp/wpa_supplicant.conf" + { + echo "ctrl_interface=/var/run/wpa_supplicant" + echo "network={" + echo " ssid=\"$ssid\"" + echo " key_mgmt=WPA-PSK" + echo " pairwise=CCMP TKIP" + echo " group=CCMP TKIP" + echo " psk=\"$pass\"" + echo "}" + } > "$WPA_CONF" + killall -q wpa_supplicant 2>/dev/null + retry_command "wpa_supplicant -B -i \"$iface\" -D nl80211 -c \"$WPA_CONF\" 2>&1 | tee wpa.log" 3 2 + sleep 4 + udhcpc -i "$iface" >/dev/null 2>&1 + sleep 2 + return 0 + fi + log_error "Neither nmcli nor wpa_supplicant+udhcpc available" + return 1 +} + +# Get IPv4 address (returns IP or empty) +wifi_get_ip() { + iface="$1" + ip="" + if command -v ifconfig >/dev/null 2>&1; then + ip=$(ifconfig "$iface" 2>/dev/null | awk '/inet / {print $2; exit}') + fi + if [ -z "$ip" ] && command -v ip >/dev/null 2>&1; then + ip=$(ip addr show "$iface" 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1) + fi + echo "$ip" +} + +# Log+exit helpers with optional cleanup +log_pass_exit() { + # Usage: log_pass_exit "$TESTNAME" "Message" cleanup_func arg + TESTNAME="$1" + MSG="$2" + CLEANUP_FUNC="$3" + CLEANUP_ARG="$4" + log_pass "$MSG" + echo "$TESTNAME PASS" > "./$TESTNAME.res" + if [ -n "$CLEANUP_FUNC" ] && command -v "$CLEANUP_FUNC" >/dev/null 2>&1; then + "$CLEANUP_FUNC" "$CLEANUP_ARG" + fi + exit 0 +} + +log_fail_exit() { + # Usage: log_fail_exit "$TESTNAME" "Message" cleanup_func arg + TESTNAME="$1" + MSG="$2" + CLEANUP_FUNC="$3" + CLEANUP_ARG="$4" + log_fail "$MSG" + echo "$TESTNAME FAIL" > "./$TESTNAME.res" + if [ -n "$CLEANUP_FUNC" ] && command -v "$CLEANUP_FUNC" >/dev/null 2>&1; then + "$CLEANUP_FUNC" "$CLEANUP_ARG" + fi + exit 1 +} + +log_skip_exit() { + # Usage: log_skip_exit "$TESTNAME" "Message" cleanup_func arg + TESTNAME="$1" + MSG="$2" + CLEANUP_FUNC="$3" + CLEANUP_ARG="$4" + log_skip "$MSG" + echo "$TESTNAME SKIP" > "./$TESTNAME.res" + if [ -n "$CLEANUP_FUNC" ] && command -v "$CLEANUP_FUNC" >/dev/null 2>&1; then + "$CLEANUP_FUNC" "$CLEANUP_ARG" + fi + exit 0 +} + +# Robust systemd service check: returns 0 if networkd up, 0 if systemd missing, 1 if error +check_systemd_services() { + # If systemd not present, pass for minimal or kernel-only builds + if ! command -v systemctl >/dev/null 2>&1; then + log_info "systemd/systemctl not found (kernel/minimal build). Skipping service checks." + return 0 + fi + for service in "$@"; do + if systemctl is-enabled "$service" >/dev/null 2>&1; then + if ! systemctl is-active --quiet "$service"; then + log_warn "$service not running. Retrying start..." + retry_command "systemctl start $service" 3 2 + if ! systemctl is-active --quiet "$service"; then + log_fail "$service failed to start after 3 retries." + return 1 + else + log_pass "$service started after retry." + fi + fi + else + log_warn "$service not enabled or not found." + fi + done + return 0 +} + +# Ensure udhcpc default.script exists, create if missing +ensure_udhcpc_script() { + udhcpc_dir="/usr/share/udhcpc" + udhcpc_script="$udhcpc_dir/default.script" + udhcpc_backup="$udhcpc_script.bak" + + if [ ! -d "$udhcpc_dir" ]; then + mkdir -p "$udhcpc_dir" || return 1 + fi + + # Backup if script already exists and is not a backup yet + if [ -f "$udhcpc_script" ] && [ ! -f "$udhcpc_backup" ]; then + cp "$udhcpc_script" "$udhcpc_backup" + fi + + if [ ! -x "$udhcpc_script" ]; then + cat > "$udhcpc_script" <<'EOF' +#!/bin/sh +case "$1" in + deconfig) + ip addr flush dev "$interface" + ;; + renew|bound) + echo "[INFO] Configuring $interface with IP: $ip/$subnet" + ip addr flush dev "$interface" + ip addr add "$ip/$subnet" dev "$interface" + ip link set "$interface" up + if [ -n "$router" ]; then + ip route del default dev "$interface" 2>/dev/null + ip route add default via "$router" dev "$interface" + fi +echo "[INFO] Setting DNS to 8.8.8.8" +echo "nameserver 8.8.8.8" > /etc/resolv.conf + ;; +esac +exit 0 +EOF + chmod +x "$udhcpc_script" + fi + + echo "$udhcpc_script" +} + +# Resotre back the default.script +restore_udhcpc_script() { + udhcpc_dir="/usr/share/udhcpc" + udhcpc_script="$udhcpc_dir/default.script" + udhcpc_backup="$udhcpc_script.bak" + + if [ -f "$udhcpc_backup" ]; then + mv -f "$udhcpc_backup" "$udhcpc_script" + echo "[INFO] Restored original udhcpc default.script" + fi +} + +# Bring an interface up or down using available tools +# Usage: bring_interface_up_down +bring_interface_up_down() { + iface="$1" + state="$2" + if command -v ip >/dev/null 2>&1; then + ip link set "$iface" "$state" + elif command -v ifconfig >/dev/null 2>&1; then + if [ "$state" = "up" ]; then + ifconfig "$iface" up + else + ifconfig "$iface" down + fi + else + log_error "No ip or ifconfig tools found to bring $iface $state" + return 1 + fi +} + +wifi_write_wpa_conf() { + iface="$1" + ssid="$2" + pass="$3" + conf_file="/tmp/wpa_supplicant_${iface}.conf" + { + echo "ctrl_interface=/var/run/wpa_supplicant" + echo "network={" + echo " ssid=\"$ssid\"" + echo " key_mgmt=WPA-PSK" + echo " pairwise=CCMP TKIP" + echo " group=CCMP TKIP" + echo " psk=\"$pass\"" + echo "}" + } > "$conf_file" + echo "$conf_file" +} + +# Find the first available WiFi interface (wl* or wlan0), using 'ip' or 'ifconfig'. +# Prints the interface name, or returns non-zero if not found. +get_wifi_interface() { + WIFI_IF="" + + # Prefer 'ip' if available. + if command -v ip >/dev/null 2>&1; then + WIFI_IF=$(ip link | awk -F: '/ wl/ {print $2}' | tr -d ' ' | head -n1) + if [ -z "$WIFI_IF" ]; then + WIFI_IF=$(ip link | awk -F: '/^[0-9]+: wl/ {print $2}' | tr -d ' ' | head -n1) + fi + if [ -z "$WIFI_IF" ] && ip link show wlan0 >/dev/null 2>&1; then + WIFI_IF="wlan0" + fi + else + # Fallback to 'ifconfig' if 'ip' is missing. + if command -v ifconfig >/dev/null 2>&1; then + WIFI_IF=$(ifconfig -a 2>/dev/null | grep -o '^wl[^:]*' | head -n1) + if [ -z "$WIFI_IF" ] && ifconfig wlan0 >/dev/null 2>&1; then + WIFI_IF="wlan0" + fi + fi + fi + + if [ -n "$WIFI_IF" ]; then + echo "$WIFI_IF" + return 0 + else + return 1 + fi +}