/* * \brief DHCP related definitions * \author Stefan Kalkowski * \date 2010-08-19 */ /* * Copyright (C) 2010-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 _NET__DHCP_H_ #define _NET__DHCP_H_ /* Genode */ #include #include #include #include #include #include #include namespace Net { class Dhcp_packet; } /** * Data layout of this class conforms to an DHCP packet (RFC 2131) * * DHCP packet layout: * * =================================== * | 1 byte | 1 byte | 1 byte | 1 byte | * =================================== * | op | htype | hlen | hops | * ----------------------------------- * | connection-id (xid) | * ----------------------------------- * | seconds | flags | * ----------------------------------- * | client-ip-address | * ----------------------------------- * | your-ip-address | * ----------------------------------- * | server-ip-address | * ----------------------------------- * | relay-agent-ip-address | * ----------------------------------- * | client-hw-address | * | (16 bytes) | * ----------------------------------- * | sname | * | (64 bytes) | * ----------------------------------- * | file | * | (128 bytes) | * ----------------------------------- * | options | * | (312 bytes, optional) | * ----------------------------------- */ class Net::Dhcp_packet { private: Genode::uint8_t _op; Genode::uint8_t _htype; Genode::uint8_t _hlen; Genode::uint8_t _hops; Genode::uint32_t _xid; Genode::uint16_t _secs; Genode::uint16_t _flags; Genode::uint8_t _ciaddr[Ipv4_packet::ADDR_LEN]; Genode::uint8_t _yiaddr[Ipv4_packet::ADDR_LEN]; Genode::uint8_t _siaddr[Ipv4_packet::ADDR_LEN]; Genode::uint8_t _giaddr[Ipv4_packet::ADDR_LEN]; Genode::uint8_t _chaddr[16]; Genode::uint8_t _sname[64]; Genode::uint8_t _file[128]; Genode::uint32_t _magic_cookie; Genode::uint8_t _opts[0]; enum Flag { BROADCAST = 0x80 }; public: enum class Htype : Genode::uint8_t { ETH = 1 }; enum Opcode { REQUEST = 1, REPLY = 2, INVALID }; enum Udp_port { BOOTPS = 67, BOOTPC = 68 }; void default_magic_cookie() { _magic_cookie = host_to_big_endian(0x63825363); } /******************************* ** 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, DOMAIN_NAME = 15, BROADCAST_ADDR = 28, REQ_IP_ADDR = 50, IP_LEASE_TIME = 51, MSG_TYPE = 53, SERVER = 54, PARAM_REQ_LIST = 55, MAX_MSG_SZ = 57, CLI_ID = 61, END = 255, }; Option(Code code, Genode::uint8_t len) : _code((Genode::uint8_t)code), _len(len) { } Code code() const { return (Code)_code; } Genode::uint8_t len() const { return _len; } /********* ** log ** *********/ void print(Genode::Output &output) const; } __attribute__((packed)); struct Option_not_found : Genode::Exception { Option::Code const code; Option_not_found(Option::Code code) : code(code) { } }; /** * 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)) { } unsigned long value() const { return host_to_big_endian(_value); } }; /** * DHCP option to request specific option type values from the server */ struct Parameter_request_list : Option { static constexpr Code CODE = Code::PARAM_REQ_LIST; Parameter_request_list(Genode::size_t len) : Option(CODE, len) { } }; /** * Domain name server option */ class Dns_server : public Option { private: Ipv4_address _dns_servers[0]; public: static constexpr Code CODE = Code::DNS_SERVER; Dns_server(Genode::size_t len) : Option(CODE, len) { } template void for_each_address(FUNC && func) const { for (unsigned idx = 0; idx < len() / sizeof(_dns_servers[0]); idx++) { func(_dns_servers[idx]); } } }; /** * Domain name option */ class Domain_name : public Option { private: char _name[0]; public: static constexpr Code CODE = Code::DOMAIN_NAME; Domain_name (Genode::size_t len) : Option(CODE, len) { } template void with_string(FUNC && func) const { func(_name, Option::len()); } }; 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; using Requested_addr = Ipv4_option; class Client_id { private: Genode::uint8_t _code; Genode::uint8_t _len; Genode::uint8_t _value[7]; public: Client_id(Mac_address value) : _code((Genode::uint8_t)Option::Code::CLI_ID), _len(7) { _value[0] = 1; _value[1] = value.addr[0]; _value[2] = value.addr[1]; _value[3] = value.addr[2]; _value[4] = value.addr[3]; _value[5] = value.addr[4]; _value[6] = value.addr[5]; } Genode::uint8_t code() const { return _code; } Genode::uint8_t len() const { return _len; } } __attribute__((packed)); struct Max_msg_size : Option_tpl { static constexpr Code CODE = Code::MAX_MSG_SZ; Max_msg_size(Genode::uint16_t size) : Option_tpl(CODE, host_to_big_endian(size)) { } }; /** * 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: class Parameter_request_list_data { private: Genode::uint8_t *const _base; Genode::size_t _size { 0 }; SIZE_GUARD &_size_guard; public: Parameter_request_list_data(Genode::uint8_t *base, SIZE_GUARD &size_guard) : _base { base }, _size_guard { size_guard } { } template void append_param_req() { _size_guard.consume_head(sizeof(_base[0])); _base[_size] = (Genode::uint8_t)OPTION::CODE; _size++; } Genode::size_t size() const { return _size; } }; class Dns_server_data { private: Ipv4_address *const _addr_array; Genode::size_t _addr_idx { 0 }; SIZE_GUARD &_pkt_size_guard; public: Dns_server_data(Ipv4_address *addr_array, SIZE_GUARD &pkt_size_guard) : _addr_array { addr_array }, _pkt_size_guard { pkt_size_guard } { } void append_address(Ipv4_address const &addr) { _pkt_size_guard.consume_head(sizeof(_addr_array[0])); _addr_array[_addr_idx] = addr; _addr_idx++; } Genode::size_t size() const { return _addr_idx * sizeof(Ipv4_address); } }; 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.consume_head(sizeof(OPTION)); Genode::construct_at