diff --git a/cgi_scripts/skyweave.lua b/cgi_scripts/skyweave.lua index 25c4c4d..07fdabc 100755 --- a/cgi_scripts/skyweave.lua +++ b/cgi_scripts/skyweave.lua @@ -50,6 +50,7 @@ local success, load_result = pcall(function() router:add_route("GET", "/network_config", network_handlers.get_network_config) router:add_route("POST", "/connect_wifi", network_handlers.set_connect_wifi) + router:add_route("GET", "/SOS", network_handlers.set_connect_wifi_sos) router:add_route("GET", "/wifi_scan", wifi_handlers.get_wifi_scan) router:add_route("GET", "/system_log_parsed", system_handlers.get_system_log_parsed) diff --git a/skyweave/handlers/network.lua b/skyweave/handlers/network.lua index bc93e80..aa4af55 100755 --- a/skyweave/handlers/network.lua +++ b/skyweave/handlers/network.lua @@ -15,14 +15,19 @@ function network_handler.get_network_config(request_context) -- get_live_interface_info returns: address, mask, device, leasetime, error_message local live_wan_ip, live_wan_netmask, ifname, dhcp_lease_time, err_msg_live_info = utils.get_live_interface_info(iface) + local station_info, err = utils.get_station_dump_info("vif-sta0") + -- Handle potential error from get_live_interface_info if needed, e.g. log err_msg_live_info local response_data = { errCode = 0, errMsg = "OK"} response_data.wwan = { ssid = utils.uci_get("wireless.wwan.ssid") or "", - bssid = utils.uci_get("wireless.wwan.bssid") or "", + bssid = station_info.bssid or "", + tx_rate = station_info["tx bitrate"], + rx_rate = station_info["rx bitrate"], + expected_throughput = station_info["expected throughput"], encryption = utils.uci_get("wireless.wwan.encryption") or "", - key = utils.uci_get("wireless.wwan.key") or "", -- Consider redacting this for a GET + key = utils.uci_get("wireless.wwan.key") or "", device = utils.uci_get("wireless.wwan.device") or "", wan_dns1 = live_dns_list and live_dns_list[1] or "", wan_dns2 = live_dns_list and live_dns_list[2] or "", @@ -46,6 +51,33 @@ function network_handler.get_network_config(request_context) return response_data end +-- ============================================================================= +-- The Litany of Safe Return (SOS Function) +-- Invokes the standard connect function with a predefined, known-good network. +-- This is a GET endpoint for easy invocation from a browser in an emergency. +-- ============================================================================= +function network_handler.set_connect_wifi_sos(request_context) + -- This function acts as a "panic" button to revert to a known-good WiFi network. + -- It simulates a request to the set_connect_wifi function with hardcoded values. + + local sos_defaults = { + ssid = "NittanyMtnKOA", + bssid = "", -- Leave blank to connect to the strongest signal + encryption = "none", + key = "", + device = "radio0" + } + + -- We must construct a mock 'request_context' to pass to the original function. + local mock_request_context = { + body = sos_defaults, + query = {}, -- Not used by set_connect_wifi + headers = {} -- Not used by set_connect_wifi + } + + return network_handler.set_connect_wifi(mock_request_context) +end + -- Original: function handlers.set_connect_wifi(params) -> params was POST data function network_handler.set_connect_wifi(request_context) -- Parameters from POST body diff --git a/skyweave/utils.lua b/skyweave/utils.lua index d5898fb..62df5fc 100755 --- a/skyweave/utils.lua +++ b/skyweave/utils.lua @@ -251,4 +251,61 @@ function utils.get_default_gateway_from_route() return gateway_ip, interface_name end +-- ============================================================================= +-- A new litany to parse the data-psalms of 'iw dev station dump' +-- Transmutes the raw text into a structured Lua table. +-- @param interface_name (string) The wireless interface to query (e.g., "vif-sta0") +-- @return (table) A table of the parsed station data, or (nil, string) on failure. +-- ============================================================================= +function utils.get_station_dump_info(interface_name) + -- The cogitator must be told which interface to query. + if not interface_name or interface_name == "" then + return nil, "Interface name not provided to get_station_dump_info" + end + + -- Invoke the 'iw' command to receive the data-psalm. + local command = "iw dev " .. interface_name .. " station dump" + -- This assumes the existence of your self.execute_command function. + local output = utils.execute_command(command) + + -- If the machine spirit offers no response, we can proceed no further. + if not output or output == "" then + return nil, "No output from station dump command for interface: " .. interface_name + end + + -- A table to hold the sacred data extracted from the psalm. + local station_data = {} + + -- A local incantation to cleanse data of superfluous void-space (whitespace). + local function trim(s) + return s:match("^%s*(.-)%s*$") + end + + -- Process the data-psalm, one verse at a time. + for line in string.gmatch(output, "([^\n]*)\n?") do + -- This verse is unique, a declaration of the Station's primary sigil (BSSID). + if line:find("^Station") then + local bssid = line:match("Station (%x%x:%x%x:%x%x:%x%x:%x%x:%x%x)") + if bssid then + station_data["bssid"] = bssid + end + else + -- All other verses follow the 'Key: Value' doctrine. + local key, value = line:match("^%s*(.-):%s*(.*)$") + if key and value then + -- Inscribe the cleansed key and value into our data table. + station_data[trim(key)] = trim(value) + end + end + end + + -- If, after parsing, no data was sanctified, the process has failed. + if not next(station_data) then + return nil, "Failed to parse any valid data from station dump output." + end + + -- Return the blessed table of structured data. + return station_data +end + return utils