nic_router: DHCP client functionality

If the attribute 'interface' is not set in a 'domain' tag, the router tries to
dynamically receive and maintain an IP configuration for that domain by using
DHCP in the client role at all interfaces that connect to the domain. In the
DHCP discover phase, the router simply chooses the first DHCP offer that
arrives. So, no comparison of different DHCP offers is done. In the DHCP
request phase, the server is expected to provide an IP address, a gateway, a
subnet mask, and an IP lease time to the router. If anything substantial goes
wrong during a DHCP exchange, the router discards the outcome of the exchange
and goes back to the DHCP discover phase. At any time where there is no valid
IP configuration present at a domain, the domain does only act as DHCP client
and all other router functionality is disabled for the domain. A domain cannot
act as DHCP client and DHCP server at once. So, a 'domain' tag must either
have an 'interface' attribute or must not contain a 'dhcp-server' tag.

Ref #2534
This commit is contained in:
Martin Stein 2017-10-16 11:31:43 +02:00 committed by Christian Helmuth
parent 3560555acc
commit db9d4d3a3c
13 changed files with 562 additions and 73 deletions

View File

@ -11,7 +11,7 @@ The 'nic_router' component can be used to individually route IPv4 packets
between multiple NIC sessions. Thereby, it can translate between different
subnets. The component supports IP routing, TCP and UDP routing, the
partitioning of the TCP and UDP port spaces, port forwarding, NAT, and can
also act as DHCP server.
also act as DHCP server and as DHCP client.
Basics
@ -41,7 +41,8 @@ named "uplink". For each domain there must be a domain tag:
The 'interface' attribute defines two things at once. First, it tells the
router which subnet can be found behind this domain, and second, which IP
identity the router shall use in case it has to communicate as itself with
the subnet.
the subnet. If the 'interface' attribute is not set in a 'domain' tag, the
router acts as DHCP client (Section [Configuring DHCP client functionality]).
Additionaly, the optional 'gateway' attribute can be set for a domain:
@ -50,7 +51,9 @@ Additionaly, the optional 'gateway' attribute can be set for a domain:
It defines the standard gateway of the subnet behind this domain. If a packet
shall be routed to this domain and its final IP destination does not match
the subnet, its Ethernet destination is set to the MAC address of the gateway.
If a gateway isn't given for a domain, such packets get dropped.
If a gateway isn't given for a domain, such packets get dropped. If a gateway
is given for a domain without an 'interface' attribute, this gateway
configuration is not getting effective.
For each domain, the routing of packets from this domain can be configured
individually by adding subtags to the corresponding domain tag. There are
@ -299,14 +302,32 @@ the router while ip_lease_time_sec is applied only when the offer is
acknowledged by the client in time.
Configuring DHCP client functionality
#####################################
If the attribute 'interface' is not set in a 'domain' tag, the router tries to
dynamically receive and maintain an IP configuration for that domain by using
DHCP in the client role at all interfaces that connect to the domain. In the
DHCP discover phase, the router simply chooses the first DHCP offer that
arrives. So, no comparison of different DHCP offers is done. In the DHCP
request phase, the server is expected to provide an IP address, a gateway, a
subnet mask, and an IP lease time to the router. If anything substantial goes
wrong during a DHCP exchange, the router discards the outcome of the exchange
and goes back to the DHCP discover phase. At any time where there is no valid
IP configuration present at a domain, the domain does only act as DHCP client
and all other router functionality is disabled for the domain. A domain cannot
act as DHCP client and DHCP server at once. So, a 'domain' tag must either
have an 'interface' attribute or must not contain a 'dhcp-server' tag.
Examples
########
This section will list and explain some interesting configuration snippets. A
comprehensive example of how to use the router (except DHCP server
functionality) can be found in the test script 'libports/run/nic_router.run'.
For an example of how to use the DHCP server functionality see the
'ports/run/virtualbox_nic_router.run' script.
For an example of how to use the DHCP server and the DHCP client functionality
see the 'ports/run/virtualbox_nic_router.run' script.
The environment for the examples shall be as
follows. There are two virtual subnets 192.168.1.0/24 and 192.168.2.0/24 that

View File

@ -74,6 +74,7 @@ Net::Session_component::Session_component(Allocator &alloc,
_tx.sigh_packet_avail(_sink_submit);
_rx.sigh_ack_avail(_source_ack);
_rx.sigh_ready_to_submit(_source_submit);
Interface::_init();
}

View File

@ -0,0 +1,259 @@
/*
* \brief DHCP client state model
* \author Martin Stein
* \date 2016-08-24
*/
/*
* Copyright (C) 2016-2017 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 <dhcp_client.h>
#include <interface.h>
#include <domain.h>
#include <configuration.h>
#include <size_guard.h>
using namespace Genode;
using namespace Net;
using Message_type = Dhcp_packet::Message_type;
using Packet_ignored = Interface::Packet_ignored;
Configuration &Dhcp_client::_config() { return _domain().config(); };
Domain &Dhcp_client::_domain() { return _interface.domain(); }
Dhcp_client::Dhcp_client(Genode::Allocator &alloc,
Timer::Connection &timer,
Interface &interface)
:
_alloc(alloc), _interface(interface),
_timeout(timer, *this, &Dhcp_client::_handle_timeout)
{ }
void Dhcp_client::discover()
{
_set_state(State::SELECT, _config().rtt());
_send(Message_type::DISCOVER, Ipv4_address(), Ipv4_address());
}
void Dhcp_client::_rerequest(State next_state)
{
_set_state(next_state, _rerequest_timeout(2));
_send(Message_type::REQUEST, _domain().ip_config().interface.address,
Ipv4_address());
}
void Dhcp_client::_set_state(State state, Microseconds timeout)
{
_state = state;
_timeout.schedule(timeout);
}
Microseconds Dhcp_client::_rerequest_timeout(unsigned lease_time_div_log2)
{
/* FIXME limit the time because of shortcomings in timeout framework */
enum { MAX_TIMEOUT_SEC = 3600 };
unsigned long timeout_sec = _lease_time_sec >> lease_time_div_log2;
if (timeout_sec > MAX_TIMEOUT_SEC) {
timeout_sec = MAX_TIMEOUT_SEC;
warning("Had to prune the state timeout of DHCP client");
}
return Microseconds(timeout_sec * 1000UL * 1000UL);
}
void Dhcp_client::_handle_timeout(Duration)
{
switch (_state) {
case State::BOUND: _rerequest(State::RENEW); break;
case State::RENEW: _rerequest(State::REBIND); break;
case State::REBIND: _domain().discard_ip_config();
default: discover();
}
}
void Dhcp_client::handle_ip(Ethernet_frame &eth, size_t eth_size)
{
if (eth.dst() != _interface.router_mac()) {
throw Packet_ignored("DHCP client expects Ethernet targeting the router");
}
Ipv4_packet &ip = *new (eth.data<void>())
Ipv4_packet(eth_size - sizeof(Ethernet_frame));
if (ip.protocol() != Ipv4_packet::Protocol::UDP) {
throw Packet_ignored("DHCP client expects UDP packet");
}
Udp_packet &udp = *new (ip.data<void>())
Udp_packet(eth_size - sizeof(Ipv4_packet));
if (!Dhcp_packet::is_dhcp(&udp)) {
throw Packet_ignored("DHCP client expects DHCP packet");
}
Dhcp_packet &dhcp = *new (udp.data<void>())
Dhcp_packet(eth_size - sizeof(Ipv4_packet) - sizeof(Udp_packet));
if (dhcp.op() != Dhcp_packet::REPLY) {
throw Packet_ignored("DHCP client expects DHCP reply");
}
try { _handle_dhcp_reply(dhcp); }
catch (Dhcp_packet::Option_not_found) {
throw Packet_ignored("DHCP client misses DHCP option");
}
}
void Dhcp_client::_handle_dhcp_reply(Dhcp_packet &dhcp)
{
Message_type const msg_type =
dhcp.option<Dhcp_packet::Message_type_option>().value();
switch (_state) {
case State::SELECT:
if (msg_type != Message_type::OFFER) {
throw Packet_ignored("DHCP client expects an offer");
}
_set_state(State::REQUEST, _config().rtt());
_send(Message_type::REQUEST, dhcp.yiaddr(),
dhcp.option<Dhcp_packet::Server_ipv4>().value());
break;
case State::REQUEST:
if (msg_type != Message_type::ACK) {
throw Packet_ignored("DHCP client expects an acknowledgement");
}
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
_set_state(State::BOUND, _rerequest_timeout(1));
_domain().ip_config(dhcp.yiaddr(),
dhcp.option<Dhcp_packet::Subnet_mask>().value(),
dhcp.option<Dhcp_packet::Router_ipv4>().value());
break;
case State::RENEW:
case State::REBIND:
if (msg_type != Message_type::ACK) {
throw Packet_ignored("DHCP client expects an acknowledgement");
}
_set_state(State::BOUND, _rerequest_timeout(1));
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
break;
default: throw Packet_ignored("DHCP client doesn't expect a packet");
}
}
void Dhcp_client::_send(Message_type msg_type,
Ipv4_address client_ip,
Ipv4_address server_ip)
{
/* allocate buffer for the request */
enum { BUF_SIZE = 1024 };
using Size_guard = Size_guard_tpl<BUF_SIZE, Interface::Dhcp_msg_buffer_too_small>;
void *buf;
try { _alloc.alloc(BUF_SIZE, &buf); }
catch (...) { throw Interface::Alloc_dhcp_msg_buffer_failed(); }
Mac_address client_mac = _interface.router_mac();
/* create ETH header of the request */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(buf);
eth.dst(Mac_address(0xff));
eth.src(client_mac);
eth.type(Ethernet_frame::Type::IPV4);
/* create IP header of the request */
enum { IPV4_TIME_TO_LIVE = 64 };
size_t const ip_off = size.curr();
size.add(sizeof(Ipv4_packet));
Ipv4_packet &ip = *eth.data<Ipv4_packet>();
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.diff_service(0);
ip.identification(0);
ip.flags(0);
ip.fragment_offset(0);
ip.time_to_live(IPV4_TIME_TO_LIVE);
ip.protocol(Ipv4_packet::Protocol::UDP);
ip.src(client_ip);
ip.dst(Ipv4_address(0xff));
/* create UDP header of the request */
size_t const udp_off = size.curr();
size.add(sizeof(Udp_packet));
Udp_packet &udp = *ip.data<Udp_packet>();
udp.src_port(Port(Dhcp_packet::BOOTPC));
udp.dst_port(Port(Dhcp_packet::BOOTPS));
/* create mandatory DHCP fields of the request */
size_t const dhcp_off = size.curr();
size.add(sizeof(Dhcp_packet));
Dhcp_packet &dhcp = *udp.data<Dhcp_packet>();
dhcp.op(Dhcp_packet::REQUEST);
dhcp.htype(Dhcp_packet::Htype::ETH);
dhcp.hlen(sizeof(Mac_address));
dhcp.hops(0);
dhcp.xid(0x12345678);
dhcp.secs(0);
dhcp.flags(0);
dhcp.ciaddr(client_ip);
dhcp.yiaddr(Ipv4_address());
dhcp.siaddr(Ipv4_address());
dhcp.giaddr(Ipv4_address());
dhcp.client_mac(client_mac);
dhcp.zero_fill_sname();
dhcp.zero_fill_file();
dhcp.default_magic_cookie();
/* append DHCP option fields to the request */
Dhcp_packet::Options_aggregator<Size_guard>
dhcp_opts(dhcp, size);
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
switch (msg_type) {
case Message_type::DISCOVER:
dhcp_opts.append_option<Dhcp_packet::Client_id>(client_mac);
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(BUF_SIZE - dhcp_off);
break;
case Message_type::REQUEST:
dhcp_opts.append_option<Dhcp_packet::Client_id>(client_mac);
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(BUF_SIZE - dhcp_off);
if (_state == State::REQUEST) {
dhcp_opts.append_option<Dhcp_packet::Requested_addr>(client_ip);
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(server_ip);
}
break;
default:
throw Interface::Bad_send_dhcp_args();
}
dhcp_opts.append_option<Dhcp_packet::Options_end>();
/* fill in header values that need the packet to be complete already */
udp.length(size.curr() - udp_off);
udp.update_checksum(ip.src(), ip.dst());
ip.total_length(size.curr() - ip_off);
ip.checksum(Ipv4_packet::calculate_checksum(ip));
/* send request to sender of request and free request buffer */
_interface.send(eth, size.curr());
_alloc.free(buf, BUF_SIZE);
}

View File

@ -0,0 +1,74 @@
/*
* \brief DHCP client state model
* \author Martin Stein
* \date 2016-08-24
*/
/*
* Copyright (C) 2016-2017 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.
*/
#ifndef _DHCP_CLIENT_H_
#define _DHCP_CLIENT_H_
/* Genode includes */
#include <timer_session/connection.h>
#include <net/dhcp.h>
namespace Net {
class Domain;
class Configuration;
class Interface;
class Ethernet_frame;
class Dhcp_client;
}
class Net::Dhcp_client
{
private:
enum class State
{
INIT = 0, SELECT = 1, REQUEST = 2, BOUND = 3, RENEW = 4, REBIND = 5
};
Genode::Allocator &_alloc;
Interface &_interface;
State _state { State::INIT };
Timer::One_shot_timeout<Dhcp_client> _timeout;
unsigned long _lease_time_sec;
void _handle_dhcp_reply(Dhcp_packet &dhcp);
void _handle_timeout(Genode::Duration);
void _rerequest(State next_state);
Genode::Microseconds _rerequest_timeout(unsigned lease_time_div_log2);
void _set_state(State state, Genode::Microseconds timeout);
void _send(Dhcp_packet::Message_type msg_type,
Ipv4_address client_ip,
Ipv4_address server_ip);
Configuration &_config();
Domain &_domain();
public:
Dhcp_client(Genode::Allocator &alloc,
Timer::Connection &timer,
Interface &interface);
void handle_ip(Ethernet_frame &eth, Genode::size_t eth_size);
void discover();
};
#endif /* _DHCP_CLIENT_H_ */

View File

@ -116,6 +116,22 @@ Domain_base::Domain_base(Xml_node const node)
** Domain **
************/
void Domain::ip_config(Ipv4_address ip,
Ipv4_address subnet_mask,
Ipv4_address gateway)
{
_ip_config.construct(Ipv4_address_prefix(ip, subnet_mask), gateway);
_ip_config_changed();
}
void Domain::discard_ip_config()
{
_ip_config.construct();
_ip_config_changed();
}
void Domain::_read_forward_rules(Cstring const &protocol,
Domain_tree &domains,
Xml_node const node,
@ -163,17 +179,36 @@ Domain::Domain(Configuration &config, Xml_node const node, Allocator &alloc)
_ip_config(_node.attribute_value("interface", Ipv4_address_prefix()),
_node.attribute_value("gateway", Ipv4_address()))
{
if (_name == Domain_name() || !_ip_config.interface_valid) {
if (_name == Domain_name()) {
error("Missing name attribute in domain node");
throw Invalid();
}
if (!ip_config().valid && _node.has_sub_node("dhcp-server")) {
error("Domain cannot act as DHCP client and server at once");
throw Invalid();
}
_ip_config_changed();
}
void Domain::_ip_config_changed()
{
if (!ip_config().valid) {
return;
}
if (_config.verbose()) {
log("New IP config at domain \"", *this, "\":"
" interface ", ip_config().interface,
" gateway ", ip_config().gateway);
}
/* try to find configuration for DHCP server role */
try {
_dhcp_server.set(*new (alloc)
Dhcp_server(node.sub_node("dhcp-server"), alloc,
_ip_config.interface));
_dhcp_server.set(*new (_alloc)
Dhcp_server(_node.sub_node("dhcp-server"), _alloc,
ip_config().interface));
if (_config.verbose()) {
log(" DHCP server: ", _dhcp_server.deref()); }
log("DHCP server at domain \"", *this, "\": ", _dhcp_server.deref()); }
}
catch (Xml_node::Nonexistent_sub_node) { }
catch (Dhcp_server::Invalid) {
@ -219,8 +254,8 @@ void Domain::create_rules(Domain_tree &domains)
Ipv4_address const &Domain::next_hop(Ipv4_address const &ip) const
{
if (_ip_config.interface.prefix_matches(ip)) { return ip; }
if (_ip_config.gateway_valid) { return _ip_config.gateway; }
if (ip_config().interface.prefix_matches(ip)) { return ip; }
if (ip_config().gateway_valid) { return ip_config().gateway; }
throw No_next_hop();
}

View File

@ -29,6 +29,7 @@
#include <util/xml_node.h>
#include <util/noncopyable.h>
#include <os/duration.h>
#include <util/reconstructible.h>
namespace Genode { class Allocator; }
@ -125,21 +126,21 @@ class Net::Domain : public Domain_base
{
private:
Domain_avl_member _avl_member;
Configuration &_config;
Genode::Xml_node _node;
Genode::Allocator &_alloc;
Ip_rule_list _ip_rules;
Forward_rule_tree _tcp_forward_rules;
Forward_rule_tree _udp_forward_rules;
Transport_rule_list _tcp_rules;
Transport_rule_list _udp_rules;
Port_allocator _tcp_port_alloc;
Port_allocator _udp_port_alloc;
Nat_rule_tree _nat_rules;
Pointer<Interface> _interface;
Pointer<Dhcp_server> _dhcp_server;
Ipv4_config _ip_config;
Domain_avl_member _avl_member;
Configuration &_config;
Genode::Xml_node _node;
Genode::Allocator &_alloc;
Ip_rule_list _ip_rules;
Forward_rule_tree _tcp_forward_rules;
Forward_rule_tree _udp_forward_rules;
Transport_rule_list _tcp_rules;
Transport_rule_list _udp_rules;
Port_allocator _tcp_port_alloc;
Port_allocator _udp_port_alloc;
Nat_rule_tree _nat_rules;
Pointer<Interface> _interface;
Pointer<Dhcp_server> _dhcp_server;
Genode::Reconstructible<Ipv4_config> _ip_config;
void _read_forward_rules(Genode::Cstring const &protocol,
Domain_tree &domains,
@ -153,6 +154,8 @@ class Net::Domain : public Domain_base
char const *type,
Transport_rule_list &rules);
void _ip_config_changed();
public:
struct Invalid : Genode::Exception { };
@ -168,6 +171,12 @@ class Net::Domain : public Domain_base
Ipv4_address const &next_hop(Ipv4_address const &ip) const;
void ip_config(Ipv4_address ip,
Ipv4_address subnet_mask,
Ipv4_address gateway);
void discard_ip_config();
/*********
** log **
@ -180,7 +189,7 @@ class Net::Domain : public Domain_base
** Accessors **
***************/
Ipv4_config const &ip_config() const { return _ip_config; }
Ipv4_config const &ip_config() const { return *_ip_config; }
Domain_name const &name() { return _name; }
Ip_rule_list &ip_rules() { return _ip_rules; }
Forward_rule_tree &tcp_forward_rules() { return _tcp_forward_rules; }

View File

@ -20,32 +20,11 @@
#include <interface.h>
#include <configuration.h>
#include <l3_protocol.h>
#include <size_guard.h>
using namespace Net;
using namespace Genode;
/**
* Utility to ensure that a size value doesn't exceed a limit
*/
template <size_t MAX, typename EXCEPTION>
class Size_guard
{
private:
size_t _curr { 0 };
public:
void add(size_t size)
{
size_t const new_size = _curr + size;
if (new_size > MAX) { throw EXCEPTION(); }
_curr = new_size;
}
size_t curr() const { return _curr; }
};
/***************
** Utilities **
@ -186,7 +165,7 @@ void Interface::_pass_ip(Ethernet_frame &eth,
Ipv4_packet &ip)
{
ip.checksum(Ipv4_packet::calculate_checksum(ip));
_send(eth, eth_size);
send(eth, eth_size);
}
@ -339,12 +318,13 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
{
/* allocate buffer for the reply */
enum { BUF_SIZE = 512 };
using Size_guard = Size_guard_tpl<BUF_SIZE, Dhcp_msg_buffer_too_small>;
void *buf;
try { _alloc.alloc(BUF_SIZE, &buf); }
catch (...) { throw Alloc_dhcp_reply_buffer_failed(); }
catch (...) { throw Alloc_dhcp_msg_buffer_failed(); }
/* create ETH header of the reply */
Size_guard<BUF_SIZE, Dhcp_reply_buffer_too_small> reply_size;
Size_guard reply_size;
reply_size.add(sizeof(Ethernet_frame));
Ethernet_frame &reply_eth = *reinterpret_cast<Ethernet_frame *>(buf);
reply_eth.dst(client_mac);
@ -394,7 +374,7 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
reply_dhcp.default_magic_cookie();
/* append DHCP option fields to the reply */
Dhcp_packet::Options_aggregator<Size_guard<BUF_SIZE, Dhcp_reply_buffer_too_small> >
Dhcp_packet::Options_aggregator<Size_guard>
reply_dhcp_opts(reply_dhcp, reply_size);
reply_dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
reply_dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(_router_ip());
@ -413,7 +393,7 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
reply_ip.checksum(Ipv4_packet::calculate_checksum(reply_ip));
/* send reply to sender of request and free reply buffer */
_send(reply_eth, reply_size.curr());
send(reply_eth, reply_size.curr());
_alloc.free(buf, BUF_SIZE);
}
@ -584,6 +564,9 @@ void Interface::_handle_ip(Ethernet_frame &eth,
return;
}
catch (Pointer<Dhcp_server>::Invalid) { }
} else {
_dhcp_client.handle_ip(eth, eth_size);
return;
}
}
}
@ -690,7 +673,7 @@ void Interface::_broadcast_arp_request(Ipv4_address const &ip)
arp.src_ip(_router_ip());
arp.dst_mac(Mac_address(0xff));
arp.dst_ip(ip);
_send(eth_arp, sizeof(eth_arp));
send(eth_arp, sizeof(eth_arp));
}
@ -758,7 +741,7 @@ void Interface::_handle_arp_request(Ethernet_frame &eth,
/* mark packet as reply and send it back to its sender */
arp.opcode(Arp_packet::REPLY);
_send(eth, eth_size);
send(eth, eth_size);
}
@ -838,10 +821,19 @@ void Interface::_handle_eth(void *const eth_base,
if (_config().verbose()) {
log("\033[33m(router <- ", _domain, ")\033[0m ", *eth); }
switch (eth->type()) {
case Ethernet_frame::Type::ARP: _handle_arp(*eth, eth_size); break;
case Ethernet_frame::Type::IPV4: _handle_ip(*eth, eth_size, pkt); break;
default: throw Bad_network_protocol(); }
if (_domain.ip_config().valid) {
switch (eth->type()) {
case Ethernet_frame::Type::ARP: _handle_arp(*eth, eth_size); break;
case Ethernet_frame::Type::IPV4: _handle_ip(*eth, eth_size, pkt); break;
default: throw Bad_network_protocol(); }
} else {
switch (eth->type()) {
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(*eth, eth_size); break;
default: throw Bad_network_protocol(); }
}
}
catch (Ethernet_frame::No_ethernet_frame) {
error("invalid ethernet frame"); }
@ -866,10 +858,10 @@ void Interface::_handle_eth(void *const eth_base,
catch (Bad_dhcp_request) {
error("bad DHCP request"); }
catch (Alloc_dhcp_reply_buffer_failed) {
catch (Alloc_dhcp_msg_buffer_failed) {
error("failed to allocate buffer for DHCP reply"); }
catch (Dhcp_reply_buffer_too_small) {
catch (Dhcp_msg_buffer_too_small) {
error("DHCP reply buffer too small"); }
catch (Dhcp_server::Alloc_ip_failed) {
@ -877,7 +869,7 @@ void Interface::_handle_eth(void *const eth_base,
}
void Interface::_send(Ethernet_frame &eth, Genode::size_t const size)
void Interface::send(Ethernet_frame &eth, Genode::size_t const size)
{
if (_config().verbose()) {
log("\033[33m(", _domain, " <- router)\033[0m ", eth); }
@ -919,6 +911,14 @@ Interface::Interface(Entrypoint &ep,
}
void Interface::_init()
{
if (!_domain.ip_config().valid) {
_dhcp_client.discover();
}
}
void Interface::_ack_packet(Packet_descriptor const &pkt)
{
if (!_sink().ready_to_ack()) {

View File

@ -19,6 +19,7 @@
#include <arp_cache.h>
#include <arp_waiter.h>
#include <l3_protocol.h>
#include <dhcp_client.h>
/* Genode includes */
#include <nic_session/nic_session.h>
@ -120,6 +121,8 @@ class Net::Interface
Mac_address const _router_mac;
Mac_address const _mac;
void _init();
private:
Timer::Connection &_timer;
@ -134,6 +137,7 @@ class Net::Interface
Link_list _closed_udp_links;
Ip_allocation_tree _ip_allocations;
Ip_allocation_list _released_ip_allocations;
Dhcp_client _dhcp_client { _alloc, _timer, *this };
void _new_link(L3_protocol const protocol,
Link_side_id const &local_id,
@ -190,8 +194,6 @@ class Net::Interface
void _broadcast_arp_request(Ipv4_address const &ip);
void _send(Ethernet_frame &eth, Genode::size_t const eth_size);
void _pass_prot(Ethernet_frame &eth,
Genode::size_t const eth_size,
Ipv4_packet &ip,
@ -239,12 +241,20 @@ class Net::Interface
public:
struct Bad_transport_protocol : Genode::Exception { };
struct Bad_network_protocol : Genode::Exception { };
struct Packet_postponed : Genode::Exception { };
struct Bad_dhcp_request : Genode::Exception { };
struct Alloc_dhcp_reply_buffer_failed : Genode::Exception { };
struct Dhcp_reply_buffer_too_small : Genode::Exception { };
struct Bad_send_dhcp_args : Genode::Exception { };
struct Bad_transport_protocol : Genode::Exception { };
struct Bad_network_protocol : Genode::Exception { };
struct Packet_postponed : Genode::Exception { };
struct Bad_dhcp_request : Genode::Exception { };
struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { };
struct Dhcp_msg_buffer_too_small : Genode::Exception { };
struct Packet_ignored : Genode::Exception
{
char const *reason;
Packet_ignored(char const *reason) : reason(reason) { }
};
Interface(Genode::Entrypoint &ep,
Timer::Connection &timer,
@ -261,6 +271,8 @@ class Net::Interface
void dissolve_link(Link_side &link_side, L3_protocol const prot);
void send(Ethernet_frame &eth, Genode::size_t const eth_size);
/*********
** log **
@ -273,6 +285,8 @@ class Net::Interface
** Accessors **
***************/
Domain &domain() { return _domain; }
Mac_address router_mac() const { return _router_mac; }
Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; }
Arp_waiter_list &foreign_arp_waiters() { return _foreign_arp_waiters; }
};

View File

@ -77,3 +77,27 @@ Ipv4_address Ipv4_address_prefix::broadcast_address() const
}
return result;
}
Ipv4_address_prefix::Ipv4_address_prefix(Ipv4_address address,
Ipv4_address subnet_mask)
:
address(address)
{
Genode::uint8_t rest;
if (subnet_mask.addr[0] != 0xff) {
rest = subnet_mask.addr[0];
prefix = 0;
} else if (subnet_mask.addr[1] != 0xff) {
rest = subnet_mask.addr[1];
prefix = 8;
} else if (subnet_mask.addr[2] != 0xff) {
rest = subnet_mask.addr[2];
prefix = 16;
} else {
rest = subnet_mask.addr[3];
prefix = 24;
}
for (Genode::uint8_t mask = 1 << 7; rest & mask; mask >>= 1)
prefix++;
}

View File

@ -23,7 +23,12 @@ namespace Net { class Ipv4_address_prefix; }
struct Net::Ipv4_address_prefix
{
Ipv4_address address;
Genode::uint8_t prefix { 32 };
Genode::uint8_t prefix;
Ipv4_address_prefix(Ipv4_address address,
Ipv4_address subnet_mask);
Ipv4_address_prefix() : prefix(32) { }
bool valid() const { return address.valid() || prefix == 0; }

View File

@ -0,0 +1,45 @@
/*
* \brief Utility to ensure that a size value doesn't exceed a limit
* \author Martin Stein
* \date 2016-08-24
*/
/*
* Copyright (C) 2016-2017 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.
*/
#ifndef _SIZE_GUARD_H_
#define _SIZE_GUARD_H_
/* Genode includes */
#include <base/stdint.h>
namespace Genode {
template <size_t MAX, typename EXCEPTION>
class Size_guard_tpl;
}
template <Genode::size_t MAX, typename EXCEPTION>
class Genode::Size_guard_tpl
{
private:
size_t _curr { 0 };
public:
void add(size_t size)
{
size_t const new_size = _curr + size;
if (new_size > MAX) { throw EXCEPTION(); }
_curr = new_size;
}
size_t curr() const { return _curr; }
};
#endif /* _SIZE_GUARD_H_ */

View File

@ -8,5 +8,6 @@ SRC_CC += nat_rule.cc mac_allocator.cc main.cc ipv4_config.cc
SRC_CC += uplink.cc interface.cc arp_cache.cc configuration.cc
SRC_CC += domain.cc l3_protocol.cc direct_rule.cc link.cc
SRC_CC += transport_rule.cc leaf_rule.cc permit_rule.cc
SRC_CC += dhcp_client.cc
INC_DIR += $(PRG_DIR)

View File

@ -37,4 +37,5 @@ Net::Uplink::Uplink(Env &env,
rx_channel()->sigh_packet_avail(_sink_submit);
tx_channel()->sigh_ack_avail(_source_ack);
tx_channel()->sigh_ready_to_submit(_source_submit);
Interface::_init();
}