Auto-bring WiFi interface up before TSCM scan

When the WiFi interface is down (e.g. USB adapter not activated),
scanning fails with "Network is down" errors. Now the scanner
proactively checks interface state via /sys/class/net and brings
it up using ip link (or ifconfig fallback) before attempting scans,
with a retry loop if the initial scan still fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Smittix
2026-02-07 14:45:24 +00:00
parent 70e9611f02
commit bb4ccc6355

View File

@@ -301,6 +301,73 @@ class UnifiedWiFiScanner:
return False
def _ensure_interface_up(self, interface: str) -> bool:
"""
Ensure a WiFi interface is up before scanning.
Attempts to bring the interface up using 'ip link set <iface> up',
falling back to 'ifconfig <iface> up'.
Args:
interface: Network interface name.
Returns:
True if the interface was brought up (or was already up),
False if we failed to bring it up.
"""
# Check current state via /sys/class/net
operstate_path = f"/sys/class/net/{interface}/operstate"
try:
with open(operstate_path) as f:
state = f.read().strip()
if state == "up":
return True
logger.info(f"Interface {interface} is '{state}', attempting to bring up")
except FileNotFoundError:
# Interface might not exist or /sys not available (non-Linux)
return True
except Exception:
pass
# Try ip link set up
if shutil.which('ip'):
try:
result = subprocess.run(
['ip', 'link', 'set', interface, 'up'],
capture_output=True,
text=True,
timeout=5,
)
if result.returncode == 0:
logger.info(f"Brought interface {interface} up via ip link")
time.sleep(1) # Brief settle time
return True
else:
logger.warning(f"ip link set {interface} up failed: {result.stderr.strip()}")
except Exception as e:
logger.warning(f"Failed to run ip link: {e}")
# Fallback to ifconfig
if shutil.which('ifconfig'):
try:
result = subprocess.run(
['ifconfig', interface, 'up'],
capture_output=True,
text=True,
timeout=5,
)
if result.returncode == 0:
logger.info(f"Brought interface {interface} up via ifconfig")
time.sleep(1)
return True
else:
logger.warning(f"ifconfig {interface} up failed: {result.stderr.strip()}")
except Exception as e:
logger.warning(f"Failed to run ifconfig: {e}")
logger.error(f"Could not bring interface {interface} up")
return False
# =========================================================================
# Quick Scan
# =========================================================================
@@ -362,6 +429,9 @@ class UnifiedWiFiScanner:
result.is_complete = True
return result
else: # Linux - try tools in order with fallback
# Ensure interface is up before scanning
self._ensure_interface_up(iface)
tools_to_try = []
if self._capabilities.has_nmcli:
tools_to_try.append(('nmcli', self._scan_with_nmcli))
@@ -375,6 +445,7 @@ class UnifiedWiFiScanner:
result.is_complete = True
return result
interface_was_down = False
for tool_name, scan_func in tools_to_try:
try:
logger.info(f"Attempting quick scan with {tool_name} on {iface}")
@@ -386,8 +457,28 @@ class UnifiedWiFiScanner:
error_msg = f"{tool_name}: {str(e)}"
errors_encountered.append(error_msg)
logger.warning(f"Quick scan with {tool_name} failed: {e}")
if 'is down' in str(e):
interface_was_down = True
continue # Try next tool
# If all tools failed because interface was down, try bringing it up and retry
if not tool_used and interface_was_down:
logger.info(f"Interface {iface} appears down, attempting to bring up and retry scan")
if self._ensure_interface_up(iface):
errors_encountered.clear()
for tool_name, scan_func in tools_to_try:
try:
logger.info(f"Retrying scan with {tool_name} on {iface} after bringing interface up")
observations = scan_func(iface, timeout)
tool_used = tool_name
logger.info(f"Retry scan with {tool_name} found {len(observations)} networks")
break
except Exception as e:
error_msg = f"{tool_name}: {str(e)}"
errors_encountered.append(error_msg)
logger.warning(f"Retry scan with {tool_name} failed: {e}")
continue
if not tool_used:
# All tools failed
result.error = "All scan tools failed. " + "; ".join(errors_encountered)