2014-11-22 15:13:43 +01:00
|
|
|
/*
|
|
|
|
* \brief Startup Wifi driver
|
|
|
|
* \author Josef Soentgen
|
|
|
|
* \date 2014-03-03
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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/env.h>
|
|
|
|
#include <base/sleep.h>
|
2014-12-10 10:08:51 +01:00
|
|
|
#include <os/attached_rom_dataspace.h>
|
2015-03-09 14:31:26 +01:00
|
|
|
#include <os/config.h>
|
2014-11-22 15:13:43 +01:00
|
|
|
#include <os/server.h>
|
2014-12-10 10:08:51 +01:00
|
|
|
#include <util/xml_node.h>
|
2015-10-29 13:53:22 +01:00
|
|
|
#include <util/string.h>
|
2014-11-22 15:13:43 +01:00
|
|
|
|
|
|
|
/* local includes */
|
|
|
|
#include "wpa.h"
|
|
|
|
|
2014-12-10 10:08:51 +01:00
|
|
|
typedef long long ssize_t;
|
2014-11-22 15:13:43 +01:00
|
|
|
|
|
|
|
extern void wifi_init(Server::Entrypoint &, Genode::Lock &);
|
2014-12-10 10:08:51 +01:00
|
|
|
extern "C" void wpa_conf_reload(void);
|
|
|
|
extern "C" ssize_t wpa_write_conf(char const *, Genode::size_t);
|
|
|
|
|
2015-03-09 14:31:26 +01:00
|
|
|
bool config_verbose = false;
|
2014-11-22 15:13:43 +01:00
|
|
|
|
|
|
|
static Genode::Lock &wpa_startup_lock()
|
|
|
|
{
|
|
|
|
static Genode::Lock _l(Genode::Lock::LOCKED);
|
|
|
|
return _l;
|
|
|
|
}
|
|
|
|
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-03-06 14:24:06 +01:00
|
|
|
namespace {
|
|
|
|
template <Genode::size_t CAPACITY>
|
|
|
|
class Buffer
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
char _data[CAPACITY] { 0 };
|
|
|
|
Genode::size_t _length { 0 };
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
void reset() { _data[0] = 0; _length = 0; }
|
|
|
|
char const *data() const { return _data; }
|
|
|
|
Genode::size_t length() const { return _length; }
|
|
|
|
|
|
|
|
void append(char const *format, ...)
|
|
|
|
{
|
|
|
|
va_list list;
|
|
|
|
va_start(list, format);
|
|
|
|
Genode::String_console sc(_data + _length, CAPACITY - _length);
|
|
|
|
sc.vprintf(format, list);
|
|
|
|
va_end(list);
|
|
|
|
|
|
|
|
_length += sc.len();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} /* anonymous namespace */
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate wpa_supplicant.conf file
|
|
|
|
*/
|
|
|
|
static int generate_wpa_supplicant_conf(char const **p, Genode::size_t *len, char const *ssid,
|
|
|
|
char const *bssid, bool protection = false, char const *psk = 0)
|
2014-12-10 10:08:51 +01:00
|
|
|
{
|
2015-10-29 13:53:22 +01:00
|
|
|
static char const *start_fmt = "network={\n\tscan_ssid=1\n";
|
2015-03-06 14:24:06 +01:00
|
|
|
static char const *ssid_fmt = "\tssid=\"%s\"\n";
|
|
|
|
static char const *bssid_fmt = "\tbssid=%s\n";
|
|
|
|
static char const *prot_fmt = "\tkey_mgmt=%s\n";
|
|
|
|
static char const *psk_fmt = "\tpsk=\"%s\"\n";
|
|
|
|
static char const *end_fmt = "}\n";
|
|
|
|
|
|
|
|
static Buffer<256> buffer;
|
|
|
|
buffer.reset();
|
|
|
|
|
|
|
|
buffer.append(start_fmt);
|
|
|
|
|
|
|
|
if (ssid)
|
|
|
|
buffer.append(ssid_fmt, ssid);
|
|
|
|
|
|
|
|
if (bssid)
|
|
|
|
buffer.append(bssid_fmt, bssid);
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-03-06 14:24:06 +01:00
|
|
|
if (protection)
|
|
|
|
buffer.append(psk_fmt, psk);
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-03-06 14:24:06 +01:00
|
|
|
buffer.append(prot_fmt, protection ? "WPA-PSK" : "NONE");
|
|
|
|
|
|
|
|
buffer.append(end_fmt);
|
|
|
|
|
|
|
|
*p = buffer.data();
|
|
|
|
*len = buffer.length();
|
2014-12-10 10:08:51 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct Wlan_configration
|
|
|
|
{
|
2015-03-06 14:24:06 +01:00
|
|
|
Genode::Attached_rom_dataspace config_rom { "wlan_configuration" };
|
2014-12-10 10:08:51 +01:00
|
|
|
Genode::Signal_rpc_member<Wlan_configration> dispatcher;
|
2015-03-06 14:24:06 +01:00
|
|
|
Genode::Lock update_lock;
|
|
|
|
|
|
|
|
char const *buffer;
|
|
|
|
Genode::size_t size;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write configuration buffer to conf file to activate the new configuration.
|
|
|
|
*/
|
|
|
|
void _activate_configuration()
|
|
|
|
{
|
|
|
|
if (wpa_write_conf(buffer, size) == 0) {
|
|
|
|
PINF("reload wpa_supplicant configuration");
|
|
|
|
wpa_conf_reload();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Write dummy configuration buffer to conf file to activate the new
|
|
|
|
* configuration.
|
|
|
|
*/
|
|
|
|
void _active_dummy_configuration()
|
|
|
|
{
|
|
|
|
generate_wpa_supplicant_conf(&buffer, &size, "dummyssid", "00:00:00:00:00:00");
|
|
|
|
_activate_configuration();
|
|
|
|
}
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-03-06 14:24:06 +01:00
|
|
|
/**
|
|
|
|
* Update the conf file used by the wpa_supplicant.
|
|
|
|
*/
|
|
|
|
void _update_configuration()
|
2014-12-10 10:08:51 +01:00
|
|
|
{
|
2015-10-29 13:53:22 +01:00
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
Lock::Guard guard(update_lock);
|
2015-03-06 14:24:06 +01:00
|
|
|
|
2014-12-10 10:08:51 +01:00
|
|
|
config_rom.update();
|
|
|
|
|
2015-03-06 14:24:06 +01:00
|
|
|
/**
|
|
|
|
* We generate a dummy configuration because there is no valid
|
|
|
|
* configuration yet to fool wpa_supplicant to keep it scanning
|
|
|
|
* for the non exisiting network.
|
|
|
|
*/
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!config_rom.valid()) {
|
2015-03-06 14:24:06 +01:00
|
|
|
_active_dummy_configuration();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-10-29 13:53:22 +01:00
|
|
|
Xml_node node(config_rom.local_addr<char>(), config_rom.size());
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-03-06 14:24:06 +01:00
|
|
|
/**
|
2015-10-29 13:53:22 +01:00
|
|
|
* Since <selected_accesspoint/> is empty or missing an ssid attribute
|
|
|
|
* we also generate a dummy configuration.
|
2015-03-06 14:24:06 +01:00
|
|
|
*/
|
2015-10-29 13:53:22 +01:00
|
|
|
if (!node.has_attribute("ssid")) {
|
2015-03-06 14:24:06 +01:00
|
|
|
_active_dummy_configuration();
|
|
|
|
return;
|
|
|
|
}
|
2014-12-10 10:08:51 +01:00
|
|
|
|
|
|
|
/**
|
2015-03-06 14:24:06 +01:00
|
|
|
* Try to generate a valid configuration.
|
2014-12-10 10:08:51 +01:00
|
|
|
*/
|
2015-10-29 13:53:22 +01:00
|
|
|
enum { MAX_SSID_LENGTH = 32 + 1,
|
|
|
|
BSSID_LENGTH = 12 + 5 + 1,
|
|
|
|
PROT_LENGTH = 7 + 1,
|
|
|
|
MIN_PSK_LENGTH = 8,
|
|
|
|
MAX_PSK_LENGTH = 63 + 1};
|
2015-03-06 14:24:06 +01:00
|
|
|
|
2015-10-29 13:53:22 +01:00
|
|
|
String<MAX_SSID_LENGTH> ssid;
|
|
|
|
node.attribute("ssid").value(&ssid);
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-10-29 13:53:22 +01:00
|
|
|
bool use_bssid = node.has_attribute("bssid");
|
|
|
|
String<BSSID_LENGTH> bssid;
|
2015-03-06 14:24:06 +01:00
|
|
|
if (use_bssid)
|
2015-10-29 13:53:22 +01:00
|
|
|
node.attribute("bssid").value(&bssid);
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-10-29 13:53:22 +01:00
|
|
|
bool use_protection = false;
|
|
|
|
if (node.has_attribute("protection")) {
|
|
|
|
String<PROT_LENGTH> prot;
|
|
|
|
node.attribute("protection").value(&prot);
|
|
|
|
use_protection = (prot == "WPA-PSK");
|
|
|
|
}
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-10-29 13:53:22 +01:00
|
|
|
String<MAX_PSK_LENGTH> psk;
|
2015-03-06 14:24:06 +01:00
|
|
|
if (use_protection && node.has_attribute("psk"))
|
2015-10-29 13:53:22 +01:00
|
|
|
node.attribute("psk").value(&psk);
|
2014-12-10 10:08:51 +01:00
|
|
|
|
2015-03-06 14:24:06 +01:00
|
|
|
/* psk must be between 8 and 63 characters long */
|
2015-10-29 13:53:22 +01:00
|
|
|
if (use_protection && (psk.length() < MIN_PSK_LENGTH)) {
|
|
|
|
PERR("error: given psk is too short");
|
2015-03-06 14:24:06 +01:00
|
|
|
_active_dummy_configuration();
|
|
|
|
return;
|
2014-12-10 10:08:51 +01:00
|
|
|
}
|
2015-03-06 14:24:06 +01:00
|
|
|
|
2015-10-29 13:53:22 +01:00
|
|
|
if (generate_wpa_supplicant_conf(&buffer, &size, ssid.string(),
|
|
|
|
use_bssid ? bssid.string() : 0,
|
|
|
|
use_protection, psk.string()) == 0)
|
2015-03-06 14:24:06 +01:00
|
|
|
_activate_configuration();
|
2014-12-10 10:08:51 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:24:06 +01:00
|
|
|
void _handle_update(unsigned) { _update_configuration(); }
|
2014-12-10 10:08:51 +01:00
|
|
|
|
|
|
|
Wlan_configration(Server::Entrypoint &ep)
|
|
|
|
:
|
|
|
|
dispatcher(ep, *this, &Wlan_configration::_handle_update)
|
|
|
|
{
|
|
|
|
config_rom.sigh(dispatcher);
|
2015-03-06 14:24:06 +01:00
|
|
|
_update_configuration();
|
2014-12-10 10:08:51 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-11-22 15:13:43 +01:00
|
|
|
struct Main
|
|
|
|
{
|
|
|
|
Server::Entrypoint &_ep;
|
|
|
|
Wpa_thread *_wpa;
|
|
|
|
|
2014-12-10 10:08:51 +01:00
|
|
|
Wlan_configration *_wc;
|
|
|
|
|
2014-11-22 15:13:43 +01:00
|
|
|
Main(Server::Entrypoint &ep)
|
|
|
|
:
|
|
|
|
_ep(ep)
|
|
|
|
{
|
2016-02-29 15:26:19 +01:00
|
|
|
Genode::Xml_node config = Genode::config()->xml_node();
|
2016-06-09 15:55:13 +02:00
|
|
|
config_verbose = config.attribute_value("verbose", config_verbose);
|
2016-02-29 15:26:19 +01:00
|
|
|
|
|
|
|
_wpa = new (Genode::env()->heap()) Wpa_thread(wpa_startup_lock(), config_verbose);
|
2014-11-22 15:13:43 +01:00
|
|
|
|
|
|
|
_wpa->start();
|
|
|
|
|
2014-12-10 10:08:51 +01:00
|
|
|
try {
|
|
|
|
_wc = new (Genode::env()->heap()) Wlan_configration(_ep);
|
|
|
|
} catch (...) { PWRN("could not create wlan_configration handler"); }
|
|
|
|
|
2014-11-22 15:13:43 +01:00
|
|
|
wifi_init(ep, wpa_startup_lock());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
namespace Server {
|
|
|
|
char const *name() { return "wifi_drv_ep"; }
|
|
|
|
size_t stack_size() { return 32 * 1024 * sizeof(long); }
|
|
|
|
void construct(Entrypoint &ep) { static Main server(ep); }
|
|
|
|
}
|