Skip to content

Commit ead8739

Browse files
committed
WiFi Test: Add cleanup logic and improve hybrid connection handling
- Register a cleanup() function to terminate background wpa_supplicant processes - Ensure WPA config is temporary and removed post test - Improve robustness of fallback to wpa_supplicant + udhcpc if nmcli fails - Ensure IP and internet connectivity checks are logged - Preserve original argument/env/file logic for SSID/password - Maintain logging, result output, and functestlib usage Signed-off-by: Srikanth Muppandam <[email protected]>
1 parent cb65b42 commit ead8739

File tree

4 files changed

+366
-0
lines changed

4 files changed

+366
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# WiFi Connectivity Validation
2+
3+
## 📋 Overview
4+
5+
This test validates WiFi functionality by:
6+
7+
- Connecting to an access point (AP) using either `nmcli` or `wpa_supplicant`.
8+
- Verifying IP acquisition via DHCP.
9+
- Checking internet connectivity with a `ping` test.
10+
- Handling systemd network service status.
11+
- Supporting flexible SSID/password input via arguments, environment, or file.
12+
13+
## ✅ SSID/PASSWORD Input Priority (Hybrid Approach)
14+
15+
1. **Command-line arguments**:
16+
```sh
17+
./run.sh "MySSID" "MyPassword"
18+
```
19+
20+
2. **Environment variables**:
21+
```sh
22+
SSID_ENV=MySSID PASSWORD_ENV=MyPassword ./run.sh
23+
```
24+
25+
3. **Fallback to `ssid_list.txt` file** (if above not set):
26+
```txt
27+
MySSID MyPassword
28+
```
29+
30+
## ⚙️ Supported Tools
31+
32+
- Primary: `nmcli`
33+
- Fallback: `wpa_supplicant`, `udhcpc`, `ifconfig`
34+
35+
Ensure these tools are available in the system before running the test. Missing tools are detected and logged as skipped/failure.
36+
37+
## 🧪 Test Flow
38+
39+
1. **Dependency check** – verifies necessary binaries are present.
40+
2. **Systemd services check** – attempts to start network services if inactive.
41+
3. **WiFi connect (nmcli or wpa_supplicant)** – based on tool availability.
42+
4. **IP assignment check** – validates `ifconfig wlan0` output.
43+
5. **Internet test** – pings `8.8.8.8` to confirm outbound reachability.
44+
6. **Result logging** – writes `.res` file and logs all actions.
45+
46+
## 🧾 Output
47+
48+
- `WiFi_Connectivity.res`: Contains `WiFi_Connectivity PASS` or `FAIL`.
49+
- Logs are printed using `log_info`, `log_pass`, and `log_fail` from `functestlib.sh`.
50+
51+
## 📂 Directory Structure
52+
53+
```
54+
WiFi/
55+
├── run.sh
56+
├── ssid_list.txt (optional)
57+
├── README.md
58+
```
59+
60+
## 🌐 Integration (meta-qcom_PreMerge.yaml)
61+
62+
Add this test with SSID parameters as follows:
63+
64+
```yaml
65+
- name: WiFi_Connectivity
66+
path: Runner/suites/Connectivity/WiFi
67+
timeout:
68+
minutes: 5
69+
params:
70+
SSID_ENV: "xxxx"
71+
PASSWORD_ENV: "xxxx"
72+
```
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#!/bin/sh
2+
3+
# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4+
# SPDX-License-Identifier: BSD-3-Clause-Clear
5+
6+
# Robustly find and source init_env
7+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8+
INIT_ENV=""
9+
SEARCH="$SCRIPT_DIR"
10+
while [ "$SEARCH" != "/" ]; do
11+
if [ -f "$SEARCH/init_env" ]; then
12+
INIT_ENV="$SEARCH/init_env"
13+
break
14+
fi
15+
SEARCH=$(dirname "$SEARCH")
16+
done
17+
18+
if [ -z "$INIT_ENV" ]; then
19+
echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2
20+
exit 1
21+
fi
22+
23+
# shellcheck disable=SC1090
24+
if [ -z "$__INIT_ENV_LOADED" ]; then
25+
. "$INIT_ENV"
26+
fi
27+
28+
# shellcheck disable=SC1090,SC1091
29+
. "$TOOLS/functestlib.sh"
30+
31+
TESTNAME="WiFi"
32+
res_file="./$TESTNAME.res"
33+
test_path=$(find_test_case_by_name "$TESTNAME")
34+
cd "$test_path" || exit 1
35+
36+
log_info "-------------------------------------------------------------"
37+
log_info "------------------- Starting $TESTNAME Test -----------------"
38+
39+
# Fetch credentials from function; expects functestlib.sh to have get_wifi_credentials
40+
CRED=$(get_wifi_credentials "$1" "$2")
41+
if [ $? -ne 0 ] || [ -z "$CRED" ]; then
42+
log_fail "SSID and password not provided via argument, env, or file."
43+
echo "$TESTNAME FAIL" > "$res_file"
44+
exit 1
45+
fi
46+
SSID=$(echo "$CRED" | awk '{print $1}')
47+
PASSWORD=$(echo "$CRED" | awk '{print $2}')
48+
log_info "DEBUG: Using SSID='$SSID' and PASSWORD='[hidden]'"
49+
50+
# Define cleanup function
51+
cleanup() {
52+
log_info "Cleaning up WiFi test environment..."
53+
killall -q wpa_supplicant 2>/dev/null
54+
rm -f /tmp/wpa_supplicant.conf nmcli.log wpa.log
55+
if command -v ip >/dev/null 2>&1; then
56+
for iface in $(ip link | awk -F: '/ wl/ {print $2}' | tr -d ' '); do
57+
ip link set "$iface" down 2>/dev/null
58+
done
59+
else
60+
ifconfig wlan0 down 2>/dev/null
61+
fi
62+
}
63+
64+
# Check for ping, nmcli, wpa_supplicant, udhcpc etc
65+
check_net_tools || {
66+
log_fail "Core network utilities missing."
67+
echo "$TESTNAME FAIL" > "$res_file"
68+
exit 1
69+
}
70+
check_dependencies ping nmcli wpa_supplicant udhcpc
71+
72+
# Systemd service check if systemd exists (ok to skip on kernel-only build)
73+
check_systemd_services systemd-networkd.service
74+
75+
# Find WiFi interface dynamically
76+
WIFI_IF=$(get_wifi_interface)
77+
if [ -z "$WIFI_IF" ]; then
78+
log_fail "No WiFi interface found"
79+
echo "$TESTNAME FAIL" > "$res_file"
80+
exit 1
81+
fi
82+
log_info "Using WiFi interface: $WIFI_IF"
83+
84+
# Try nmcli first if available
85+
if command -v nmcli >/dev/null 2>&1; then
86+
log_info "Trying to connect using nmcli..."
87+
if nmcli dev wifi connect "$SSID" password "$PASSWORD" ifname "$WIFI_IF" 2>&1 | tee nmcli.log; then
88+
log_pass "Connected to $SSID using nmcli"
89+
IP=$(get_ip_address "$WIFI_IF")
90+
log_info "IP Address: $IP"
91+
if ping -c 3 -W 2 8.8.8.8 >/dev/null 2>&1; then
92+
log_pass "Internet connectivity verified via ping"
93+
echo "$TESTNAME PASS" > "$res_file"
94+
cleanup
95+
exit 0
96+
else
97+
log_fail "Ping test failed after nmcli connection"
98+
fi
99+
else
100+
log_warn "nmcli failed to connect. Will try fallback."
101+
fi
102+
fi
103+
104+
# Fallback to wpa_supplicant + udhcpc if available
105+
if command -v wpa_supplicant >/dev/null 2>&1 && command -v udhcpc >/dev/null 2>&1; then
106+
log_info "Falling back to wpa_supplicant + udhcpc"
107+
WPA_CONF="/tmp/wpa_supplicant.conf"
108+
{
109+
echo "ctrl_interface=/var/run/wpa_supplicant"
110+
echo "network={"
111+
echo " ssid=\"$SSID\""
112+
echo " key_mgmt=WPA-PSK"
113+
echo " pairwise=CCMP TKIP"
114+
echo " group=CCMP TKIP"
115+
echo " psk=\"$PASSWORD\""
116+
echo "}"
117+
} > "$WPA_CONF"
118+
119+
killall -q wpa_supplicant 2>/dev/null
120+
wpa_supplicant -B -i "$WIFI_IF" -D nl80211 -c "$WPA_CONF" 2>&1 | tee wpa.log
121+
sleep 4
122+
udhcpc -i "$WIFI_IF" >/dev/null 2>&1
123+
sleep 2
124+
125+
IP=$(get_ip_address "$WIFI_IF")
126+
if [ -n "$IP" ]; then
127+
log_pass "Got IP via udhcpc: $IP"
128+
if ping -c 3 -W 2 8.8.8.8 >/dev/null 2>&1; then
129+
log_pass "Internet connectivity verified via ping"
130+
echo "$TESTNAME PASS" > "$res_file"
131+
cleanup
132+
exit 0
133+
else
134+
log_fail "Ping test failed after wpa_supplicant connection"
135+
fi
136+
else
137+
log_fail "Failed to acquire IP via udhcpc"
138+
fi
139+
else
140+
log_error "Neither nmcli nor wpa_supplicant+udhcpc available"
141+
fi
142+
143+
log_fail "$TESTNAME : Test Failed"
144+
echo "$TESTNAME FAIL" > "$res_file"
145+
cleanup
146+
exit 1
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#<SSID> <PASSWORD>
2+
#<SSID_1> <PASSWORD_1>

Runner/utils/functestlib.sh

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,3 +382,149 @@ weston_start() {
382382
fi
383383
}
384384

385+
# Retry a shell command up to N times with a delay
386+
retry_command() {
387+
cmd="$1"
388+
retries="$2"
389+
delay="$3"
390+
attempt=1
391+
while [ "$attempt" -le "$retries" ]; do
392+
if eval "$cmd"; then
393+
return 0
394+
fi
395+
log_warn "Attempt $attempt/$retries failed for: $cmd"
396+
attempt=$((attempt + 1))
397+
sleep "$delay"
398+
done
399+
return 1
400+
}
401+
402+
# Check and ensure given systemd services are active (with retries and logging)
403+
check_systemd_services() {
404+
# Skip if systemd is not present
405+
if ! command -v systemctl >/dev/null 2>&1; then
406+
log_warn "systemd is not available. Skipping systemd service checks."
407+
return 0
408+
fi
409+
410+
for service in "$@"; do
411+
if systemctl is-enabled "$service" >/dev/null 2>&1; then
412+
if ! systemctl is-active --quiet "$service"; then
413+
log_warn "$service is not running. Attempting to start with retries..."
414+
retry_command "systemctl start $service" 3 2
415+
if systemctl is-active --quiet "$service"; then
416+
log_pass "$service started successfully after retry."
417+
else
418+
log_fail "$service failed to start after 3 retries."
419+
return 1
420+
fi
421+
else
422+
log_info "$service is already active."
423+
fi
424+
else
425+
log_warn "$service is not enabled or not found."
426+
fi
427+
done
428+
return 0
429+
}
430+
431+
# Ensure at least one network tool is available
432+
check_net_tools() {
433+
# At least one of ifconfig or ip must be available
434+
if command -v ifconfig >/dev/null 2>&1 || command -v ip >/dev/null 2>&1; then
435+
return 0
436+
else
437+
log_error "Neither ifconfig nor ip found in PATH"
438+
return 1
439+
fi
440+
}
441+
442+
# Get IP address using ifconfig or ip (fallback logic)
443+
get_ip_address() {
444+
iface="$1"
445+
ip=""
446+
if command -v ifconfig >/dev/null 2>&1; then
447+
ip=$(ifconfig "$iface" 2>/dev/null | awk '/inet / {print $2; exit}')
448+
fi
449+
if [ -z "$ip" ] && command -v ip >/dev/null 2>&1; then
450+
ip=$(ip addr show "$iface" 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1)
451+
fi
452+
echo "$ip"
453+
}
454+
455+
# get_wifi_credentials: Retrieves SSID and password for WiFi connection
456+
# Usage: get_wifi_credentials "$1" "$2"
457+
# - $1: SSID (optional, from argument)
458+
# - $2: Password (optional, from argument)
459+
# Returns: prints "<ssid> <password>" to stdout, or nothing on failure (return 1)
460+
get_wifi_credentials() {
461+
ssid="$1"
462+
pass="$2"
463+
464+
# Try arguments first
465+
if [ -z "$ssid" ] || [ -z "$pass" ]; then
466+
# Try environment variables
467+
ssid="${SSID_ENV:-$ssid}"
468+
pass="${PASSWORD_ENV:-$pass}"
469+
fi
470+
471+
# Try ssid_list.txt if still missing
472+
if [ -z "$ssid" ] || [ -z "$pass" ]; then
473+
if [ -f "./ssid_list.txt" ]; then
474+
# Read only first line; tolerate tabs/spaces between fields
475+
# shellcheck disable=SC2162
476+
read -r ssid pass _ < ./ssid_list.txt
477+
if [ -z "$ssid" ] || [ -z "$pass" ]; then
478+
log_error "Corrupted ssid_list.txt (missing SSID or password)"
479+
return 1
480+
fi
481+
log_info "Using SSID and password from ssid_list.txt"
482+
else
483+
log_error "SSID and password not provided via argument, env, or file."
484+
return 1
485+
fi
486+
fi
487+
488+
# Validate again
489+
if [ -z "$ssid" ] || [ -z "$pass" ]; then
490+
log_error "SSID and password values are empty after all methods."
491+
return 1
492+
fi
493+
494+
# Output: "<ssid> <password>"
495+
printf '%s %s\n' "$ssid" "$pass"
496+
return 0
497+
}
498+
499+
# Find the first available WiFi interface.
500+
# Prints the interface name and sets WIFI_IF variable.
501+
get_wifi_interface() {
502+
# Try with 'ip' first
503+
if command -v ip >/dev/null 2>&1; then
504+
WIFI_IF=$(ip link | awk -F: '/ wl/ {print $2}' | tr -d ' ' | head -n1)
505+
if [ -z "$WIFI_IF" ]; then
506+
WIFI_IF=$(ip link | awk -F: '/^[0-9]+: wl/ {print $2}' | tr -d ' ' | head -n1)
507+
fi
508+
if [ -z "$WIFI_IF" ]; then
509+
# fallback: see if wlan0 exists
510+
if ip link show wlan0 >/dev/null 2>&1; then
511+
WIFI_IF="wlan0"
512+
fi
513+
fi
514+
else
515+
# Fallback to ifconfig
516+
WIFI_IF=$(ifconfig -a 2>/dev/null | grep -o '^wl[^:]*' | head -n1)
517+
if [ -z "$WIFI_IF" ]; then
518+
if ifconfig wlan0 >/dev/null 2>&1; then
519+
WIFI_IF="wlan0"
520+
fi
521+
fi
522+
fi
523+
524+
if [ -n "$WIFI_IF" ]; then
525+
echo "$WIFI_IF"
526+
return 0
527+
else
528+
return 1
529+
fi
530+
}

0 commit comments

Comments
 (0)