NetworkManager: Always prefer system APs as intended.

If we had a local prefered AP with a higher RSSI,
we attempted to associate with it over wpa_supplicant
being already attempting to associate with its own preferred AP.
That... failed horribly.

Also adapt to the new lj-wpaclient API, fixing a few other edge-cases,
and making the whole thing slightly faster because we no longer
uselessly sleep.
And more reliable because we now actually wait for replies to our
requests.

Bump base

https://github.com/koreader/koreader-base/pull/1424
pull/8403/head
NiLuJe 3 years ago
parent 1ff19f8ba7
commit bc5da5276d

@ -1 +1 @@
Subproject commit 5c8fa477f8abca437950420e08efa3d2ef0da1bf Subproject commit e0643c89f924718cf04b8e56502e68e172a355dd

@ -599,6 +599,7 @@ function NetworkMgr:reconnectOrShowNetworkMenu(complete_callback)
-- rescan if the first scan appeared to yield an empty list. -- rescan if the first scan appeared to yield an empty list.
--- @fixme This *might* be an issue better handled in lj-wpaclient... --- @fixme This *might* be an issue better handled in lj-wpaclient...
if #network_list == 0 then if #network_list == 0 then
logger.warn("Initial Wi-Fi scan yielded no results, rescanning")
network_list, err = self:getNetworkList() network_list, err = self:getNetworkList()
if network_list == nil then if network_list == nil then
UIManager:show(InfoMessage:new{text = err}) UIManager:show(InfoMessage:new{text = err})
@ -613,27 +614,53 @@ function NetworkMgr:reconnectOrShowNetworkMenu(complete_callback)
if self.wifi_toggle_long_press then if self.wifi_toggle_long_press then
self.wifi_toggle_long_press = nil self.wifi_toggle_long_press = nil
else else
local ssid
-- We need to do two passes, as we may have *both* an already connected network (from the global wpa config),
-- *and* preferred networks, and if the prferred networks have a better signal quality,
-- they'll be sorted *earlier*, which would cause us to try to associate to a different AP than
-- what wpa_supplicant is already trying to do...
for dummy, network in ipairs(network_list) do for dummy, network in ipairs(network_list) do
if network.connected then if network.connected then
-- On platforms where we use wpa_supplicant (if we're calling this, we are), -- On platforms where we use wpa_supplicant (if we're calling this, we are),
-- the invocation will check its global config, and if an AP configured there is reachable, -- the invocation will check its global config, and if an AP configured there is reachable,
-- it'll already have connected to it on its own. -- it'll already have connected to it on its own.
success = true success = true
elseif network.password then ssid = network.ssid
success = NetworkMgr:authenticateNetwork(network) break
end end
if success then end
NetworkMgr:obtainIP()
if complete_callback then -- Next, look for our own prferred networks...
complete_callback() local err_msg = _("Connection failed")
if not success then
for dummy, network in ipairs(network_list) do
if network.password then
-- If we hit a preferred network and we're not already connected,
-- attempt to connect to said preferred network....
success, err_msg = NetworkMgr:authenticateNetwork(network)
if success then
ssid = network.ssid
break
end
end end
UIManager:show(InfoMessage:new{
text = T(_("Connected to network %1"), BD.wrap(network.ssid)),
timeout = 3,
})
break
end end
end end
if success then
NetworkMgr:obtainIP()
if complete_callback then
complete_callback()
end
UIManager:show(InfoMessage:new{
text = T(_("Connected to network %1"), BD.wrap(ssid)),
timeout = 3,
})
else
UIManager:show(InfoMessage:new{
text = err_msg,
timeout = 3,
})
end
end end
if not success then if not success then
-- NOTE: Also supports a disconnect_callback, should we use it for something? -- NOTE: Also supports a disconnect_callback, should we use it for something?

@ -4,7 +4,7 @@ WPA client helper for Kobo.
local FFIUtil = require("ffi/util") local FFIUtil = require("ffi/util")
local InfoMessage = require("ui/widget/infomessage") local InfoMessage = require("ui/widget/infomessage")
local WpaClient = require('lj-wpaclient/wpaclient') local WpaClient = require("lj-wpaclient/wpaclient")
local UIManager = require("ui/uimanager") local UIManager = require("ui/uimanager")
local _ = require("gettext") local _ = require("gettext")
local T = FFIUtil.template local T = FFIUtil.template
@ -20,13 +20,17 @@ function WpaSupplicant:getNetworkList()
return nil, T(CLIENT_INIT_ERR_MSG, err) return nil, T(CLIENT_INIT_ERR_MSG, err)
end end
local list = wcli:scanThenGetResults() local list
list, err = wcli:scanThenGetResults()
wcli:close() wcli:close()
if list == nil then
return nil, T("An error occurred while scanning: %1.", err)
end
local saved_networks = self:getAllSavedNetworks() local saved_networks = self:getAllSavedNetworks()
local curr_network = self:getCurrentNetwork() local curr_network = self:getCurrentNetwork()
for _,network in ipairs(list) do for _, network in ipairs(list) do
network.signal_quality = network:getSignalQuality() network.signal_quality = network:getSignalQuality()
local saved_nw = saved_networks:readSetting(network.ssid) local saved_nw = saved_networks:readSetting(network.ssid)
if saved_nw then if saved_nw then
@ -58,27 +62,30 @@ end
--- Authenticates network. --- Authenticates network.
function WpaSupplicant:authenticateNetwork(network) function WpaSupplicant:authenticateNetwork(network)
local err, wcli, nw_id local wcli, reply, err
wcli, err = WpaClient.new(self.wpa_supplicant.ctrl_interface) wcli, err = WpaClient.new(self.wpa_supplicant.ctrl_interface)
if not wcli then if not wcli then
return false, T(CLIENT_INIT_ERR_MSG, err) return false, T(CLIENT_INIT_ERR_MSG, err)
end end
nw_id, err = wcli:addNetwork() reply, err = wcli:addNetwork()
if err then return false, err end if reply == nil then
return false, err
end
local nw_id = reply
local re = wcli:setNetwork(nw_id, "ssid", string.format("\"%s\"", network.ssid)) reply, err = wcli:setNetwork(nw_id, "ssid", string.format("\"%s\"", network.ssid))
if re == "FAIL" then if reply == nil or reply == "FAIL" then
wcli:removeNetwork(nw_id) wcli:removeNetwork(nw_id)
return false, _("An error occurred while selecting network.") return false, T("An error occurred while selecting network: %1.", err)
end end
-- if password is empty its an open AP -- if password is empty its an open AP
if network.password and #network.password == 0 then -- Open AP if network.password and #network.password == 0 then -- Open AP
re = wcli:setNetwork(nw_id, "key_mgmt", "NONE") reply, err = wcli:setNetwork(nw_id, "key_mgmt", "NONE")
if re == "FAIL" then if reply == nil or reply == "FAIL" then
wcli:removeNetwork(nw_id) wcli:removeNetwork(nw_id)
return false, _("An error occurred while setting passwordless mode.") return false, T("An error occurred while setting passwordless mode: %1.", err)
end end
-- else its a WPA AP -- else its a WPA AP
else else
@ -86,10 +93,10 @@ function WpaSupplicant:authenticateNetwork(network)
network.psk = calculatePsk(network.ssid, network.password) network.psk = calculatePsk(network.ssid, network.password)
self:saveNetwork(network) self:saveNetwork(network)
end end
re = wcli:setNetwork(nw_id, "psk", network.psk) reply, err = wcli:setNetwork(nw_id, "psk", network.psk)
if re == "FAIL" then if reply == nil or reply == "FAIL" then
wcli:removeNetwork(nw_id) wcli:removeNetwork(nw_id)
return false, _("An error occurred while setting password.") return false, T("An error occurred while setting password: %1.", err)
end end
end end
wcli:enableNetworkByID(nw_id) wcli:enableNetworkByID(nw_id)
@ -99,10 +106,32 @@ function WpaSupplicant:authenticateNetwork(network)
local failure_cnt = 0 local failure_cnt = 0
local max_retry = 30 local max_retry = 30
local info = InfoMessage:new{text = _("Authenticating…")} local info = InfoMessage:new{text = _("Authenticating…")}
local msg local success = false
local msg = _("Authenticated")
UIManager:show(info) UIManager:show(info)
UIManager:forceRePaint() UIManager:forceRePaint()
while cnt < max_retry do while cnt < max_retry do
-- Start by checking if we're not actually connected already...
-- NOTE: This is mainly to catch corner-cases where our preferred network list differs from the system's,
-- and ours happened to be sorted earlier because of a better signal quality...
local connected, state = wcli:getConnectedNetwork()
if connected then
network.wpa_supplicant_id = connected.id
network.ssid = connected.ssid
success = true
break
else
if state then
UIManager:close(info)
-- Make the state prettier
local first, rest = state:sub(1, 1), state:sub(2)
info = InfoMessage:new{text = string.upper(first) .. string.lower(rest) .. ""}
UIManager:show(info)
UIManager:forceRePaint()
end
end
-- Otherwise, poke at the wpa_supplicant socket for a bit...
local ev = wcli:readEvent() local ev = wcli:readEvent()
if ev ~= nil then if ev ~= nil then
if not ev:isScanEvent() then if not ev:isScanEvent() then
@ -113,28 +142,30 @@ function WpaSupplicant:authenticateNetwork(network)
end end
if ev:isAuthSuccessful() then if ev:isAuthSuccessful() then
network.wpa_supplicant_id = nw_id network.wpa_supplicant_id = nw_id
re = true success = true
break break
elseif ev:isAuthFailed() then elseif ev:isAuthFailed() then
failure_cnt = failure_cnt + 1 failure_cnt = failure_cnt + 1
if failure_cnt > 3 then if failure_cnt > 3 then
re, msg = false, _("Failed to authenticate") success, msg = false, _("Failed to authenticate")
break break
end end
end end
else else
FFIUtil.sleep(1) wcli:waitForEvent(1 * 1000)
cnt = cnt + 1 cnt = cnt + 1
end end
end end
if re ~= true then wcli:removeNetwork(nw_id) end if success ~= true then
wcli:removeNetwork(nw_id)
end
wcli:close() wcli:close()
UIManager:close(info) UIManager:close(info)
UIManager:forceRePaint() UIManager:forceRePaint()
if cnt >= max_retry then if cnt >= max_retry then
re, msg = false, _("Timed out") success, msg = false, _("Timed out")
end end
return re, msg return success, msg
end end
function WpaSupplicant:disconnectNetwork(network) function WpaSupplicant:disconnectNetwork(network)

Loading…
Cancel
Save