49a3a0e0d0
Introduce the uplink tag: ! <config> ! <uplink label="wifi" domain="uplink"> ! <uplink label="wired" domain="wired_bridge"> ! <uplink domain="wired_bridge"> ! <config/> For each uplink tag, the NIC router requests a NIC session with the corresponding label or an empty label if there is no label attribute. These NIC sessions get attached to the domain that is set in their uplink tag as soon as the domain appears. This means their lifetime is not bound to the domain. Uplink NIC sessions can be safely moved from one domain to another without being closed by reconfiguring the corresponding domain attribute. Attention: This may render previously valid NIC router configurations useless. A domain named "uplink" doesn't automatically request a NIC session anymore. To fix these configurations, just add ! <uplink domain="uplink"/> or ! <uplink label="[LABEL]" domain="uplink"/> as direct subtag of the <config> tag. Issue #2840
229 lines
6.1 KiB
C++
229 lines
6.1 KiB
C++
/*
|
|
* \brief Sculpt network management
|
|
* \author Norman Feske
|
|
* \date 2018-04-30
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2018 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* local includes */
|
|
#include <network.h>
|
|
|
|
|
|
void Sculpt::Network::_generate_nic_router_uplink(Xml_generator &xml,
|
|
char const *label)
|
|
{
|
|
xml.node("uplink", [&] () {
|
|
xml.attribute("label", label);
|
|
xml.attribute("domain", "uplink");
|
|
});
|
|
gen_named_node(xml, "domain", "uplink", [&] () {
|
|
xml.node("nat", [&] () {
|
|
xml.attribute("domain", "default");
|
|
xml.attribute("tcp-ports", "1000");
|
|
xml.attribute("udp-ports", "1000");
|
|
xml.attribute("icmp-ids", "1000");
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
void Sculpt::Network::handle_key_press(Codepoint code)
|
|
{
|
|
enum { BACKSPACE = 8, ENTER = 10 };
|
|
if (code.value == BACKSPACE)
|
|
wpa_passphrase.remove_last_character();
|
|
else if (code.value == ENTER)
|
|
wifi_connect(dialog.selected_ap());
|
|
else if (code.value != 0)
|
|
wpa_passphrase.append_character(code);
|
|
|
|
/*
|
|
* Keep updating the passphase when pressing keys after
|
|
* clicking the connect button once.
|
|
*/
|
|
if (_wifi_connection.state == Wifi_connection::CONNECTING)
|
|
wifi_connect(_wifi_connection.bssid);
|
|
|
|
_dialog_generator.generate_dialog();
|
|
}
|
|
|
|
|
|
void Sculpt::Network::_generate_nic_router_config()
|
|
{
|
|
if ((_nic_target.wired() && !_runtime_info.present_in_runtime("nic_drv"))
|
|
|| (_nic_target.wifi() && !_runtime_info.present_in_runtime("wifi_drv"))) {
|
|
|
|
/* defer NIC router reconfiguration until the needed uplink is present */
|
|
_nic_router_config_up_to_date = false;
|
|
return;
|
|
}
|
|
|
|
_nic_router_config_up_to_date = true;
|
|
|
|
if (_nic_router_config.try_generate_manually_managed())
|
|
return;
|
|
|
|
if (!_nic_target.nic_router_needed()) {
|
|
_nic_router_config.generate([&] (Xml_generator &xml) {
|
|
xml.attribute("verbose_domain_state", "yes"); });
|
|
return;
|
|
}
|
|
|
|
_nic_router_config.generate([&] (Xml_generator &xml) {
|
|
xml.attribute("verbose_domain_state", "yes");
|
|
|
|
xml.node("report", [&] () {
|
|
xml.attribute("interval_sec", "5");
|
|
xml.attribute("bytes", "yes");
|
|
xml.attribute("config", "yes");
|
|
xml.attribute("config_triggers", "yes");
|
|
});
|
|
|
|
xml.node("default-policy", [&] () {
|
|
xml.attribute("domain", "default"); });
|
|
|
|
bool uplink_exists = true;
|
|
switch (_nic_target.type()) {
|
|
case Nic_target::WIRED: _generate_nic_router_uplink(xml, "wired"); break;
|
|
case Nic_target::WIFI: _generate_nic_router_uplink(xml, "wifi"); break;
|
|
default: uplink_exists = false;
|
|
}
|
|
gen_named_node(xml, "domain", "default", [&] () {
|
|
xml.attribute("interface", "10.0.1.1/24");
|
|
|
|
xml.node("dhcp-server", [&] () {
|
|
xml.attribute("ip_first", "10.0.1.2");
|
|
xml.attribute("ip_last", "10.0.1.200");
|
|
if (_nic_target.type() != Nic_target::LOCAL) {
|
|
xml.attribute("dns_server_from", "uplink"); }
|
|
});
|
|
|
|
if (uplink_exists) {
|
|
xml.node("tcp", [&] () {
|
|
xml.attribute("dst", "0.0.0.0/0");
|
|
xml.node("permit-any", [&] () {
|
|
xml.attribute("domain", "uplink"); }); });
|
|
|
|
xml.node("udp", [&] () {
|
|
xml.attribute("dst", "0.0.0.0/0");
|
|
xml.node("permit-any", [&] () {
|
|
xml.attribute("domain", "uplink"); }); });
|
|
|
|
xml.node("icmp", [&] () {
|
|
xml.attribute("dst", "0.0.0.0/0");
|
|
xml.attribute("domain", "uplink"); });
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
void Sculpt::Network::_handle_wlan_accesspoints()
|
|
{
|
|
bool const initial_scan = !_wlan_accesspoints_rom.xml().has_sub_node("accesspoint");
|
|
|
|
_wlan_accesspoints_rom.update();
|
|
|
|
/* suppress updating the list while the access-point list is hovered */
|
|
if (!initial_scan && dialog.ap_list_hovered())
|
|
return;
|
|
|
|
Access_point_update_policy policy(_alloc);
|
|
_access_points.update_from_xml(policy, _wlan_accesspoints_rom.xml());
|
|
_dialog_generator.generate_dialog();
|
|
}
|
|
|
|
|
|
void Sculpt::Network::_handle_wlan_state()
|
|
{
|
|
_wlan_state_rom.update();
|
|
_wifi_connection = Wifi_connection::from_xml(_wlan_state_rom.xml());
|
|
_dialog_generator.generate_dialog();
|
|
}
|
|
|
|
|
|
void Sculpt::Network::_handle_nic_router_state()
|
|
{
|
|
_nic_router_state_rom.update();
|
|
|
|
Nic_state const old_nic_state = _nic_state;
|
|
_nic_state = Nic_state::from_xml(_nic_router_state_rom.xml());
|
|
|
|
if (_nic_state.ipv4 != old_nic_state.ipv4)
|
|
_dialog_generator.generate_dialog();
|
|
|
|
/* if the nic state becomes ready, consider spawning the update subsystem */
|
|
if (old_nic_state.ready() != _nic_state.ready())
|
|
_runtime_config_generator.generate_runtime_config();
|
|
}
|
|
|
|
|
|
void Sculpt::Network::_handle_nic_router_config(Xml_node config)
|
|
{
|
|
Nic_target::Type target = _nic_target.managed_type;
|
|
|
|
_nic_target.policy = config.has_type("empty")
|
|
? Nic_target::MANAGED : Nic_target::MANUAL;
|
|
|
|
if (_nic_target.manual()) {
|
|
|
|
/* obtain uplink information from configuration */
|
|
target = Nic_target::LOCAL;
|
|
|
|
if (!config.has_sub_node("domain"))
|
|
target = Nic_target::OFF;
|
|
|
|
struct Break : Exception { };
|
|
try {
|
|
config.for_each_sub_node("domain", [&] (Xml_node domain) {
|
|
|
|
/* skip domains that are not called "uplink" */
|
|
if (domain.attribute_value("name", String<16>()) != "uplink")
|
|
return;
|
|
|
|
config.for_each_sub_node("uplink", [&] (Xml_node uplink) {
|
|
|
|
/* skip uplinks not assigned to a domain called "uplink" */
|
|
if (uplink.attribute_value("domain", String<16>()) != "uplink")
|
|
return;
|
|
|
|
if (uplink.attribute_value("label", String<16>()) == "wired") {
|
|
target = Nic_target::WIRED;
|
|
throw Break();
|
|
}
|
|
if (uplink.attribute_value("label", String<16>()) == "wifi") {
|
|
target = Nic_target::WIFI;
|
|
throw Break();
|
|
}
|
|
});
|
|
});
|
|
} catch (Break) { }
|
|
_nic_target.manual_type = target;
|
|
}
|
|
|
|
nic_target(target);
|
|
_generate_nic_router_config();
|
|
_runtime_config_generator.generate_runtime_config();
|
|
_dialog_generator.generate_dialog();
|
|
}
|
|
|
|
|
|
void Sculpt::Network::gen_runtime_start_nodes(Xml_generator &xml) const
|
|
{
|
|
if (_use_nic_drv)
|
|
xml.node("start", [&] () { gen_nic_drv_start_content(xml); });
|
|
|
|
if (_use_wifi_drv)
|
|
xml.node("start", [&] () { gen_wifi_drv_start_content(xml); });
|
|
|
|
if (_nic_target.type() != Nic_target::OFF)
|
|
xml.node("start", [&] () {
|
|
gen_nic_router_start_content(xml); });
|
|
}
|