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
2017-10-16 09:31:43 +00:00
|
|
|
/*
|
|
|
|
* \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>
|
|
|
|
|
2018-04-06 15:34:01 +00:00
|
|
|
enum { PKT_SIZE = 1024 };
|
|
|
|
|
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
2017-10-16 09:31:43 +00:00
|
|
|
using namespace Genode;
|
|
|
|
using namespace Net;
|
2017-12-05 13:43:02 +00:00
|
|
|
using Message_type = Dhcp_packet::Message_type;
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 14:42:15 +00:00
|
|
|
using Drop_packet_inform = Net::Interface::Drop_packet_inform;
|
2018-04-06 15:34:01 +00:00
|
|
|
using Dhcp_options = Dhcp_packet::Options_aggregator<Size_guard>;
|
|
|
|
|
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
2017-10-16 09:31:43 +00:00
|
|
|
|
2018-04-06 15:34:01 +00:00
|
|
|
/***************
|
|
|
|
** Utilities **
|
|
|
|
***************/
|
|
|
|
|
|
|
|
void append_param_req_list(Dhcp_options &dhcp_opts)
|
|
|
|
{
|
|
|
|
dhcp_opts.append_param_req_list([&] (Dhcp_options::Parameter_request_list_data &data) {
|
|
|
|
data.append_param_req<Dhcp_packet::Message_type_option>();
|
|
|
|
data.append_param_req<Dhcp_packet::Server_ipv4>();
|
|
|
|
data.append_param_req<Dhcp_packet::Ip_lease_time>();
|
|
|
|
data.append_param_req<Dhcp_packet::Dns_server_ipv4>();
|
|
|
|
data.append_param_req<Dhcp_packet::Subnet_mask>();
|
|
|
|
data.append_param_req<Dhcp_packet::Router_ipv4>();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*****************
|
|
|
|
** Dhcp_client **
|
|
|
|
*****************/
|
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
2017-10-16 09:31:43 +00:00
|
|
|
|
|
|
|
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()
|
|
|
|
{
|
2017-11-28 14:03:28 +00:00
|
|
|
_set_state(State::SELECT, _config().dhcp_discover_timeout());
|
2018-04-04 15:25:52 +00:00
|
|
|
_send(Message_type::DISCOVER, Ipv4_address(), Ipv4_address(),
|
|
|
|
Ipv4_address());
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Dhcp_client::_rerequest(State next_state)
|
|
|
|
{
|
|
|
|
_set_state(next_state, _rerequest_timeout(2));
|
2018-04-04 15:25:52 +00:00
|
|
|
Ipv4_address const client_ip = _domain().ip_config().interface.address;
|
|
|
|
_send(Message_type::REQUEST, client_ip, Ipv4_address(), client_ip);
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-26 12:53:29 +00:00
|
|
|
void Dhcp_client::handle_ip(Ethernet_frame ð,
|
|
|
|
Size_guard &size_guard)
|
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
2017-10-16 09:31:43 +00:00
|
|
|
{
|
2017-11-03 13:06:46 +00:00
|
|
|
if (eth.dst() != _interface.router_mac() &&
|
|
|
|
eth.dst() != Mac_address(0xff))
|
2018-04-26 12:53:29 +00:00
|
|
|
{ throw Drop_packet_inform("DHCP client expects Ethernet targeting the router"); }
|
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
2017-10-16 09:31:43 +00:00
|
|
|
|
2018-04-26 12:53:29 +00:00
|
|
|
Ipv4_packet &ip = eth.data<Ipv4_packet>(size_guard);
|
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
2017-10-16 09:31:43 +00:00
|
|
|
if (ip.protocol() != Ipv4_packet::Protocol::UDP) {
|
2018-04-26 12:53:29 +00:00
|
|
|
throw Drop_packet_inform("DHCP client expects UDP packet"); }
|
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
2017-10-16 09:31:43 +00:00
|
|
|
|
2018-04-26 12:53:29 +00:00
|
|
|
Udp_packet &udp = ip.data<Udp_packet>(size_guard);
|
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
2017-10-16 09:31:43 +00:00
|
|
|
if (!Dhcp_packet::is_dhcp(&udp)) {
|
2018-04-26 12:53:29 +00:00
|
|
|
throw Drop_packet_inform("DHCP client expects DHCP packet"); }
|
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
2017-10-16 09:31:43 +00:00
|
|
|
|
2018-04-26 12:53:29 +00:00
|
|
|
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size_guard);
|
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
2017-10-16 09:31:43 +00:00
|
|
|
if (dhcp.op() != Dhcp_packet::REPLY) {
|
2018-04-26 12:53:29 +00:00
|
|
|
throw Drop_packet_inform("DHCP client expects DHCP reply"); }
|
|
|
|
|
2017-11-03 13:06:46 +00:00
|
|
|
if (dhcp.client_mac() != _interface.router_mac()) {
|
2018-04-26 12:53:29 +00:00
|
|
|
throw Drop_packet_inform("DHCP client expects DHCP targeting the router"); }
|
|
|
|
|
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
2017-10-16 09:31:43 +00:00
|
|
|
try { _handle_dhcp_reply(dhcp); }
|
|
|
|
catch (Dhcp_packet::Option_not_found) {
|
2018-04-26 12:53:29 +00:00
|
|
|
throw Drop_packet_inform("DHCP client misses DHCP option"); }
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
2017-12-05 13:43:02 +00:00
|
|
|
throw Drop_packet_inform("DHCP client expects an offer");
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|
2017-11-28 14:03:28 +00:00
|
|
|
_set_state(State::REQUEST, _config().dhcp_request_timeout());
|
2018-04-04 15:25:52 +00:00
|
|
|
_send(Message_type::REQUEST, Ipv4_address(),
|
|
|
|
dhcp.option<Dhcp_packet::Server_ipv4>().value(),
|
|
|
|
dhcp.yiaddr());
|
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
2017-10-16 09:31:43 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case State::REQUEST:
|
2018-03-22 23:30:04 +00:00
|
|
|
{
|
|
|
|
if (msg_type != Message_type::ACK) {
|
|
|
|
throw Drop_packet_inform("DHCP client expects an acknowledgement");
|
|
|
|
}
|
|
|
|
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
|
|
|
|
_set_state(State::BOUND, _rerequest_timeout(1));
|
|
|
|
Ipv4_address dns_server;
|
|
|
|
try { dns_server = dhcp.option<Dhcp_packet::Dns_server_ipv4>().value(); }
|
|
|
|
catch (Dhcp_packet::Option_not_found) { }
|
|
|
|
_domain().ip_config(dhcp.yiaddr(),
|
|
|
|
dhcp.option<Dhcp_packet::Subnet_mask>().value(),
|
|
|
|
dhcp.option<Dhcp_packet::Router_ipv4>().value(),
|
|
|
|
dns_server);
|
|
|
|
break;
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|
|
|
|
case State::RENEW:
|
|
|
|
case State::REBIND:
|
|
|
|
|
|
|
|
if (msg_type != Message_type::ACK) {
|
2017-12-05 13:43:02 +00:00
|
|
|
throw Drop_packet_inform("DHCP client expects an acknowledgement");
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|
|
|
|
_set_state(State::BOUND, _rerequest_timeout(1));
|
|
|
|
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
|
|
|
|
break;
|
|
|
|
|
2017-12-05 13:43:02 +00:00
|
|
|
default: throw Drop_packet_inform("DHCP client doesn't expect a packet");
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Dhcp_client::_send(Message_type msg_type,
|
|
|
|
Ipv4_address client_ip,
|
2018-04-04 15:25:52 +00:00
|
|
|
Ipv4_address server_ip,
|
|
|
|
Ipv4_address requested_ip)
|
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
2017-10-16 09:31:43 +00:00
|
|
|
{
|
|
|
|
Mac_address client_mac = _interface.router_mac();
|
2018-04-26 12:53:29 +00:00
|
|
|
_interface.send(PKT_SIZE, [&] (void *pkt_base, Size_guard &size_guard) {
|
2017-12-20 14:56:47 +00:00
|
|
|
|
|
|
|
/* create ETH header of the request */
|
2018-04-26 12:53:29 +00:00
|
|
|
Ethernet_frame ð = Ethernet_frame::construct_at(pkt_base, size_guard);
|
2017-12-20 14:56:47 +00:00
|
|
|
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 };
|
2018-04-26 12:53:29 +00:00
|
|
|
size_t const ip_off = size_guard.head_size();
|
|
|
|
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size_guard);
|
2017-12-20 14:56:47 +00:00
|
|
|
ip.header_length(sizeof(Ipv4_packet) / 4);
|
|
|
|
ip.version(4);
|
|
|
|
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 */
|
2018-04-26 12:53:29 +00:00
|
|
|
size_t const udp_off = size_guard.head_size();
|
|
|
|
Udp_packet &udp = ip.construct_at_data<Udp_packet>(size_guard);
|
2017-12-20 14:56:47 +00:00
|
|
|
udp.src_port(Port(Dhcp_packet::BOOTPC));
|
|
|
|
udp.dst_port(Port(Dhcp_packet::BOOTPS));
|
|
|
|
|
|
|
|
/* create mandatory DHCP fields of the request */
|
2018-04-26 12:53:29 +00:00
|
|
|
size_t const dhcp_off = size_guard.head_size();
|
|
|
|
Dhcp_packet &dhcp = udp.construct_at_data<Dhcp_packet>(size_guard);
|
2017-12-20 14:56:47 +00:00
|
|
|
dhcp.op(Dhcp_packet::REQUEST);
|
|
|
|
dhcp.htype(Dhcp_packet::Htype::ETH);
|
|
|
|
dhcp.hlen(sizeof(Mac_address));
|
|
|
|
dhcp.ciaddr(client_ip);
|
|
|
|
dhcp.client_mac(client_mac);
|
|
|
|
dhcp.default_magic_cookie();
|
|
|
|
|
|
|
|
/* append DHCP option fields to the request */
|
2018-04-26 12:53:29 +00:00
|
|
|
Dhcp_options dhcp_opts(dhcp, size_guard);
|
2017-12-20 14:56:47 +00:00
|
|
|
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
|
|
|
|
switch (msg_type) {
|
|
|
|
case Message_type::DISCOVER:
|
2018-04-06 15:34:01 +00:00
|
|
|
append_param_req_list(dhcp_opts);
|
2017-12-20 14:56:47 +00:00
|
|
|
dhcp_opts.append_option<Dhcp_packet::Client_id>(client_mac);
|
|
|
|
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(PKT_SIZE - dhcp_off);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Message_type::REQUEST:
|
2018-04-06 15:34:01 +00:00
|
|
|
append_param_req_list(dhcp_opts);
|
2017-12-20 14:56:47 +00:00
|
|
|
dhcp_opts.append_option<Dhcp_packet::Client_id>(client_mac);
|
|
|
|
dhcp_opts.append_option<Dhcp_packet::Max_msg_size>(PKT_SIZE - dhcp_off);
|
|
|
|
if (_state == State::REQUEST) {
|
2018-04-04 15:25:52 +00:00
|
|
|
dhcp_opts.append_option<Dhcp_packet::Requested_addr>(requested_ip);
|
2017-12-20 14:56:47 +00:00
|
|
|
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(server_ip);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
throw Interface::Bad_send_dhcp_args();
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|
2017-12-20 14:56:47 +00:00
|
|
|
dhcp_opts.append_option<Dhcp_packet::Options_end>();
|
|
|
|
|
|
|
|
/* fill in header values that need the packet to be complete already */
|
2018-04-26 12:53:29 +00:00
|
|
|
udp.length(size_guard.head_size() - udp_off);
|
2017-12-20 14:56:47 +00:00
|
|
|
udp.update_checksum(ip.src(), ip.dst());
|
2018-04-26 12:53:29 +00:00
|
|
|
ip.total_length(size_guard.head_size() - ip_off);
|
2018-04-16 22:35:16 +00:00
|
|
|
ip.update_checksum();
|
2017-12-20 14:56:47 +00:00
|
|
|
});
|
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
2017-10-16 09:31:43 +00:00
|
|
|
}
|