diff --git a/src/lib/remote_rom/backend/nic_ip/base.cc b/src/lib/remote_rom/backend/nic_ip/base.cc index b3e446b..5fe3c34 100644 --- a/src/lib/remote_rom/backend/nic_ip/base.cc +++ b/src/lib/remote_rom/backend/nic_ip/base.cc @@ -20,6 +20,28 @@ void Remote_rom::Backend_base::_handle_rx_packet() } } +void Remote_rom::Backend_base::_handle_arp_request(Ethernet_frame ð, + Size_guard &guard, + Arp_packet &arp) +{ + /* + * The ARP packet gets re-written, we interchange source + * and destination MAC and IP addresses, and set the opcode + * to reply, and then push the packet back to the NIC driver. + */ + Ipv4_address old_src_ip = arp.src_ip(); + arp.opcode(Arp_packet::REPLY); + arp.dst_mac(arp.src_mac()); + arp.src_mac(_mac_address); + arp.src_ip(arp.dst_ip()); + arp.dst_ip(old_src_ip); + eth.dst(arp.dst_mac()); + + /* set our MAC as sender */ + eth.src(_mac_address); + send(ð, guard.total_size()); +} + void Remote_rom::Backend_base::handle_ethernet(void* src, Genode::size_t size) { try { @@ -51,23 +73,17 @@ void Remote_rom::Backend_base::handle_arp(Ethernet_frame ð, /* look whether the IP address is our's */ if (arp.dst_ip() == _accept_ip) { - if (arp.opcode() == Arp_packet::REQUEST) { - /* - * The ARP packet gets re-written, we interchange source - * and destination MAC and IP addresses, and set the opcode - * to reply, and then push the packet back to the NIC driver. - */ - Ipv4_address old_src_ip = arp.src_ip(); - arp.opcode(Arp_packet::REPLY); - arp.dst_mac(arp.src_mac()); - arp.src_mac(_mac_address); - arp.src_ip(arp.dst_ip()); - arp.dst_ip(old_src_ip); - eth.dst(arp.dst_mac()); - - /* set our MAC as sender */ - eth.src(_mac_address); - send(ð, edguard.total_size()); + switch (arp.opcode()) { + case Arp_packet::REQUEST: + _handle_arp_request(eth, edguard, arp); + break; + case Arp_packet::REPLY: + if (_arp_waiting && arp.src_ip() == _dst_ip) { + _dst_mac = arp.src_mac(); + _arp_waiting = false; + } + break; + default: break; } } } @@ -80,6 +96,9 @@ void Remote_rom::Backend_base::handle_ip(Ethernet_frame ð, || _accept_ip == ip.dst()) { if (ip.protocol() == Ipv4_packet::Protocol::UDP) { + if (_dst_mac == Ethernet_frame::broadcast() && ip.src() == _dst_ip) { + _dst_mac = eth.src(); + } /* remote_rom protocol is wrapped in UDP */ Udp_packet &udp = ip.data(edguard); if (udp.dst_port() == _udp_port) diff --git a/src/lib/remote_rom/backend/nic_ip/base.h b/src/lib/remote_rom/backend/nic_ip/base.h index f364ccb..44ac0d2 100644 --- a/src/lib/remote_rom/backend/nic_ip/base.h +++ b/src/lib/remote_rom/backend/nic_ip/base.h @@ -54,6 +54,10 @@ class Remote_rom::Backend_base : public Genode::Interface /* rx packet handler */ void _handle_rx_packet(); + void _handle_arp_request(Ethernet_frame ð, + Size_guard &guard, + Arp_packet &arp); + void _handle_link_state() { Genode::log("link state changed"); @@ -79,6 +83,7 @@ class Remote_rom::Backend_base : public Genode::Interface Timer::Connection _timer; const bool _verbose = false; + bool _arp_waiting { false }; Nic::Packet_allocator _tx_block_alloc; Nic::Connection _nic; Mac_address _mac_address; @@ -93,8 +98,41 @@ class Remote_rom::Backend_base : public Genode::Interface */ virtual void receive(Packet &packet, Size_guard &) = 0; + inline void arp_request() + { + if (_dst_mac == Ethernet_frame::broadcast() && !_arp_waiting) { + size_t const frame_size = sizeof(Ethernet_frame) + + sizeof(Arp_packet); + Nic::Packet_descriptor pd = alloc_tx_packet(frame_size); + Size_guard size_guard(pd.size()); + + char *content = _nic.tx()->packet_content(pd); + Ethernet_frame ð = Ethernet_frame::construct_at(content, + size_guard); + eth.src(_mac_address); + eth.dst(Ethernet_frame::broadcast()); + eth.type(Ethernet_frame::Type::ARP); + + Arp_packet &arp = eth.construct_at_data(size_guard); + arp.hardware_address_type(Arp_packet::ETHERNET); + arp.protocol_address_type(Arp_packet::IPV4); + arp.hardware_address_size(sizeof(Mac_address)); + arp.protocol_address_size(sizeof(Ipv4_address)); + arp.opcode(Arp_packet::REQUEST); + arp.src_mac(_mac_address); + arp.src_ip(_src_ip); + arp.dst_mac(Ethernet_frame::broadcast()); + arp.dst_ip(_dst_ip); + + _arp_waiting = true; + submit_tx_packet(pd); + } + } + Ethernet_frame &prepare_eth(void *base, Size_guard &size_guard) { + arp_request(); + Ethernet_frame ð = Ethernet_frame::construct_at(base, size_guard); eth.src(_mac_address); eth.dst(_dst_mac);