diff --git a/repos/os/include/net/dhcp.h b/repos/os/include/net/dhcp.h
index c370561092..ba2cdbef7d 100644
--- a/repos/os/include/net/dhcp.h
+++ b/repos/os/include/net/dhcp.h
@@ -17,6 +17,7 @@
/* Genode */
#include
#include
+#include
#include
#include
@@ -65,7 +66,8 @@ class Net::Dhcp_packet
{
public:
- class No_dhcp_packet : Genode::Exception {};
+ struct No_dhcp_packet : Genode::Exception { };
+ struct Option_not_found : Genode::Exception { };
private:
@@ -92,32 +94,6 @@ class Net::Dhcp_packet
enum class Htype : Genode::uint8_t { ETH = 1 };
- /**
- * This class represents the data layout of an DHCP option.
- */
- class Option
- {
- private:
-
- Genode::uint8_t _code;
- Genode::uint8_t _len;
- Genode::uint8_t _value[0];
-
- public:
-
- Option() {}
-
- Genode::uint8_t code() { return _code; }
- Genode::size_t length() { return _len; }
- void* value() { return _value; }
-
- /**
- * Placement new.
- */
- void * operator new(__SIZE_TYPE__, void* addr) { return addr; }
- } __attribute__((packed));
-
-
enum Opcode {
REQUEST = 1,
REPLY = 2,
@@ -129,39 +105,6 @@ class Net::Dhcp_packet
BOOTPC = 68
};
- enum Option_type {
- REQ_IP_ADDR = 50,
- IP_LEASE_TIME = 51,
- OPT_OVERLOAD = 52,
- MSG_TYPE = 53,
- SRV_ID = 54,
- REQ_PARAMETER = 55,
- MESSAGE = 56,
- MAX_MSG_SZ = 57,
- RENEWAL = 58,
- REBINDING = 59,
- VENDOR = 60,
- CLI_ID = 61,
- TFTP_SRV_NAME = 66,
- BOOT_FILE = 67,
- END = 255
- };
-
- enum Message_type {
- DHCP_DISCOVER = 1,
- DHCP_OFFER = 2,
- DHCP_REQUEST = 3,
- DHCP_DECLINE = 4,
- DHCP_ACK = 5,
- DHCP_NAK = 6,
- DHCP_RELEASE = 7,
- DHCP_INFORM = 8
- };
-
-
- /*****************
- ** Constructor **
- *****************/
Dhcp_packet(Genode::size_t size) {
/* dhcp packet needs to fit in */
@@ -170,6 +113,228 @@ class Net::Dhcp_packet
}
+ /*******************************
+ ** Utilities for the options **
+ *******************************/
+
+ /**
+ * Header of a DHCP option or DHCP option without a payload
+ */
+ class Option
+ {
+ private:
+
+ Genode::uint8_t _code;
+ Genode::uint8_t _len;
+ Genode::uint8_t _value[0];
+
+ public:
+
+ enum class Code : Genode::uint8_t {
+ INVALID = 0,
+ SUBNET_MASK = 1,
+ ROUTER = 3,
+ DNS_SERVER = 6,
+ BROADCAST_ADDR = 28,
+ REQ_IP_ADDR = 50,
+ IP_LEASE_TIME = 51,
+ OPT_OVERLOAD = 52,
+ MSG_TYPE = 53,
+ SERVER = 54,
+ REQ_PARAMETER = 55,
+ MESSAGE = 56,
+ MAX_MSG_SZ = 57,
+ RENEWAL = 58,
+ REBINDING = 59,
+ VENDOR = 60,
+ CLI_ID = 61,
+ TFTP_SRV_NAME = 66,
+ BOOT_FILE = 67,
+ END = 255,
+ };
+
+ Option(Code code, Genode::uint8_t len)
+ : _code((Genode::uint8_t)code), _len(len) { }
+
+ Option() { }
+
+ Code code() const { return (Code)_code; }
+ Genode::uint8_t len() const { return _len; }
+
+
+ /*********
+ ** log **
+ *********/
+
+ void print(Genode::Output &output) const;
+
+ } __attribute__((packed));
+
+
+ /**
+ * DHCP option that contains a payload of type T
+ */
+ template
+ class Option_tpl : public Option
+ {
+ protected:
+
+ T _value;
+
+ public:
+
+ Option_tpl(Code code, T value)
+ : Option(code, sizeof(T)), _value(value) { }
+
+ } __attribute__((packed));
+
+
+ /**
+ * DHCP option that specifies the IP packet lease time in seconds
+ */
+ struct Ip_lease_time : Option_tpl
+ {
+ static constexpr Code CODE = Code::IP_LEASE_TIME;
+
+ Ip_lease_time(Genode::uint32_t time)
+ : Option_tpl(CODE, host_to_big_endian(time)) { }
+ };
+
+ enum class Message_type : Genode::uint8_t {
+ DISCOVER = 1,
+ OFFER = 2,
+ REQUEST = 3,
+ DECLINE = 4,
+ ACK = 5,
+ NAK = 6,
+ RELEASE = 7,
+ INFORM = 8
+ };
+
+ /**
+ * DHCP option that specifies the DHCP message type
+ */
+ struct Message_type_option : Option_tpl
+ {
+ static constexpr Code CODE = Code::MSG_TYPE;
+
+ Message_type_option(Message_type value)
+ : Option_tpl(CODE, (Genode::uint8_t)value) { }
+
+ Message_type value() const { return (Message_type)_value; }
+ };
+
+
+ /**
+ * DHCP options that have only one IPv4 address as payload
+ */
+ template
+ struct Ipv4_option : Option_tpl
+ {
+ static constexpr Code CODE = _CODE;
+
+ Ipv4_option(Ipv4_address value)
+ : Option_tpl(CODE, value.to_uint32_big_endian()) { }
+
+ Ipv4_address value() const {
+ return Ipv4_address::from_uint32_big_endian(_value); }
+ };
+
+ using Dns_server_ipv4 = Ipv4_option;
+ using Subnet_mask = Ipv4_option;
+ using Broadcast_addr = Ipv4_option;
+ using Router_ipv4 = Ipv4_option;
+ using Server_ipv4 = Ipv4_option;
+
+ /**
+ * DHCP option that marks the end of an options field
+ */
+ struct Options_end : Option
+ {
+ static constexpr Code CODE = Code::END;
+
+ Options_end() : Option(CODE, 0) { }
+ };
+
+
+ /**
+ * Utility to append individual options to an existing DHCP packet
+ *
+ * \param SIZE_GUARD guard that may limit the options list size
+ *
+ * Overwrites existing options if any!
+ */
+ template
+ class Options_aggregator
+ {
+ private:
+
+ Genode::addr_t _base;
+ SIZE_GUARD &_size_guard;
+
+ public:
+
+ Options_aggregator(Dhcp_packet &packet,
+ SIZE_GUARD &size_guard)
+ :
+ _base((Genode::addr_t)packet.opts()),
+ _size_guard(size_guard)
+ { }
+
+ template
+ void append_option(ARGS &&... args)
+ {
+ _size_guard.add(sizeof(OPTION));
+ Genode::construct_at