wifi: report wlan networks

The wifi_drv now provides two reports. The first one contains all
accesspoints that were found while scanning the supported frequencies.
The second one reports the state of the driver, i.e., if it is
conntected to an accesspoint or not. In addition to that, the driver
now gets its configuration via a ROM session.

More detailed information are available in 'repos/dde_linux/README'.

Issue #1415.
This commit is contained in:
Josef Söntgen 2014-12-10 10:08:51 +01:00 committed by Christian Helmuth
parent c578a455ba
commit 85031f1c1a
8 changed files with 421 additions and 6 deletions

View File

@ -131,3 +131,45 @@ Configuration snippet:
! <any-service> <parent/> <any-child /> </any-service>
! </route>
!</start
The wifi_drv creates two distinct reports to communicate its state and
information about the wireless infrastructure to other components. The
first one is a list of all available accesspoints. The following examplary
report shows its structure:
!<wlan_accesspoints>
! <accesspoint ssid="skynet" bssid="00:01:02:03:04:05" quality="40"/>
! <accesspoint ssid="foobar" bssid="01:02:03:04:05:06" quality="70" protection="WPA-PSK"/>
! <accesspoint ssid="foobar" bssid="01:02:03:04:05:07" quality="10" protection="WPA-PSK"/>
!</wlan_accesspoints>
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:
!<wlan_state>
! <accesspoint ssid="foobar" bssid="01:02:03:04:05:06" quality="70" protection="WPA-PSK" state="connected"/>
!</wlan_state>
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:
!<selected_accesspoint ssid="foobar" bssid="01:02:03:04:05:06" protection="WPA-PSK" psk="foobar123!"/>
To disconnect from an accesspoint, a empty report is sent:
!<selected_accesspoint/>
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.

View File

@ -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)

View File

@ -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]",

View File

@ -1 +1 @@
8251d08813903fffb40bab8041618909d06e690a
1752fc50fccc55b94e45ca8c730df74e7c349a7b

View File

@ -14,13 +14,19 @@
/* Genode includes */
#include <base/env.h>
#include <base/sleep.h>
#include <os/attached_rom_dataspace.h>
#include <os/server.h>
#include <util/xml_node.h>
/* 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<Wlan_configration> 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<char>(), size);
/**
* Since <selected_accesspoint/> 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());
}
};

View File

@ -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)>
{

View File

@ -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 <j@w1.fi>
*
@ -6,12 +21,20 @@
* See README for more details.
*/
#include "includes.h"
/* libc includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
/* 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(&params, 0, sizeof(params));
params.wpa_debug_level = MSG_INFO;
// params.wpa_debug_level = MSG_DEBUG;
global = wpa_supplicant_init(&params);
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;
}

View File

@ -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 <base/printf.h>
#include <os/attached_rom_dataspace.h>
#include <os/reporter.h>
#include <util/string.h>
/* 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_MAX_LEN> 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_MAX_LEN> 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_MAX_LEN> 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"); }
}