wifi_drv: add hidden network support

Fixes #2988.
This commit is contained in:
Josef Söntgen 2018-09-13 15:13:23 +02:00 committed by Christian Helmuth
parent 8193e7b3b4
commit ecccbb46cb
9 changed files with 366 additions and 184 deletions

View File

@ -22,7 +22,7 @@ extern "C" {
struct Msg_buffer struct Msg_buffer
{ {
unsigned char recv[4096]; unsigned char recv[4096*8];
unsigned char send[1024]; unsigned char send[1024];
unsigned recv_id; unsigned recv_id;
unsigned send_id; unsigned send_id;

View File

@ -93,3 +93,16 @@ index 436bc8c99..f5ff4facb 100644
#endif /* CONFIG_ELOOP_POLL */ #endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_EPOLL #ifdef CONFIG_ELOOP_EPOLL
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index fe39c25b7..3a682785e 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -9778,7 +9778,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
char *buf, size_t *resp_len)
{
char *reply;
- const int reply_size = 4096;
+ const int reply_size = 4096*8;
int reply_len;
if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||

View File

@ -1 +1 @@
5ee7d9befaff281fec480e2257f302c76fe85126 85b33124266df46e53981153e5014fd372d0680d

View File

@ -113,8 +113,8 @@ append config {
<config verbose="no"> <config verbose="no">
<rom name="wifi_config"> <rom name="wifi_config">
<inline description="CONNECT"> <inline description="CONNECT">
<wifi_config connected_scan_interval="30" scan_interval="5" rfkill="no" verbose="no"> <wifi_config connected_scan_interval="0" scan_interval="5" rfkill="no" verbose="no" verbose_state="no">
<accesspoint enabled="true" ssid="} [wifi_ssid] {" protection="WPA2" passphrase="} [wifi_psk] {"/> <network ssid="} [wifi_ssid] {" protection="WPA2" passphrase="} [wifi_psk] {"/>
</wifi_config> </wifi_config>
</inline> </inline>
<sleep milliseconds="600000"/> <!-- 10 minutes --> <sleep milliseconds="600000"/> <!-- 10 minutes -->

View File

@ -79,7 +79,15 @@ append config {
</config> </config>
</start> </start>
<start name="report_rom"> <start name="scan_report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="2M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="no"/>
</start>
<start name="accesspoints_report_rom">
<binary name="report_rom"/>
<resource name="RAM" quantum="2M"/> <resource name="RAM" quantum="2M"/>
<provides> <service name="Report"/> <service name="ROM"/> </provides> <provides> <service name="Report"/> <service name="ROM"/> </provides>
<config verbose="no"/> <config verbose="no"/>
@ -91,30 +99,28 @@ append config {
<provides><service name="ROM"/></provides> <provides><service name="ROM"/></provides>
<config verbose="yes"> <config verbose="yes">
<rom name="wifi_config"> <rom name="wifi_config">
<inline description="disconnect">
<wifi_config connected_scan_interval="30" scan_interval="5" rfkill="no" verbose="no" verbose_state="no"/>
</inline>
<sleep milliseconds="15000"/>
<inline description="connect"> <inline description="connect">
<wifi_config connected_scan_interval="30" scan_interval="5" rfkill="no" verbose="yes"> <wifi_config connected_scan_interval="30" scan_interval="5" rfkill="no" verbose="no" verbose_state="no">
<accesspoint ssid="} [wifi_ssid] {" protection="WPA2" passphrase="} [wifi_psk] {"/> <network ssid="} [wifi_ssid] {" protection="WPA2" explicit_scan="true" passphrase="} [wifi_psk] {"/>
</wifi_config> </wifi_config>
</inline> </inline>
<sleep milliseconds="60000"/> <sleep milliseconds="60000"/>
<inline description="rfkill block"> <inline description="rfkill block">
<wifi_config connected_scan_interval="30" scan_interval="5" rfkill="yes" verbose="yes"> <wifi_config connected_scan_interval="30" scan_interval="5" rfkill="yes" verbose="no" verbose_state="no">
<accesspoint ssid="} [wifi_ssid] {" protection="WPA2" passphrase="} [wifi_psk] {"/> <network ssid="} [wifi_ssid] {" protection="WPA2" explicit_scan="true" passphrase="} [wifi_psk] {"/>
</wifi_config> </wifi_config>
</inline> </inline>
<sleep milliseconds="30000"/> <sleep milliseconds="30000"/>
<inline description="rfkill unblock"> <inline description="rfkill unblock">
<wifi_config connected_scan_interval="30" scan_interval="5" rfkill="no" verbose="yes"> <wifi_config connected_scan_interval="30" scan_interval="5" rfkill="no" verbose="no" verbose_state="no">
<accesspoint ssid="} [wifi_ssid] {" protection="WPA2" passphrase="} [wifi_psk] {"/> <network ssid="} [wifi_ssid] {" protection="WPA2" explicit_scan="true" passphrase="} [wifi_psk] {"/>
</wifi_config> </wifi_config>
</inline> </inline>
<sleep milliseconds="30000"/> <sleep milliseconds="30000"/>
<inline description="disconnect">
<wifi_config connected_scan_interval="30" scan_interval="5" rfkill="no" verbose="yes">
<accesspoint ssid="} [wifi_ssid] {" protection="WPA2" passphrase="} [wifi_psk] {"/>
</wifi_config>
</inline>
<sleep milliseconds="60000"/>
</rom> </rom>
</config> </config>
</start> </start>
@ -133,7 +139,8 @@ append config {
</config> </config>
<route> <route>
<service name="Rtc"> <any-child/> </service> <service name="Rtc"> <any-child/> </service>
<service name="Report"> <child name="report_rom"/> </service> <service name="Report" label="accesspoints"> <child name="accesspoints_report_rom"/> </service>
<service name="Report" label="state"> <child name="scan_report_rom"/> </service>
<service name="ROM" label="wifi_config"> <child name="config_rom"/> </service> <service name="ROM" label="wifi_config"> <child name="config_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service> <any-service> <parent/> <any-child/> </any-service>
</route> </route>

View File

@ -71,12 +71,13 @@ static struct Recv_msg_table {
char const *string; char const *string;
size_t len; size_t len;
} recv_table[] = { } recv_table[] = {
{ "OK", 2 }, { "OK", 2 },
{ "FAIL", 4 }, { "FAIL", 4 },
{ "CTRL-EVENT-SCAN-RESULTS", 23 }, { "CTRL-EVENT-SCAN-RESULTS", 23 },
{ "CTRL-EVENT-CONNECTED", 20 }, { "CTRL-EVENT-CONNECTED", 20 },
{ "CTRL-EVENT-DISCONNECTED", 23 }, { "CTRL-EVENT-DISCONNECTED", 23 },
{ "SME: Trying to authenticate", 27 }, { "SME: Trying to authenticate", 27 },
{ "CTRL-EVENT-NETWORK-NOT-FOUND", 28 },
}; };
enum Rmi { enum Rmi {
@ -86,6 +87,7 @@ enum Rmi {
CONNECTED, CONNECTED,
DISCONNECTED, DISCONNECTED,
SME_AUTH, SME_AUTH,
NOT_FOUND,
}; };
@ -110,6 +112,10 @@ static bool connecting_to_network(char const *msg) {
return check_recv_msg(msg, recv_table[SME_AUTH]); } return check_recv_msg(msg, recv_table[SME_AUTH]); }
static bool network_not_found(char const *msg) {
return check_recv_msg(msg, recv_table[NOT_FOUND]); }
static bool scan_results(char const *msg) { static bool scan_results(char const *msg) {
return Genode::strcmp("bssid", msg, 5) == 0; } return Genode::strcmp("bssid", msg, 5) == 0; }
@ -151,12 +157,13 @@ struct Accesspoint
int id { -1 }; int id { -1 };
bool enabled { false }; bool enabled { false };
/* /*
* Internal configuration fields * Internal configuration fields
*/ */
bool auto_connect { false }; bool auto_connect { false };
bool update { false }; bool update { false };
bool stale { false }; bool stale { false };
bool explicit_scan { false };
/** /**
* Default constructor * Default constructor
@ -171,11 +178,12 @@ struct Accesspoint
: bssid(bssid), freq(freq), prot(prot), ssid(ssid), signal(signal) : bssid(bssid), freq(freq), prot(prot), ssid(ssid), signal(signal)
{ } { }
void invalidate() { ssid = Ssid(); } void invalidate() { ssid = Ssid(); bssid = Bssid(); }
bool valid() const { return ssid.length() > 1; } bool valid() const { return ssid.length() > 1; }
bool wpa() const { return prot != "NONE"; } bool bssid_valid() const { return bssid.length() > 1; }
bool stored() const { return id != -1; } bool wpa() const { return prot != "NONE"; }
bool stored() const { return id != -1; }
}; };
@ -343,7 +351,7 @@ struct Wifi::Frontend
} }
if (_rfkilled && _state != State::IDLE) { if (_rfkilled && _state != State::IDLE) {
Genode::warning(__func__, ": rfkilled with ", state_strings(_state)); Genode::warning("rfkilled in state ", state_strings(_state));
} }
} }
@ -357,12 +365,12 @@ struct Wifi::Frontend
bool _use_11n { true }; bool _use_11n { true };
bool _deferred_config_update { false }; bool _deferred_config_update { false };
bool _fake_connecting { false }; bool _single_autoconnect { false };
unsigned _connected_scan_interval { 15 }; unsigned _connected_scan_interval { 15 };
unsigned _scan_interval { 5 }; unsigned _scan_interval { 5 };
void _handle_config_update() void _config_update(bool signal)
{ {
_config_rom.update(); _config_rom.update();
@ -400,7 +408,18 @@ struct Wifi::Frontend
* by the singal handler but is not expected to be any different * by the singal handler but is not expected to be any different
* as the rfkill call is not supposed to fail. * as the rfkill call is not supposed to fail.
*/ */
if (blocked) { _rfkilled = true; } if (blocked && !_rfkilled) {
_rfkilled = true;
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () {
xml.attribute("state", "disconnected");
xml.attribute("rfkilled", _rfkilled);
});
});
_connected_ap.invalidate();
}
} }
/* /*
@ -413,90 +432,92 @@ struct Wifi::Frontend
return; return;
} }
bool fake_connecting = false; bool single_autoconnect = false;
/* update AP list */ /* update AP list */
try { auto parse = [&] ( Genode::Xml_node node) {
config.for_each_sub_node("accesspoint", [&] ( Genode::Xml_node node) {
Accesspoint ap; Accesspoint ap;
ap.ssid = node.attribute_value("ssid", Accesspoint::Ssid("")); ap.ssid = node.attribute_value("ssid", Accesspoint::Ssid());
ap.bssid = node.attribute_value("bssid", Accesspoint::Bssid("")); ap.bssid = node.attribute_value("bssid", Accesspoint::Bssid());
size_t const ssid_len = ap.ssid.length() - 1; size_t const ssid_len = ap.ssid.length() - 1;
if (ssid_len == 0 || ssid_len > 32) { if (ssid_len == 0 || ssid_len > 32) {
Genode::warning("ignoring accesspoint with invalid ssid"); Genode::warning("ignoring accesspoint with invalid ssid");
return;
}
Accesspoint *p = _lookup_ap_by_ssid(ap.ssid);
if (p) {
if (_verbose) { Genode::log("Update: '", p->ssid, "'"); }
/* mark for updating */
p->update = true;
} else {
p = _ap_slot();
if (!p) {
Genode::warning("could not add accesspoint, no slots left");
return; return;
} }
}
Accesspoint *p = _lookup_ap_by_ssid(ap.ssid); ap.pass = node.attribute_value("passphrase", Accesspoint::Pass(""));
if (p) { ap.prot = node.attribute_value("protection", Accesspoint::Prot("NONE"));
if (_verbose) { Genode::log("Update: '", p->ssid, "'"); } ap.auto_connect = node.attribute_value("auto_connect", true);
/* mark for updating */ ap.explicit_scan = node.attribute_value("explicit_scan", false);
p->update = true;
} else { if (ap.wpa()) {
p = _ap_slot(); size_t const psk_len = ap.pass.length() - 1;
if (!p) { if (psk_len < 8 || psk_len > 63) {
Genode::warning("could not add accesspoint, no slots left"); Genode::warning("ignoring accesspoint '", ap.ssid,
return; "' with invalid pass");
} return;
}
ap.pass = node.attribute_value("passphrase", Accesspoint::Pass(""));
ap.prot = node.attribute_value("protection", Accesspoint::Prot("NONE"));
ap.auto_connect = node.attribute_value("auto_connect", true);
if (ap.wpa()) {
size_t const psk_len = ap.pass.length() - 1;
if (psk_len < 8 || psk_len > 63) {
Genode::warning("ignoring accesspoint '", ap.ssid,
"' with invalid pass");
return;
}
} }
}
/* check if updating is really necessary */ /* check if updating is really necessary */
if (p->update) { if (p->update) {
p->update = (ap.bssid != p->bssid p->update = ((ap.bssid.length() > 1 && ap.bssid != p->bssid)
|| ap.pass != p->pass || ap.pass != p->pass
|| ap.prot != p->prot || ap.prot != p->prot
|| ap.auto_connect != p->auto_connect); || ap.auto_connect != p->auto_connect);
} }
/* TODO add better way to check validity */ /* TODO add better way to check validity */
if (ap.bssid.length() == 17 + 1) { p->bssid = ap.bssid; } if (ap.bssid.length() == 17 + 1) { p->bssid = ap.bssid; }
p->ssid = ap.ssid; p->ssid = ap.ssid;
p->prot = ap.prot; p->prot = ap.prot;
p->pass = ap.pass; p->pass = ap.pass;
p->auto_connect = ap.auto_connect; p->auto_connect = ap.auto_connect;
p->explicit_scan = ap.explicit_scan;
fake_connecting |= (p->update || p->auto_connect) && !_connected_ap.valid(); single_autoconnect |= (p->update || p->auto_connect) && !_connected_ap.valid();
}); };
} catch (...) { Genode::warning("accesspoint list empty"); } config.for_each_sub_node("network", parse);
/* /*
* To accomodate a management component that only deals * To accomodate a management component that only deals
* with on network, e.g. the sculpt_manager, generate a * with on network, e.g. the sculpt_manager, generate a
* fake connected event. * fake connecting event. Either a connected or disconnected
* event will bring us to square one.
*/ */
if (_count_to_be_enabled() == 1 && fake_connecting) { if (signal && _count_to_be_enabled() == 1 && single_autoconnect && !_rfkilled) {
auto lookup = [&] (Accesspoint const &ap) { auto lookup = [&] (Accesspoint const &ap) {
if (!ap.auto_connect) { return; } if (!ap.auto_connect) { return; }
if (_verbose) { Genode::log("Fake connected event for '", ap.ssid, "'"); } if (_verbose) { Genode::log("Single autoconnect event for '", ap.ssid, "'"); }
try { try {
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () { xml.node("accesspoint", [&] () {
xml.attribute("ssid", ap.ssid); xml.attribute("ssid", ap.ssid);
xml.attribute("state", "connected"); xml.attribute("state", "connecting");
}); });
}); });
_fake_connecting = true; _single_autoconnect = true;
} catch (...) { } } catch (...) { }
}; };
@ -510,6 +531,8 @@ struct Wifi::Frontend
_mark_stale_aps(config); _mark_stale_aps(config);
} }
void _handle_config_update() { _config_update(true); }
/* state */ /* state */
Accesspoint *_processed_ap { nullptr }; Accesspoint *_processed_ap { nullptr };
@ -611,14 +634,43 @@ struct Wifi::Frontend
return; return;
} }
_arm_scan_timer(_connected_ap.valid()); _arm_scan_timer(_connected_ap.bssid_valid());
/* skip as we will be scheduled some time soon(tm) anyway */ /* skip as we will be scheduled some time soon(tm) anyway */
if (_state != State::IDLE) { return; } if (_state != State::IDLE) { return; }
/* TODO scan request/pending results timeout */ /* left one attempt out */
if (_scan_busy) {
_scan_busy = false;
return;
}
enum { SSID_ARG_LEN = 64 + 5, /* "ssid " + "a5a5a5a5..." */ };
/* count * (SSID_ARG_LEN + " ") + NUL */
char ssid_buffer[MAX_ACCESSPOINTS * (SSID_ARG_LEN + 1) + 1] = { };
size_t buffer_pos = 0;
auto valid_ssid = [&] (Accesspoint const &ap) {
if (!ap.explicit_scan) { return; }
char ssid_hex[64+1] = { };
char const *ssid = ap.ssid.string();
for (size_t i = 0; i < ap.ssid.length() - 1; i++) {
Util::byte2hex((ssid_hex + i * 2), ssid[i]);
}
Genode::String<SSID_ARG_LEN + 1> tmp(" ssid ", (char const*)ssid_hex);
size_t const tmp_len = tmp.length() - 1;
Genode::memcpy((ssid_buffer + buffer_pos), tmp.string(), tmp_len);
buffer_pos += tmp_len;
};
_for_each_ap(valid_ssid);
_state_transition(_state, State::INITIATE_SCAN); _state_transition(_state, State::INITIATE_SCAN);
_submit_cmd(Cmd_str("SCAN")); _submit_cmd(Cmd_str("SCAN ", (char const*)ssid_buffer));
} }
void _arm_scan_timer(bool connected) void _arm_scan_timer(bool connected)
@ -644,6 +696,9 @@ struct Wifi::Frontend
if (!count_lines) { return; } if (!count_lines) { return; }
try { try {
bool connecting_attempt = false;
Genode::Reporter::Xml_generator xml(*_ap_reporter, [&]() { Genode::Reporter::Xml_generator xml(*_ap_reporter, [&]() {
for_each_result_line(msg, [&] (Accesspoint const &ap) { for_each_result_line(msg, [&] (Accesspoint const &ap) {
@ -658,8 +713,22 @@ struct Wifi::Frontend
xml.attribute("quality", ap.signal); xml.attribute("quality", ap.signal);
if (ap.wpa()) { xml.attribute("protection", ap.prot); } if (ap.wpa()) { xml.attribute("protection", ap.prot); }
}); });
auto check_existence = [&] (Accesspoint &lap) {
connecting_attempt |= (lap.ssid == ap.ssid) && ap.auto_connect;
};
_for_each_ap(check_existence);
}); });
}); });
if (!_connected_ap.bssid_valid() && connecting_attempt) {
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () {
xml.attribute("state", "connecting");
});
});
}
} catch (...) { /* silently omit report */ } } catch (...) { /* silently omit report */ }
} }
@ -670,7 +739,7 @@ struct Wifi::Frontend
auto mark_stale = [&] (Accesspoint &ap) { auto mark_stale = [&] (Accesspoint &ap) {
ap.stale = true; ap.stale = true;
config.for_each_sub_node("accesspoint", [&] ( Genode::Xml_node node) { config.for_each_sub_node("network", [&] ( Genode::Xml_node node) {
Accesspoint::Ssid ssid = node.attribute_value("ssid", Accesspoint::Ssid("")); Accesspoint::Ssid ssid = node.attribute_value("ssid", Accesspoint::Ssid(""));
if (ap.ssid == ssid) { ap.stale = false; } if (ap.ssid == ssid) { ap.stale = false; }
@ -735,8 +804,6 @@ struct Wifi::Frontend
Genode::log("Update network: '", _processed_ap->ssid, "'"); Genode::log("Update network: '", _processed_ap->ssid, "'");
} }
// _processed_ap->update = false;
/* re-use state to change PSK */ /* re-use state to change PSK */
_state_transition(_state, State::FILL_NETWORK_PSK); _state_transition(_state, State::FILL_NETWORK_PSK);
_network_set_psk(); _network_set_psk();
@ -873,12 +940,17 @@ struct Wifi::Frontend
/* result handling */ /* result handling */
bool _scan_busy { false };
void _handle_scan_results(State state, char const *msg) void _handle_scan_results(State state, char const *msg)
{ {
switch (state) { switch (state) {
case State::INITIATE_SCAN: case State::INITIATE_SCAN:
if (!cmd_successful(msg)) { if (!cmd_successful(msg)) {
Genode::warning("could not initiate scan: ", msg); _scan_busy = Genode::strcmp(msg, "FAIL-BUSY");
if (!_scan_busy) {
Genode::warning("could not initiate scan: ", msg);
}
} }
_state_transition(_state, State::IDLE); _state_transition(_state, State::IDLE);
break; break;
@ -1054,16 +1126,17 @@ struct Wifi::Frontend
* If some step failed we have to generate a fake * If some step failed we have to generate a fake
* disconnect event. * disconnect event.
*/ */
if (_fake_connecting && !successfully) { if (_single_autoconnect && !successfully) {
try { try {
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () { Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () { xml.node("accesspoint", [&] () {
xml.attribute("state", "disconnected"); xml.attribute("state", "disconnected");
xml.attribute("rfkilled", _rfkilled);
xml.attribute("config_error", true); xml.attribute("config_error", true);
}); });
}); });
_fake_connecting = false; _single_autoconnect = false;
} catch (...) { } } catch (...) { }
} }
} }
@ -1072,15 +1145,11 @@ struct Wifi::Frontend
{ {
_state_transition(_state, State::IDLE); _state_transition(_state, State::IDLE);
_state_transition(_state, State::LIST_NETWORKS); /*
_submit_cmd(Cmd_str("LIST_NETWORKS")); * Querying the status might have failed but we already sent
} * out a rudimentary report, just stop here.
*/
void _handle_info_result(State state, char const *msg) if (0 == msg[0]) { return; }
{
_state_transition(_state, State::IDLE);
if (!_connected_event && !_disconnected_event) { return; }
Accesspoint ap { }; Accesspoint ap { };
@ -1099,16 +1168,66 @@ struct Wifi::Frontend
}; };
for_each_line(msg, fill_ap); for_each_line(msg, fill_ap);
/* if (!ap.ssid.valid()) {
Genode::error("Cannot query SSID :-(");
return;
}
Accesspoint *p = _lookup_ap_by_ssid(ap.ssid);
if (p) {
p->bssid = ap.bssid;
p->freq = ap.freq;
}
_connected_ap.ssid = ap.ssid;
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () {
xml.attribute("ssid", ap.ssid);
xml.attribute("bssid", ap.bssid);
xml.attribute("freq", ap.freq);
xml.attribute("state", "connected");
});
});
}
void _handle_info_result(State state, char const *msg)
{
_state_transition(_state, State::IDLE);
if (!_connected_event && !_disconnected_event) { return; }
/*
* It might happen that the supplicant already flushed
* its internal BSS information and cannot help us out.
* Since we already sent out a rudimentary report, just
* stop here.
*/
if (0 == msg[0]) { return; }
Accesspoint ap { };
auto fill_ap = [&] (char const *line) {
if (Genode::strcmp(line, "ssid=", 5) == 0) {
ap.ssid = Accesspoint::Ssid(line+5);
} else
if (Genode::strcmp(line, "bssid=", 6) == 0) {
ap.bssid = Accesspoint::Bssid(line+6);
} else
if (Genode::strcmp(line, "freq=", 5) == 0) {
ap.freq = Accesspoint::Freq(line+5);
}
};
for_each_line(msg, fill_ap);
/*
* When the config is changed while we are still connecting and * When the config is changed while we are still connecting and
* for some reasons the accesspoint does not get disabled * for some reasons the accesspoint does not get disabled
* a connected event could arrive and we will get a nullptr... * a connected event could arrive and we will get a nullptr...
*/ */
Accesspoint *p = _lookup_ap_by_ssid(ap.ssid); Accesspoint *p = _lookup_ap_by_ssid(ap.ssid);
if (!p) {
Genode::warning("received connection event for unknown "
"network '", ap.ssid, "'");
}
/* /*
* ... but we still generate a report and let the management * ... but we still generate a report and let the management
@ -1129,8 +1248,13 @@ struct Wifi::Frontend
}); });
if (_disconnected_fail) { if (_disconnected_fail) {
/*
if (!p || _processed_ap || _state != State::IDLE) { * Being able to remove a failed network from the internal
* state of the supplicant relies on a sucessful BSS request.
* In case that failes the supplicant will try to join the
* network again and again...
*/
if (!p || _processed_ap) {
Genode::error("cannot disabled failed network"); Genode::error("cannot disabled failed network");
} else { } else {
_processed_ap = p; _processed_ap = p;
@ -1140,20 +1264,21 @@ struct Wifi::Frontend
} else } else
if (_connected_event) { if (_connected_event) {
/*
* In case the BSS cmd did not return a valid SSID, which
* was observed only with hidden networks so far, check the
* current status.
*/
if (!p) { if (!p) {
Genode::error("cannot lookup connected network"); _state_transition(_state, State::STATUS);
return; _submit_cmd(Cmd_str("STATUS"));
} else {
p->bssid = ap.bssid;
p->freq = ap.freq;
} }
p->bssid = ap.bssid;
p->freq = ap.freq;
_connected_ap = ap; _connected_ap = ap;
} else
/* just your normal disconnect event */
{
_connected_ap.invalidate();
} }
} }
@ -1200,60 +1325,71 @@ struct Wifi::Frontend
bool _disconnected_event { false }; bool _disconnected_event { false };
bool _disconnected_fail { false }; bool _disconnected_fail { false };
enum { MAX_ATTEMPTS = 3, };
unsigned _scan_attempts { 0 };
Accesspoint::Bssid _pending_bssid { }; Accesspoint::Bssid _pending_bssid { };
bool _handle_connection_events(char const *msg) void _handle_connection_events(char const *msg)
{ {
bool const connected = check_recv_msg(msg, recv_table[Rmi::CONNECTED]); bool const connected = check_recv_msg(msg, recv_table[Rmi::CONNECTED]);
bool const disconnected = check_recv_msg(msg, recv_table[Rmi::DISCONNECTED]); bool const disconnected = check_recv_msg(msg, recv_table[Rmi::DISCONNECTED]);
bool const auth_failed = disconnected && _auth_failure(msg);
State state = connected ? State::CONNECTED : State::DISCONNECTED; State state = connected ? State::CONNECTED : State::DISCONNECTED;
Accesspoint::Bssid const &bssid = _extract_bssid(msg, state); Accesspoint::Bssid const &bssid = _extract_bssid(msg, state);
/*
* Always reset the "global" connection state first
*/
_connected_ap.invalidate();
if (connected) { _connected_ap.bssid = bssid; }
if (connected || disconnected) { _connecting = Accesspoint::Bssid(); }
/*
* Save local connection state here for later re-use when
* the BSS information are handled.
*/
_connected_event = connected; _connected_event = connected;
_disconnected_event = disconnected; _disconnected_event = disconnected;
_disconnected_fail = disconnected && _auth_failure(msg); _disconnected_fail = auth_failed;
if (connected) { if (!_rfkilled) {
/*
* As we only received the BSSID, try to gather more information
* so we may generate a more thorough follow-up state report.
*/
if (_state != State::IDLE) { if (_state != State::IDLE) {
_pending_bssid = bssid; _pending_bssid = bssid;
} else { } else {
_state_transition(_state, State::INFO); _state_transition(_state, State::INFO);
_submit_cmd(Cmd_str("BSS ", bssid)); _submit_cmd(Cmd_str("BSS ", bssid));
} }
} else {
/* _arm_scan_timer(connected);
* In case of disconnected event use stored information if we
* already were connected.
*/
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () {
if (_connected_ap.valid()) {
xml.attribute("ssid", _connected_ap.ssid);
xml.attribute("bssid", _connected_ap.bssid);
xml.attribute("freq", _connected_ap.freq);
} else {
xml.attribute("bssid", bssid);
}
xml.attribute("state", "disconnected");
xml.attribute("rfkilled", _rfkilled);
xml.attribute("auth_failure", _disconnected_fail);
});
});
_connected_ap.invalidate();
/* arm scan timer implicitly */
_handle_scan_timer();
} }
/* reset */ /*
_fake_connecting = false; * Generate the first rudimentary report whose missing information
* are (potentially) filled in later (see above).
*/
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () {
xml.attribute("bssid", bssid);
xml.attribute("state", connected ? "connected"
: "disconnected");
if (disconnected) {
xml.attribute("rfkilled", _rfkilled);
if (auth_failed) {
xml.attribute("auth_failure", auth_failed);
}
}
});
});
return connected || disconnected; /* reset */
_single_autoconnect = false;
} }
Genode::Signal_handler<Wifi::Frontend> _events_handler; Genode::Signal_handler<Wifi::Frontend> _events_handler;
@ -1271,10 +1407,6 @@ struct Wifi::Frontend
return; return;
} }
if (_rfkilled) {
Genode::warning(__func__, ": rfkilled with ", state_strings(_state));
}
if (results_available(msg)) { if (results_available(msg)) {
/* /*
@ -1291,7 +1423,7 @@ struct Wifi::Frontend
} else } else
if (connecting_to_network(msg)) { if (connecting_to_network(msg)) {
if (!_fake_connecting) { if (!_single_autoconnect) {
Accesspoint::Bssid const &bssid = _extract_bssid(msg, State::CONNECTING); Accesspoint::Bssid const &bssid = _extract_bssid(msg, State::CONNECTING);
_connecting = bssid; _connecting = bssid;
@ -1304,6 +1436,29 @@ struct Wifi::Frontend
} }
} else } else
if (network_not_found(msg)) {
/* always try to update the accesspoint list */
if (_state == State::IDLE) {
_state_transition(_state, State::PENDING_RESULTS);
_submit_cmd(Cmd_str("SCAN_RESULTS"));
}
if (_single_autoconnect && ++_scan_attempts >= MAX_ATTEMPTS) {
_scan_attempts = 0;
_single_autoconnect = false;
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () {
xml.attribute("state", "disconnected");
xml.attribute("rfkilled", _rfkilled);
xml.attribute("not_found", true);
});
});
}
} else
{ {
_handle_connection_events(msg); _handle_connection_events(msg);
} }
@ -1326,10 +1481,6 @@ struct Wifi::Frontend
return; return;
} }
if (_rfkilled) {
Genode::warning(__func__, ": rfkilled with ", state_strings(_state));
}
_last_recv_id = recv_id; _last_recv_id = recv_id;
switch (_state & 0xf) { switch (_state & 0xf) {
@ -1353,7 +1504,7 @@ struct Wifi::Frontend
if (_verbose_state) { if (_verbose_state) {
Genode::log("State:", Genode::log("State:",
" connected: ", _connected_ap.valid(), " connected: ", _connected_ap.bssid_valid(),
" connecting: ", _connecting.length() > 1, " connecting: ", _connecting.length() > 1,
" enabled: ", _count_enabled(), " enabled: ", _count_enabled(),
" stored: ", _count_stored(), " stored: ", _count_stored(),
@ -1392,6 +1543,8 @@ struct Wifi::Frontend
try { try {
_ap_reporter.construct(env, "accesspoints"); _ap_reporter.construct(env, "accesspoints");
_ap_reporter->enabled(true); _ap_reporter->enabled(true);
Genode::Reporter::Xml_generator xml(*_ap_reporter, [&] () { });
} catch (...) { } catch (...) {
Genode::warning("no Report session available, scan results will " Genode::warning("no Report session available, scan results will "
"not be reported"); "not be reported");
@ -1400,13 +1553,20 @@ struct Wifi::Frontend
try { try {
_state_reporter.construct(env, "state"); _state_reporter.construct(env, "state");
_state_reporter->enabled(true); _state_reporter->enabled(true);
Genode::Reporter::Xml_generator xml(*_state_reporter, [&] () {
xml.node("accesspoint", [&] () {
xml.attribute("state", "disconnected");
xml.attribute("rfkilled", _rfkilled);
});
});
} catch (...) { } catch (...) {
Genode::warning("no Report session available, connectivity will " Genode::warning("no Report session available, connectivity will "
"not be reported"); "not be reported");
} }
/* read in list of APs */ /* read in list of APs */
_handle_config_update(); _config_update(false);
/* kick-off initial scanning */ /* kick-off initial scanning */
_handle_scan_timer(); _handle_scan_timer();

View File

@ -1418,7 +1418,6 @@ bool flush_work(struct work_struct *work)
*/ */
bool const queued = work_queued(work->wq, work); bool const queued = work_queued(work->wq, work);
if (queued) { if (queued) {
Genode::error(__func__, " work: ", work, " (", work->func, ") queued");
struct workqueue_struct *wq = work->wq; struct workqueue_struct *wq = work->wq;

View File

@ -63,6 +63,7 @@ struct ctrl_iface_global_priv {
}; };
extern void lx_printf(char const *, ...) __attribute__((format(printf, 1, 2)));
extern void nl_set_wpa_ctrl_fd(void); extern void nl_set_wpa_ctrl_fd(void);
@ -72,19 +73,19 @@ void wpa_ctrl_set_fd()
} }
static int send_reply(struct ctrl_iface_priv *priv, char const *txt, size_t len) static void send_reply(struct ctrl_iface_priv *priv, char const *txt, size_t len)
{ {
char *msg = priv->send_buffer; char *msg = priv->send_buffer;
size_t mlen = priv->send_buffer_size; size_t mlen = priv->send_buffer_size;
if (!msg || !len || (len > mlen)) { return -1; } if (len >= mlen) {
lx_printf("Warning: cmd reply will be truncated\n");
len = mlen - 1;
}
memset(msg, 0, mlen);
memcpy(msg, txt, len); memcpy(msg, txt, len);
msg[len] = 0;
(*priv->send_id)++; (*priv->send_id)++;
return 0;
} }
@ -112,7 +113,6 @@ static void wpa_supplicant_ctrl_iface_receive(int fd, void *eloop_ctx,
reply = wpa_supplicant_ctrl_iface_process(wpa_s, msg, reply = wpa_supplicant_ctrl_iface_process(wpa_s, msg,
&reply_len); &reply_len);
// lx_printf("%s:%d %p %zu\n", __func__, __LINE__, reply, reply_len);
if (reply) { if (reply) {
wifi_notify_cmd_result(); wifi_notify_cmd_result();
@ -121,10 +121,12 @@ static void wpa_supplicant_ctrl_iface_receive(int fd, void *eloop_ctx,
} else } else
if (reply_len == 1) { if (reply_len == 1) {
wifi_notify_cmd_result();
send_reply(priv, "FAIL", 4); send_reply(priv, "FAIL", 4);
} else } else
if (reply_len == 2) { if (reply_len == 2) {
wifi_notify_cmd_result();
send_reply(priv, "OK", 2); send_reply(priv, "OK", 2);
} }
} }
@ -139,19 +141,19 @@ static void print_txt(char const *txt, size_t len)
} }
static int send_event(struct ctrl_iface_priv *priv, char const *txt, size_t len) static void send_event(struct ctrl_iface_priv *priv, char const *txt, size_t len)
{ {
char *msg = priv->event_buffer; char *msg = priv->event_buffer;
size_t mlen = priv->event_buffer_size; size_t mlen = priv->event_buffer_size;
if (!msg || !len || (len > mlen)) { return -1; } if (len >= mlen) {
lx_printf("Warning: event will be truncated\n");
len = mlen - 1;
}
memset(msg, 0, mlen);
memcpy(msg, txt, len); memcpy(msg, txt, len);
msg[len] = 0;
(*priv->event_id)++; (*priv->event_id)++;
return 0;
} }
@ -191,6 +193,7 @@ static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
strncmp(txt, "CTRL-EVENT-SCAN-RESULTS", 23) == 0 strncmp(txt, "CTRL-EVENT-SCAN-RESULTS", 23) == 0
|| strncmp(txt, "CTRL-EVENT-CONNECTED", 20) == 0 || strncmp(txt, "CTRL-EVENT-CONNECTED", 20) == 0
|| strncmp(txt, "CTRL-EVENT-DISCONNECTED", 23) == 0 || strncmp(txt, "CTRL-EVENT-DISCONNECTED", 23) == 0
|| strncmp(txt, "CTRL-EVENT-NETWORK-NOT-FOUND", 28) == 0
/* needed to detect connecting state */ /* needed to detect connecting state */
|| strncmp(txt, "SME: Trying to authenticate", 27) == 0 || strncmp(txt, "SME: Trying to authenticate", 27) == 0
; ;

View File

@ -246,9 +246,9 @@ append_if $use_wifi_driver config {
<policy label_prefix="config_rom" root="/"/> <policy label_prefix="config_rom" root="/"/>
<content> <content>
<inline name="wifi_config"> <inline name="wifi_config">
<wifi_config connected_scan_interval="30" scan_interval="10" rfkill="no" verbose="no">} <wifi_config connected_scan_interval="0" scan_interval="10" rfkill="no" verbose="no" verbose_state="no">}
append_if $use_wifi_driver config " append_if $use_wifi_driver config "
<accesspoint enabled=\"true\" ssid=\"$wifi_ssid\" protection=\"WPA2\" passphrase=\"$wifi_psk\"/>" <network ssid=\"$wifi_ssid\" protection=\"WPA2\" passphrase=\"$wifi_psk\"/>"
append_if $use_wifi_driver config { append_if $use_wifi_driver config {
</wifi_config> </wifi_config>
</inline> </inline>