diff --git a/repos/dde_linux/README b/repos/dde_linux/README
index a0c648ea3..7f3f66b2a 100644
--- a/repos/dde_linux/README
+++ b/repos/dde_linux/README
@@ -131,3 +131,45 @@ Configuration snippet:
!
!
!
+!
+!
+!
+!
+
+Each accesspoint node has attributes that contain the SSID and the BSSID
+of the accesspoint as well as the link quality (signal strength). These
+attributes are mandatory. If the network is protected, the node will also
+have an attribute describing the type of protection in addition.
+
+The second report provides information about the state of the connection
+to the currently connected accesspoint:
+
+!
+!
+!
+
+Valid state values are 'connected', 'disconnected', 'connecting' and
+'disconnecting'.
+
+In return, the wifi_drv get its configuration via a ROM module. This ROM
+module contains the selected accesspoint. To connect to a accesspoint
+a report like the following is used:
+
+!
+
+To disconnect from an accesspoint, a empty report is sent:
+
+!
+
+By subscribing to both reports and providing the required ROM module, a
+component can control the wireless driver. An example therefore is the Qt
+based component in 'src/app/qt_wifi_connect'.
+
+Currently only WPA/WPA2 protection using a pre-shared key is supported.
diff --git a/repos/dde_linux/lib/mk/wpa_supplicant.mk b/repos/dde_linux/lib/mk/wpa_supplicant.mk
index 7baf4d361..aaa32fea1 100644
--- a/repos/dde_linux/lib/mk/wpa_supplicant.mk
+++ b/repos/dde_linux/lib/mk/wpa_supplicant.mk
@@ -10,7 +10,8 @@ CC_OPT += -Wno-unused-function
CC_CXX_OPT += -fpermissive
-SRC_C += main.c
+SRC_C += main.c
+SRC_CC += reporter.cc
# wpa_supplicant
SRC_C_wpa_supplicant = blacklist.c \
@@ -103,4 +104,5 @@ INC_DIR += $(WS_CONTRIB_DIR)/src/utils
CC_OPT += -DCONFIG_ELOOP_POLL
vpath %.c $(WS_CONTRIB_DIR)
-vpath %.c $(WS_DIR)
+vpath %.c $(WS_DIR)
+vpath %.cc $(WS_DIR)
diff --git a/repos/dde_linux/patches/wpa_supplicant.patch b/repos/dde_linux/patches/wpa_supplicant.patch
index 5ac9822c3..443e222b4 100644
--- a/repos/dde_linux/patches/wpa_supplicant.patch
+++ b/repos/dde_linux/patches/wpa_supplicant.patch
@@ -81,3 +81,116 @@
#endif /* CONFIG_ELOOP_POLL */
#ifdef CONFIG_ELOOP_EPOLL
+@@ -801,7 +801,7 @@
+ #endif /* CONFIG_NATIVE_WINDOWS */
+
+
+-static void eloop_handle_signal(int sig)
++void eloop_handle_signal(int sig)
+ {
+ int i;
+
+--- a/wpa_supplicant/events.c
++++ b/wpa_supplicant/events.c
+@@ -1245,6 +1245,9 @@
+ }
+
+
++extern void wpa_report_scan_results(struct wpa_supplicant *);
++
++
+ /* Return != 0 if no scan results could be fetched or if scan results should not
+ * be shared with other virtual interfaces. */
+ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+@@ -1281,6 +1284,8 @@
+ goto scan_work_done;
+ }
+
++ wpa_report_scan_results(wpa_s);
++
+ #ifndef CONFIG_NO_RANDOM_POOL
+ num = scan_res->num;
+ if (num > 10)
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -267,6 +267,20 @@
+
+ #define WPAS_MAX_SCAN_SSIDS 16
+
++struct wpa_driver_scan_ssid {
++ /**
++ * ssid - specific SSID to scan for (ProbeReq)
++ * %NULL or zero-length SSID is used to indicate active scan
++ * with wildcard SSID.
++ */
++ const u8 *ssid;
++ /**
++ * ssid_len: Length of the SSID in octets
++ */
++ size_t ssid_len;
++};
++
++
+ /**
+ * struct wpa_driver_scan_params - Scan parameters
+ * Data for struct wpa_driver_ops::scan2().
+@@ -275,18 +289,7 @@
+ /**
+ * ssids - SSIDs to scan for
+ */
+- struct wpa_driver_scan_ssid {
+- /**
+- * ssid - specific SSID to scan for (ProbeReq)
+- * %NULL or zero-length SSID is used to indicate active scan
+- * with wildcard SSID.
+- */
+- const u8 *ssid;
+- /**
+- * ssid_len: Length of the SSID in octets
+- */
+- size_t ssid_len;
+- } ssids[WPAS_MAX_SCAN_SSIDS];
++ struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
+
+ /**
+ * num_ssids - Number of entries in ssids array
+--- a/wpa_supplicant/events.c
++++ b/wpa_supplicant/events.c
+@@ -2067,6 +2067,9 @@ static int disconnect_reason_recoverable(u16 reason_code)
+ }
+
+
++void wpa_report_disconnect_event(struct wpa_supplicant *);
++
++
+ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
+ u16 reason_code,
+ int locally_generated)
+@@ -2088,6 +2091,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
+
+ if (!is_zero_ether_addr(bssid) ||
+ wpa_s->wpa_state >= WPA_AUTHENTICATING) {
++ wpa_report_disconnect_event(wpa_s);
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+ " reason=%d%s",
+ MAC2STR(bssid), reason_code,
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -656,6 +656,9 @@ void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
+ }
+
+
++void wpa_report_connect_event(struct wpa_ssid *);
++
++
+ /**
+ * wpa_supplicant_set_state - Set current connection state
+ * @wpa_s: Pointer to wpa_supplicant data
+@@ -689,6 +692,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
+
+ if (state == WPA_COMPLETED && wpa_s->new_connection) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
++ wpa_report_connect_event(ssid);
+ #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
+ MACSTR " completed [id=%d id_str=%s]",
diff --git a/repos/dde_linux/ports/dde_linux.hash b/repos/dde_linux/ports/dde_linux.hash
index 4d4bfbb04..2488f3617 100644
--- a/repos/dde_linux/ports/dde_linux.hash
+++ b/repos/dde_linux/ports/dde_linux.hash
@@ -1 +1 @@
-8251d08813903fffb40bab8041618909d06e690a
+1752fc50fccc55b94e45ca8c730df74e7c349a7b
diff --git a/repos/dde_linux/src/drivers/wifi/main.cc b/repos/dde_linux/src/drivers/wifi/main.cc
index fa7828c57..c1d10ff2e 100644
--- a/repos/dde_linux/src/drivers/wifi/main.cc
+++ b/repos/dde_linux/src/drivers/wifi/main.cc
@@ -14,13 +14,19 @@
/* Genode includes */
#include
#include
+#include
#include
+#include
/* local includes */
#include "wpa.h"
+typedef long long ssize_t;
extern void wifi_init(Server::Entrypoint &, Genode::Lock &);
+extern "C" void wpa_conf_reload(void);
+extern "C" ssize_t wpa_write_conf(char const *, Genode::size_t);
+
static Genode::Lock &wpa_startup_lock()
{
@@ -28,11 +34,92 @@ static Genode::Lock &wpa_startup_lock()
return _l;
}
+
+static int update_conf(char **p, Genode::size_t *len, char const *ssid,
+ bool encryption = false, char const *psk = 0)
+{
+ char const *ssid_fmt = "network={\n\tssid=\"%s\"\n\tkey_mgmt=%s\n";
+ char const *psk_fmt = "psk=\"%s\"\n";
+ char const *end_fmt = "}\n";
+
+ static char buf[4096];
+ Genode::size_t n = Genode::snprintf(buf, sizeof(buf), ssid_fmt, ssid,
+ encryption ? "WPA-PSK" : "NONE");
+ if (encryption) {
+ n += Genode::snprintf(buf + n, sizeof(buf) - n, psk_fmt, psk);
+ }
+
+ n += Genode::snprintf(buf + n, sizeof(buf) - n, end_fmt);
+
+ *p = buf;
+ *len = n;
+
+ return 0;
+}
+
+
+struct Wlan_configration
+{
+ Genode::Attached_rom_dataspace config_rom { "wlan_configuration" };
+ Genode::Signal_rpc_member dispatcher;
+
+ void _update_conf()
+ {
+ config_rom.update();
+ Genode::size_t size = config_rom.size();
+
+ char *file_buffer;
+ Genode::size_t buffer_length;
+
+ Genode::Xml_node node(config_rom.local_addr(), size);
+
+ /**
+ * Since is empty we generate a dummy
+ * configuration to fool wpa_supplicant to keep it scanning for
+ * the non exisiting network.
+ */
+ if (!node.has_attribute("ssid")) {
+ update_conf(&file_buffer, &buffer_length, "dummyssid");
+ } else {
+ char ssid[32+1] = { 0 };
+ node.attribute("ssid").value(ssid, sizeof(ssid));
+
+ bool use_protection = node.has_attribute("protection");
+
+ char psk[63+1] = { 0 };
+ if (use_protection && node.has_attribute("psk"))
+ node.attribute("psk").value(psk, sizeof(psk));
+
+ if (update_conf(&file_buffer, &buffer_length, ssid,
+ use_protection, psk) != 0)
+ return;
+ }
+
+ if (wpa_write_conf(file_buffer, buffer_length) == 0) {
+ PINF("reload wpa_supplicant configuration");
+ wpa_conf_reload();
+ }
+ }
+
+ void _handle_update(unsigned) { _update_conf(); }
+
+ Wlan_configration(Server::Entrypoint &ep)
+ :
+ dispatcher(ep, *this, &Wlan_configration::_handle_update)
+ {
+ config_rom.sigh(dispatcher);
+ _update_conf();
+ }
+};
+
+
struct Main
{
Server::Entrypoint &_ep;
Wpa_thread *_wpa;
+ Wlan_configration *_wc;
+
Main(Server::Entrypoint &ep)
:
_ep(ep)
@@ -41,6 +128,10 @@ struct Main
_wpa->start();
+ try {
+ _wc = new (Genode::env()->heap()) Wlan_configration(_ep);
+ } catch (...) { PWRN("could not create wlan_configration handler"); }
+
wifi_init(ep, wpa_startup_lock());
}
};
diff --git a/repos/dde_linux/src/drivers/wifi/wpa.h b/repos/dde_linux/src/drivers/wifi/wpa.h
index 063737fc7..c8ac211ea 100644
--- a/repos/dde_linux/src/drivers/wifi/wpa.h
+++ b/repos/dde_linux/src/drivers/wifi/wpa.h
@@ -19,6 +19,7 @@
/* entry function */
extern "C" int wpa_main(void);
+extern "C" void wpa_conf_reload(void);
class Wpa_thread : public Genode::Thread<8 * 1024 * sizeof(long)>
{
diff --git a/repos/dde_linux/src/lib/wpa_supplicant/main.c b/repos/dde_linux/src/lib/wpa_supplicant/main.c
index 60c50e6ee..c776a5935 100644
--- a/repos/dde_linux/src/lib/wpa_supplicant/main.c
+++ b/repos/dde_linux/src/lib/wpa_supplicant/main.c
@@ -1,4 +1,19 @@
/*
+ * \brief WPA Supplicant frontend
+ * \author Josef Soentgen
+ * \date 2014-12-08
+ */
+
+/*
+ * Copyright (C) 2014 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/*
+ * based on:
+ *
* WPA Supplicant / Example program entrypoint
* Copyright (c) 2003-2005, Jouni Malinen
*
@@ -6,12 +21,20 @@
* See README for more details.
*/
-#include "includes.h"
+/* libc includes */
+#include
+#include
+#include
+#include
+/* local includes */
+#include "includes.h"
#include "common.h"
#include "wpa_supplicant_i.h"
-int wpa_main()
+static char const *conf_file = "/config/wpa_supplicant.conf";
+
+int wpa_main(void)
{
struct wpa_interface iface;
int exitcode = 0;
@@ -21,6 +44,7 @@ int wpa_main()
memset(¶ms, 0, sizeof(params));
params.wpa_debug_level = MSG_INFO;
+ // params.wpa_debug_level = MSG_DEBUG;
global = wpa_supplicant_init(¶ms);
if (global == NULL)
@@ -29,7 +53,7 @@ int wpa_main()
memset(&iface, 0, sizeof(iface));
iface.ifname = "wlan0";
- iface.confname = "/wpa_supplicant.conf";
+ iface.confname = conf_file;
if (wpa_supplicant_add_iface(global, &iface) == NULL)
exitcode = -1;
@@ -41,3 +65,24 @@ int wpa_main()
return exitcode;
}
+
+
+void eloop_handle_signal(int);
+void wpa_conf_reload(void)
+{
+ /* (ab)use POSIX signal to trigger reloading the conf file */
+ eloop_handle_signal(SIGHUP);
+}
+
+
+int wpa_write_conf(char const *buffer, size_t len)
+{
+ int fd = open(conf_file, O_TRUNC|O_WRONLY);
+ if (fd == -1)
+ return -1;
+
+ ssize_t n = write(fd, buffer, len);
+ close(fd);
+
+ return n > 0 ? 0 : -1;
+}
diff --git a/repos/dde_linux/src/lib/wpa_supplicant/reporter.cc b/repos/dde_linux/src/lib/wpa_supplicant/reporter.cc
new file mode 100644
index 000000000..44af972c2
--- /dev/null
+++ b/repos/dde_linux/src/lib/wpa_supplicant/reporter.cc
@@ -0,0 +1,121 @@
+/*
+ * \brief WPA Supplicant frontend
+ * \author Josef Soentgen
+ * \date 2014-12-08
+ */
+
+/*
+ * Copyright (C) 2014 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+/* WPA Supplicant includes */
+extern "C" {
+#include "includes.h"
+#include "common.h"
+#include "drivers/driver.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "common/ieee802_11_defs.h"
+}
+
+
+static Genode::Reporter accesspoints_reporter = { "wlan_accesspoints" };
+static Genode::Reporter state_reporter = { "wlan_state" };
+
+
+enum { SSID_MAX_LEN = 32 + 1, MAC_STR_LEN = 6*2 + 5 + 1};
+
+
+static inline void mac2str(char *buf, u8 const *mac)
+{
+ Genode::snprintf(buf, MAC_STR_LEN, "%02x:%02x:%02x:%02x:%02x:%02x",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+
+extern "C" void wpa_report_connect_event(struct wpa_ssid *wpa_ssid)
+{
+ state_reporter.enabled(true);
+
+ try {
+ Genode::Reporter::Xml_generator xml(state_reporter, [&]() {
+ /* FIXME ssid may contain any characters, even NUL */
+ Genode::String ssid((char const*)wpa_ssid->ssid, wpa_ssid->ssid_len);
+
+ char bssid_buf[MAC_STR_LEN];
+ mac2str(bssid_buf, wpa_ssid->bssid);
+
+ xml.node("accesspoint", [&]() {
+ xml.attribute("ssid", ssid.string());
+ xml.attribute("bssid", bssid_buf);
+ xml.attribute("state", "connected");
+ });
+ });
+ } catch (...) { PWRN("could not report connected state"); }
+}
+
+
+extern "C" void wpa_report_disconnect_event(struct wpa_supplicant *wpa_s)
+{
+ state_reporter.enabled(true);
+
+ try {
+ Genode::Reporter::Xml_generator xml(state_reporter, [&]() {
+ struct wpa_ssid *wpa_ssid = wpa_s->current_ssid;
+
+ /* FIXME ssid may contain any characters, even NUL */
+ Genode::String ssid((char const*)wpa_ssid->ssid, wpa_ssid->ssid_len);
+
+ char bssid_buf[MAC_STR_LEN];
+ mac2str(bssid_buf, wpa_ssid->bssid);
+
+ xml.node("accesspoint", [&]() {
+ xml.attribute("ssid", ssid.string());
+ xml.attribute("bssid", bssid_buf);
+ xml.attribute("state", "disconnected");
+ });
+
+ });
+ } catch (...) { PWRN("could not report disconnected state"); }
+}
+
+
+extern "C" void wpa_report_scan_results(struct wpa_supplicant *wpa_s)
+{
+ accesspoints_reporter.enabled(true);
+
+ try {
+ Genode::Reporter::Xml_generator xml(accesspoints_reporter, [&]() {
+ for (unsigned i = 0; i < wpa_s->last_scan_res_used; i++) {
+ struct wpa_bss *bss = wpa_s->last_scan_res[i];
+
+ bool wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) != NULL;
+ bool wpa2 = wpa_bss_get_ie(bss, WLAN_EID_RSN) != NULL;
+
+ char bssid_buf[MAC_STR_LEN];
+ mac2str(bssid_buf, bss->bssid);
+
+ Genode::String ssid((char const*)bss->ssid, bss->ssid_len);
+
+ xml.node("accesspoint", [&]() {
+ xml.attribute("ssid", ssid.string());
+ xml.attribute("bssid", bssid_buf);
+
+ /* XXX we forcefully only support WPA/WPA2 psk for now */
+ if (wpa || wpa2)
+ xml.attribute("protection", "WPA-PSK");
+ });
+ }
+ });
+ } catch (...) { PWRN("could not report scan results"); }
+}