/* * \brief A net interface in form of a signal-driven NIC-packet handler * \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 _INTERFACE_H_ #define _INTERFACE_H_ /* local includes */ #include #include #include #include #include #include #include /* Genode includes */ #include #include #include namespace Genode { class Xml_generator; } namespace Net { using Packet_descriptor = ::Nic::Packet_descriptor; using Packet_stream_sink = ::Nic::Packet_stream_sink< ::Nic::Session::Policy>; using Packet_stream_source = ::Nic::Packet_stream_source< ::Nic::Session::Policy>; using Domain_name = Genode::String<160>; class Ipv4_config; class Forward_rule_tree; class Transport_rule_list; class Ethernet_frame; class Arp_packet; class Interface_policy; class Interface; using Interface_list = List; class Interface_link_stats; class Interface_object_stats; class Dhcp_server; class Configuration; class Domain; } struct Net::Interface_object_stats { Genode::size_t alive { 0 }; Genode::size_t destroyed { 0 }; void report(Genode::Xml_generator &xml); ~Interface_object_stats(); }; struct Net::Interface_link_stats { Genode::size_t refused_for_ram { 0 }; Genode::size_t refused_for_ports { 0 }; Genode::size_t opening { 0 }; Genode::size_t open { 0 }; Genode::size_t closing { 0 }; Genode::size_t closed { 0 }; Genode::size_t dissolved_timeout_opening { 0 }; Genode::size_t dissolved_timeout_open { 0 }; Genode::size_t dissolved_timeout_closing { 0 }; Genode::size_t dissolved_timeout_closed { 0 }; Genode::size_t dissolved_no_timeout { 0 }; Genode::size_t destroyed { 0 }; void report(Genode::Xml_generator &xml); ~Interface_link_stats(); }; struct Net::Interface_policy { virtual Domain_name determine_domain_name() const = 0; virtual void handle_config(Configuration const &config) = 0; virtual Genode::Session_label const &label() const = 0; virtual void report(Genode::Xml_generator &) const { throw Report::Empty(); } virtual ~Interface_policy() { } }; class Net::Interface : private Interface_list::Element { friend class List; friend class Genode::List; private: using Signal_handler = Genode::Signal_handler; using Signal_context_capability = Genode::Signal_context_capability; enum { IPV4_TIME_TO_LIVE = 64 }; enum { MAX_FREE_OPS_PER_EMERGENCY = 1024 }; struct Dismiss_link : Genode::Exception { }; struct Dismiss_arp_waiter : Genode::Exception { }; struct Update_domain { Domain &old_domain; Domain &new_domain; Update_domain(Domain &old_domain, Domain &new_domain) : old_domain(old_domain), new_domain(new_domain) { } }; Packet_stream_sink &_sink; Packet_stream_source &_source; bool &_session_link_state; Signal_context_capability _session_link_state_sigh { }; Signal_handler _sink_ack; Signal_handler _sink_submit; Signal_handler _source_ack; Signal_handler _source_submit; Mac_address const _router_mac; Mac_address const _mac; Reference _config; Interface_policy &_policy; Timer::Connection &_timer; Genode::Allocator &_alloc; Pointer _domain { }; Arp_waiter_list _own_arp_waiters { }; Link_list _tcp_links { }; Link_list _udp_links { }; Link_list _icmp_links { }; Link_list _dissolved_tcp_links { }; Link_list _dissolved_udp_links { }; Link_list _dissolved_icmp_links { }; Dhcp_allocation_tree _dhcp_allocations { }; Dhcp_allocation_list _released_dhcp_allocations { }; Genode::Constructible _dhcp_client { }; Interface_list &_interfaces; Genode::Constructible _update_domain { }; Interface_link_stats _udp_stats { }; Interface_link_stats _tcp_stats { }; Interface_link_stats _icmp_stats { }; Interface_object_stats _arp_stats { }; Interface_object_stats _dhcp_stats { }; void _new_link(L3_protocol const protocol, Link_side_id const &local_id, Pointer remote_port_alloc, Domain &remote_domain, Link_side_id const &remote_id); void _destroy_released_dhcp_allocations(Domain &local_domain); void _destroy_dhcp_allocation(Dhcp_allocation &allocation, Domain &local_domain); void _release_dhcp_allocation(Dhcp_allocation &allocation, Domain &local_domain); void _new_dhcp_allocation(Ethernet_frame ð, Dhcp_packet &dhcp, Dhcp_server &dhcp_srv, Domain &local_domain); void _send_dhcp_reply(Dhcp_server const &dhcp_srv, Mac_address const ð_dst, Mac_address const &client_mac, Ipv4_address const &client_ip, Dhcp_packet::Message_type msg_type, Genode::uint32_t xid, Ipv4_address_prefix const &local_intf); void _send_icmp_echo_reply(Ethernet_frame ð, Ipv4_packet &ip, Icmp_packet &icmp, Genode::size_t icmp_sz, Size_guard &size_guard); Forward_rule_tree &_forward_rules(Domain &local_domain, L3_protocol const prot) const; Transport_rule_list &_transport_rules(Domain &local_domain, L3_protocol const prot) const; void _handle_arp(Ethernet_frame ð, Size_guard &size_guard, Domain &local_domain); void _handle_arp_reply(Ethernet_frame ð, Size_guard &size_guard, Arp_packet &arp, Domain &local_domain); void _handle_arp_request(Ethernet_frame ð, Size_guard &size_guard, Arp_packet &arp, Domain &local_domain); void _send_arp_reply(Ethernet_frame ð, Size_guard &size_guard, Arp_packet &arp); void _handle_dhcp_request(Ethernet_frame ð, Dhcp_packet &dhcp, Domain &local_domain); void _handle_ip(Ethernet_frame ð, Size_guard &size_guard, Packet_descriptor const &pkt, Domain &local_domain); void _handle_icmp_query(Ethernet_frame ð, Size_guard &size_guard, Ipv4_packet &ip, Packet_descriptor const &pkt, L3_protocol prot, void *prot_base, Genode::size_t prot_size, Domain &local_domain); void _handle_icmp_error(Ethernet_frame ð, Size_guard &size_guard, Ipv4_packet &ip, Packet_descriptor const &pkt, Domain &local_domain, Icmp_packet &icmp, Genode::size_t icmp_sz); void _handle_icmp(Ethernet_frame ð, Size_guard &size_guard, Ipv4_packet &ip, Packet_descriptor const &pkt, L3_protocol prot, void *prot_base, Genode::size_t prot_size, Domain &local_domain, Ipv4_address_prefix const &local_intf); void _adapt_eth(Ethernet_frame ð, Ipv4_address const &dst_ip, Packet_descriptor const &pkt, Domain &remote_domain); void _nat_link_and_pass(Ethernet_frame ð, Size_guard &size_guard, Ipv4_packet &ip, L3_protocol const prot, void *const prot_base, Genode::size_t const prot_size, Link_side_id const &local_id, Domain &local_domain, Domain &remote_domain); void _broadcast_arp_request(Ipv4_address const &src_ip, Ipv4_address const &dst_ip); void _domain_broadcast(Ethernet_frame ð, Size_guard &size_guard, Domain &local_domain); void _pass_prot(Ethernet_frame ð, Size_guard &size_guard, Ipv4_packet &ip, L3_protocol const prot, void *const prot_base, Genode::size_t const prot_size); void _pass_ip(Ethernet_frame ð, Size_guard &size_guard, Ipv4_packet &ip); void _handle_pkt(); void _continue_handle_eth(Domain const &domain, Packet_descriptor const &pkt); Ipv4_address const &_router_ip() const; void _handle_eth(void *const eth_base, Size_guard &size_guard, Packet_descriptor const &pkt); void _handle_eth(Ethernet_frame ð, Size_guard &size_guard, Packet_descriptor const &pkt, Domain &local_domain); void _ack_packet(Packet_descriptor const &pkt); void _send_alloc_pkt(Genode::Packet_descriptor &pkt, void * &pkt_base, Genode::size_t pkt_size); void _send_submit_pkt(Genode::Packet_descriptor &pkt, void * &pkt_base, Genode::size_t pkt_size); void _update_dhcp_allocations(Domain &old_domain, Domain &new_domain); void _update_own_arp_waiters(Domain &domain); void _update_udp_tcp_links(L3_protocol prot, Domain &cln_dom); void _update_icmp_links(Domain &cln_dom); void _update_link_check_nat(Link &link, Domain &new_srv_dom, L3_protocol prot, Domain &cln_dom); void _dismiss_link_log(Link &link, char const *reason); void _destroy_link(Link &link); void _update_domain_object(Domain &new_domain); void _detach_from_domain_raw(); void _detach_from_domain(); void _attach_to_domain_raw(Domain &domain); void _apply_foreign_arp(); void _failed_to_send_packet_link(); void _failed_to_send_packet_alloc(); void _send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf, Ethernet_frame const &req_eth, Ipv4_packet const &req_ip, Icmp_packet::Code const code); /*********************************** ** Packet-stream signal handlers ** ***********************************/ void _ready_to_submit(); void _ack_avail() { } void _ready_to_ack(); void _packet_avail() { } public: struct Free_resources_and_retry_handle_eth : Genode::Exception { L3_protocol prot; Free_resources_and_retry_handle_eth(L3_protocol prot = (L3_protocol)0) : prot(prot) { } }; 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 Alloc_dhcp_msg_buffer_failed : Genode::Exception { }; struct Drop_packet : Genode::Exception { char const *reason; Drop_packet(char const *reason) : reason(reason) { } }; Interface(Genode::Entrypoint &ep, Timer::Connection &timer, Mac_address const router_mac, Genode::Allocator &alloc, Mac_address const mac, Configuration &config, Interface_list &interfaces, Packet_stream_sink &sink, Packet_stream_source &source, bool &session_link_state, Interface_policy &policy); virtual ~Interface(); void dhcp_allocation_expired(Dhcp_allocation &allocation); template void send(Genode::size_t pkt_size, FUNC && write_to_pkt) { if (!link_state()) { _failed_to_send_packet_link(); return; } try { Packet_descriptor pkt; void *pkt_base; _send_alloc_pkt(pkt, pkt_base, pkt_size); Size_guard size_guard(pkt_size); write_to_pkt(pkt_base, size_guard); _send_submit_pkt(pkt, pkt_base, pkt_size); } catch (Packet_stream_source::Packet_alloc_failed) { _failed_to_send_packet_alloc(); } } void send(Ethernet_frame ð, Size_guard &size_guard); Link_list &dissolved_links(L3_protocol const protocol); Link_list &links(L3_protocol const protocol); void cancel_arp_waiting(Arp_waiter &waiter); void handle_config_1(Configuration &config); void handle_config_2(); void handle_config_3(); void attach_to_domain(); void detach_from_ip_config(); void attach_to_ip_config(Domain &domain, Ipv4_config const &ip_config); void detach_from_remote_ip_config(); void attach_to_remote_ip_config(); void attach_to_domain_finish(); bool link_state() const; void handle_link_state(); void report(Genode::Xml_generator &xml); /*************** ** Accessors ** ***************/ Configuration const &config() const { return _config(); } Domain &domain() { return _domain(); } Mac_address const &router_mac() const { return _router_mac; } Mac_address const &mac() const { return _mac; } Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; } Signal_handler &sink_ack() { return _sink_ack; } Signal_handler &sink_submit() { return _sink_submit; } Signal_handler &source_ack() { return _source_ack; } Signal_handler &source_submit() { return _source_submit; } Interface_link_stats &udp_stats() { return _udp_stats; } Interface_link_stats &tcp_stats() { return _tcp_stats; } Interface_link_stats &icmp_stats() { return _icmp_stats; } Interface_object_stats &arp_stats() { return _arp_stats; } Interface_object_stats &dhcp_stats() { return _dhcp_stats; } void session_link_state_sigh(Genode::Signal_context_capability sigh); }; #endif /* _INTERFACE_H_ */