diff --git a/repos/os/src/server/nic_router/dhcp_client.cc b/repos/os/src/server/nic_router/dhcp_client.cc index 340fa28313..b15e8040ec 100644 --- a/repos/os/src/server/nic_router/dhcp_client.cc +++ b/repos/os/src/server/nic_router/dhcp_client.cc @@ -173,7 +173,7 @@ void Dhcp_client::_send(Message_type msg_type, Ipv4_address server_ip) { enum { PKT_SIZE = 1024 }; - using Size_guard = Size_guard_tpl; + using Size_guard = Size_guard_tpl; Mac_address client_mac = _interface.router_mac(); _interface.send(PKT_SIZE, [&] (void *pkt_base) { diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index 87e5d8e0d5..bcd3b2c140 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -433,7 +433,7 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv, Ipv4_address_prefix const &local_intf) { enum { PKT_SIZE = 512 }; - using Size_guard = Genode::Size_guard_tpl; + using Size_guard = Genode::Size_guard_tpl; send(PKT_SIZE, [&] (void *pkt_base) { /* create ETH header of the reply */ @@ -445,7 +445,6 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv, eth.type(Ethernet_frame::Type::IPV4); /* create IP header of the reply */ - enum { IPV4_TIME_TO_LIVE = 64 }; size_t const ip_off = size.curr(); Ipv4_packet &ip = *eth.data(size.left()); size.add(sizeof(Ipv4_packet)); @@ -676,6 +675,64 @@ void Interface::_domain_broadcast(Ethernet_frame ð, } +void Interface::_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) +{ + enum { + ICMP_MAX_DATA_SIZE = sizeof(Ipv4_packet) + 8, + PKT_SIZE = sizeof(Ethernet_frame) + sizeof(Ipv4_packet) + + sizeof(Icmp_packet) + ICMP_MAX_DATA_SIZE, + }; + using Size_guard = Genode::Size_guard_tpl; + send(PKT_SIZE, [&] (void *pkt_base) { + + /* create ETH header */ + Size_guard size; + size.add(sizeof(Ethernet_frame)); + Ethernet_frame ð = *reinterpret_cast(pkt_base); + eth.dst(req_eth.src()); + eth.src(_router_mac); + eth.type(Ethernet_frame::Type::IPV4); + + /* create IP header */ + size_t const ip_off = size.curr(); + Ipv4_packet &ip = *eth.data(size.left()); + size.add(sizeof(Ipv4_packet)); + ip.header_length(sizeof(Ipv4_packet) / 4); + ip.version(4); + ip.diff_service(0); + ip.ecn(0); + ip.identification(0); + ip.flags(0); + ip.fragment_offset(0); + ip.time_to_live(IPV4_TIME_TO_LIVE); + ip.protocol(Ipv4_packet::Protocol::ICMP); + ip.src(local_intf.address); + ip.dst(req_ip.src()); + + /* create ICMP header */ + Icmp_packet &icmp = *ip.data(size.left()); + size.add(sizeof(Icmp_packet)); + icmp.type(Icmp_packet::Type::DST_UNREACHABLE); + icmp.code(code); + icmp.rest_of_header(0); + size_t icmp_data_size = req_ip.total_length(); + if (icmp_data_size > ICMP_MAX_DATA_SIZE) { + icmp_data_size = ICMP_MAX_DATA_SIZE; + } + size.add(icmp_data_size); + Genode::memcpy(&icmp.data(~0), &req_ip, icmp_data_size); + + /* fill in header values that require the packet to be complete */ + icmp.update_checksum(icmp_data_size); + ip.total_length(size.curr() - ip_off); + ip.checksum(Ipv4_packet::calculate_checksum(ip)); + }); +} + + void Interface::_handle_ip(Ethernet_frame ð, Genode::size_t const eth_size, Packet_descriptor const &pkt, @@ -812,6 +869,8 @@ void Interface::_handle_ip(Ethernet_frame ð, catch (Ip_rule_list::No_match) { } /* give up and drop packet */ + _send_icmp_dst_unreachable(local_intf, eth, ip, + Icmp_packet::Code::DST_NET_UNREACHABLE); if (_config().verbose()) { log("Unroutable packet"); } } @@ -1076,8 +1135,8 @@ void Interface::_handle_eth(void *const eth_base, catch (Alloc_dhcp_msg_buffer_failed) { error("failed to allocate buffer for DHCP reply"); } - catch (Dhcp_msg_buffer_too_small) { - error("DHCP reply buffer too small"); } + catch (Send_buffer_too_small) { + error("Send buffer buffer too small"); } catch (Dhcp_server::Alloc_ip_failed) { error("failed to allocate IP for DHCP client"); } diff --git a/repos/os/src/server/nic_router/interface.h b/repos/os/src/server/nic_router/interface.h index 07f4251e0f..194554c3f9 100644 --- a/repos/os/src/server/nic_router/interface.h +++ b/repos/os/src/server/nic_router/interface.h @@ -25,6 +25,7 @@ /* Genode includes */ #include #include +#include namespace Net { @@ -75,6 +76,8 @@ class Net::Interface : private Interface_list::Element private: + enum { IPV4_TIME_TO_LIVE = 64 }; + struct Dismiss_link : Genode::Exception { }; struct Dismiss_arp_waiter : Genode::Exception { }; @@ -239,6 +242,11 @@ class Net::Interface : private Interface_list::Element void _apply_foreign_arp(); + 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); + /*********************************** @@ -257,7 +265,7 @@ class Net::Interface : private Interface_list::Element struct Bad_network_protocol : Genode::Exception { }; struct Packet_postponed : Genode::Exception { }; struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { }; - struct Dhcp_msg_buffer_too_small : Genode::Exception { }; + struct Send_buffer_too_small : Genode::Exception { }; struct Drop_packet_inform : Genode::Exception { diff --git a/repos/os/src/server/nic_router/link.cc b/repos/os/src/server/nic_router/link.cc index 85cb88163a..5fa1b9a9dd 100644 --- a/repos/os/src/server/nic_router/link.cc +++ b/repos/os/src/server/nic_router/link.cc @@ -176,6 +176,7 @@ void Link::handle_config(Domain &cln_domain, switch (_protocol) { case L3_protocol::TCP: dissolve_timeout_us = config.tcp_idle_timeout(); break; case L3_protocol::UDP: dissolve_timeout_us = config.tcp_idle_timeout(); break; + default: throw Interface::Bad_transport_protocol(); } _dissolve_timeout_us = dissolve_timeout_us; _dissolve_timeout.schedule(_dissolve_timeout_us);