From d63c40af3e8e4c2f70859aeae443112489de80eb Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 14 Sep 2017 16:32:29 +0200 Subject: [PATCH] dhcp: extend options utilities Provide utilities for appending new options to an existing DHCP packet and a utility for finding existing options that returns a typed option object. Remove old version that return untyped options. Ref #2490 --- repos/os/include/net/dhcp.h | 304 +++++++++++++++++++------- repos/os/src/server/nic_bridge/nic.cc | 15 +- 2 files changed, 234 insertions(+), 85 deletions(-) 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