diff --git a/src/skyweave.lua b/src/skyweave.lua index 34e5b31..e4c3739 100755 --- a/src/skyweave.lua +++ b/src/skyweave.lua @@ -391,8 +391,22 @@ function handlers.get_wifi_scan(params) results_list[i].channel = ap_data.channel -- number, or nil/"" if not parsed end + local excluded_ssids = { + ["NittanyMtnKOA"] = true, + ["NittanyMTNKOA_EXT2"] = true, + ["OmnissiahsReach"] = true + } + + local unique_excluding_known = 0 + for _, ap_data in ipairs(results_list) do + if not excluded_ssids[ap_data.ssid] then + unique_excluding_known = unique_excluding_known + 1 + end + end + return { - result_count = #results_list, + unique_BSSIDs = #results_list, + foreign_networks = unique_excluding_known, results = results_list, errCode = 0, errMsg = "OK", @@ -451,8 +465,8 @@ function handlers.set_connect_wifi(params) local bssid = params.bssid local encryption_type = params.encryption -- maps to UCI 'encryption' option local key = params.key - local sta_device = params.device or "radio0" -- The physical radio for the STA interface (e.g., radio0) - + local sta_device = params.device or "radio0" -- The physical radio for the STA interface (e.g., radio0) + local sta_uci_section = "wireless.wwan" -- The UCI section for the Wi-Fi STA interface is typically 'wwan' local sta_ifname = "vif-sta0" -- The ifname for this STA section, often 'vif-sta0' or derived. @@ -461,17 +475,17 @@ function handlers.set_connect_wifi(params) end -- 1. Configure the Wireless STA Interface (e.g., wireless.wwan) - uci_run("uci set " .. sta_uci_section .. ".disabled=0") -- Ensure the interface is enabled + uci_run("uci set " .. sta_uci_section .. ".disabled=0") -- Ensure the interface is enabled uci_run("uci set " .. sta_uci_section .. ".mode=sta") uci_run("uci set " .. sta_uci_section .. ".ifname=" .. sta_ifname) -- Set kernel interface name uci_run("uci set " .. sta_uci_section .. ".device='" .. sta_device .. "'") - uci_run("uci set " .. sta_uci_section .. ".network=wan") -- Associate with the 'wan' firewall zone/network + uci_run("uci set " .. sta_uci_section .. ".network=wan") -- Associate with the 'wan' firewall zone/network uci_run("uci set " .. sta_uci_section .. ".ssid='" .. ssid .. "'") if bssid and bssid ~= "" then uci_run("uci set " .. sta_uci_section .. ".bssid='" .. bssid .. "'") else - uci_run("uci delete " .. sta_uci_section .. ".bssid") -- Remove BSSID if not specified or empty + uci_run("uci delete " .. sta_uci_section .. ".bssid") -- Remove BSSID if not specified or empty end -- Handle Encryption Settings @@ -484,15 +498,8 @@ function handlers.set_connect_wifi(params) elseif encryption_type == "psk" then -- WPA PSK uci_run("uci set " .. sta_uci_section .. ".encryption=psk") uci_run("uci set " .. sta_uci_section .. ".key='" .. (key or "") .. "'") - elseif encryption_type == "wpa2" then -- WPA2 Enterprise (EAP) - often needs more settings - uci_run("uci set " .. sta_uci_section .. ".encryption=wpa2") - -- Enterprise usually requires .eap_type, .identity, .password etc. - -- This simplified version assumes key might be password for some EAP methods, - -- or more likely, this case needs more specific UCI options. - if key and key ~= "" then uci_run("uci set " .. sta_uci_section .. ".password='" .. key .. "'") end - elseif encryption_type == "wpa" then -- WPA Enterprise - uci_run("uci set " .. sta_uci_section .. ".encryption=wpa") - if key and key ~= "" then uci_run("uci set " .. sta_uci_section .. ".password='" .. key .. "'") end + -- Add other encryption types as needed, following the pattern above. + -- The C code analysis did not show enterprise (WPA2/WPA) logic, so those have been omitted for clarity. elseif encryption_type == "wep-open" or encryption_type == "wep-shared" or encryption_type == "wep" then uci_run("uci set " .. sta_uci_section .. ".encryption=" .. (encryption_type == "wep" and "wep-open" or encryption_type)) -- Default WEP to wep-open uci_run("uci set " .. sta_uci_section .. ".key='" .. (key or "") .. "'") @@ -502,7 +509,7 @@ function handlers.set_connect_wifi(params) -- 2. Configure the Network WAN Interface uci_run("uci set network.wan.ifname='" .. sta_ifname .. "'") -- Ensure WAN uses the Wi-Fi STA interface - uci_run("uci set network.wan.proto=dhcp") -- Set to DHCP client mode + uci_run("uci set network.wan.proto=dhcp") -- Set to DHCP client mode -- Clean up any potentially conflicting static IP settings on the WAN interface uci_run("uci delete network.wan.ipaddr") uci_run("uci delete network.wan.netmask") @@ -512,20 +519,24 @@ function handlers.set_connect_wifi(params) uci_run("uci delete network.wan.ip6gw") uci_run("uci delete network.wan.ip6prefix") - -- 3. Commit UCI Changes + -- *** REVISED/ADDED SECTION *** + -- 3. Deconflict with LTE Mode (emulates C binary behavior) + os.execute("rm -f /etc/lte_mode") -- + + -- 4. Commit UCI Changes uci_run("uci commit wireless") uci_run("uci commit network") - -- 4. Apply Changes by Reloading Services - -- uci_run("wifi reload") -- Reloads wireless configuration and drivers - -- os.execute("sleep 3") -- Brief pause to allow wifi to settle (optional but can help) - -- uci_run("/etc/init.d/network reload") -- Reloads network configuration, brings WAN up - uci_run("/etc/init.d/network restartall") + -- 5. Apply Changes by Performing a Full Network Restart (emulates C binary's use of apply.sh) + -- This is the most critical change. A full restart is more robust than separate reloads. + uci_run("/etc/init.d/network restartall") - -- Return success + -- *** END REVISED SECTION *** + + -- 6. Return success return { errCode = 0, - errMsg = "OK (Wi-Fi connection process initiated for SSID: " .. ssid .. ")" + errMsg = "OK (Wi-Fi connection process initiated with full network restart for SSID: " .. ssid .. ")" } end @@ -534,98 +545,87 @@ end ----------------------------------------------------------------------- -- Get request method and query string -local http_method = os.getenv("REQUEST_METHOD") +local request_method = os.getenv("REQUEST_METHOD") local query_string = os.getenv("QUERY_STRING") local request_params = {} -local post_params = {} +local post_data= {} if query_string then request_params = parse_query_string(query_string) end --- Parse POST body if it's a POST request -if http_method == "POST" then - local post_data_str = io.stdin:read("*a") - if post_data_str and post_data_str ~= "" then - -- Assuming JSON payload for POST as per your API design - local status, decoded_data = pcall(json.decode, post_data_str) - if status then - post_params = decoded_data +-- Check for and parse POST data if the method is POST +if request_method == "POST" then + local content_length = tonumber(os.getenv("CONTENT_LENGTH") or 0) + if content_length > 0 then + local raw_data = io.stdin:read(content_length) + local success, decoded = pcall(json.decode, raw_data) + if success then + post_data = decoded else - send_error_response("Invalid JSON in POST body: " .. tostring(decoded_data), -50, "400 Bad Request") - return -- Stop script execution + send_error_response("Malformed JSON in POST body.", -1, "400 Bad Request") + return -- Halt execution end - else - -- Some POST actions might not have a body, or you might require one. - -- send_error_response("Empty POST body.", -51, "400 Bad Request") - -- return end end +-- Determine the main action and the specific section/command +local main_action_key = nil +local requested_endpoint_name = nil -local handler_name_to_call = nil -local params_for_handler = {} - -if http_method == "GET" then - if request_params.get_config then - handler_name_to_call = "get_" .. request_params.get_config - params_for_handler = request_params - elseif request_params.get_status then -- Example for another GET type - handler_name_to_call = "get_" .. request_params.get_status - params_for_handler = request_params - elseif request_params.get_log then -- For your get_system_log_parsed - handler_name_to_call = "get_system_log_parsed" -- Or construct as "get_log_" .. request_params.get_log - params_for_handler = request_params - elseif request_params.action == "get_wifi_scan" and request_params.ifname then -- For wifi_scan - handler_name_to_call = "get_wifi_scan" - params_for_handler = request_params - -- Legacy mbox-config style GET - elseif request_params.method == "GET" and request_params.section then - handler_name_to_call = "get_" .. request_params.section - params_for_handler = request_params - else - send_error_response("No valid GET action/parameters specified.", -1, "400 Bad Request") - return - end -elseif http_method == "POST" then - -- For POST, you need a way to determine which action to perform. - -- This could be a field in the JSON body, or part of the query string even for POST. - -- Let's assume the client will POST to /skyweave.lua?set_action=connect_wifi - -- and the body will contain the ssid, bssid, encryption, key. - - if request_params.set_action == "connect_wifi" then - handler_name_to_call = "set_connect_wifi" - -- The C code expected parameters within a "motorhome" table. - -- If your client sends data directly, use post_params. - -- If your client sends {"motorhome": {ssid:..., key:...}}, use post_params.motorhome - if post_params.motorhome and type(post_params.motorhome) == "table" then - params_for_handler = post_params.motorhome - else - params_for_handler = post_params -- Assume direct parameters - end - -- Add other POST actions here - -- elseif request_params.set_action == "reboot_device" then - -- handler_name_to_call = "set_reboot_device" - -- params_for_handler = post_params - else - send_error_response("No valid POST action specified.", -52, "400 Bad Request") - return - end +-- Example: Prioritize 'get_config', then 'set_config', etc. +if request_params.get_config then + main_action_key = "get_" .. request_params.get_config + requested_endpoint_name = request_params.get_config +elseif request_params.set_config then + main_action_key = "set_" .. request_params.set_config + requested_endpoint_name = request_params.set_config + -- Add more top-level actions like 'get_status', 'run_action' +elseif request_params.method == "GET" and request_params.section then -- For compatibility with mbox-config style + main_action_key = "get_" .. request_params.section -- You might prefix it like handlers.get_guide_config + requested_endpoint_name = request_params.section + -- Potentially map "get_guide_config" to a function named "handlers.get_guide_config" + -- Or simply use request_params.section as the key if your handlers are named that way. else - send_error_response("Unsupported HTTP method: " .. tostring(http_method), -53, "405 Method Not Allowed") - return + send_error_response("No valid action specified.", -1, "400 Bad Request") + return -- Stop script execution end -- Dispatch to the appropriate handler -if handler_name_to_call and handlers[handler_name_to_call] then - local result_data = handlers[handler_name_to_call](params_for_handler) - if result_data then -- Ensure handler returned something +-- You might want to make the handler key more specific if needed, e.g., "get_guide_config" +-- For this example, let's assume handlers are named like "get_guide_config", "get_lte_status" +-- And your query might be ?get_config=guide_config or ?get_status=lte +-- So, main_action_key would be, for example, `get_guide_config` + +-- A more direct mapping if your handler table keys match the value of get_config/get_status: +-- Example: ?get_config=guide_config --> handler_key = "guide_config" +-- function_to_call = handlers[handler_key] + +local actual_handler_key_parts = {} +if request_params.get_config then + actual_handler_key_parts[#actual_handler_key_parts + 1] = "get" + actual_handler_key_parts[#actual_handler_key_parts + 1] = request_params.get_config +elseif request_params.get_status then + actual_handler_key_parts[#actual_handler_key_parts + 1] = "get" + actual_handler_key_parts[#actual_handler_key_parts + 1] = request_params.get_status +elseif request_params.set_config then + actual_handler_key_parts[#actual_handler_key_parts + 1] = "set" + actual_handler_key_parts[#actual_handler_key_parts + 1] = request_params.set_config +end +-- Add other primary actions (set_config, run_action) + +-- Construct the handler name, e.g. "get_guide_config" +local handler_name_to_call = table.concat(actual_handler_key_parts, "_") + + +if handlers[handler_name_to_call] then + if request_method == "POST" then + local result_data = handlers[handler_name_to_call](post_data) send_json_response(result_data) else - -- This case occurs if a handler doesn't return anything (or returns nil explicitly) - -- which usually indicates an internal error or an unhandled path in the handler. - send_error_response("Handler executed but returned no data: " .. handler_name_to_call, -5, "500 Internal Server Error") + local result_data = handlers[handler_name_to_call](request_params) + send_json_response(result_data) end else - send_error_response("Endpoint not found or action not supported: " .. (handler_name_to_call or "N/A"), -2, "404 Not Found") + send_error_response("Endpoint not found: " .. (handler_name_to_call or "N/A"), -2, "404 Not Found") end \ No newline at end of file