remote_rom: implement ARP requests

This commit is contained in:
Johannes Schlatow
2018-11-30 14:40:23 +01:00
committed by Norman Feske
parent 8ed98b8459
commit 92ef8619c7
2 changed files with 74 additions and 17 deletions

View File

@@ -20,6 +20,28 @@ void Remote_rom::Backend_base::_handle_rx_packet()
} }
} }
void Remote_rom::Backend_base::_handle_arp_request(Ethernet_frame &eth,
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(&eth, guard.total_size());
}
void Remote_rom::Backend_base::handle_ethernet(void* src, Genode::size_t size) void Remote_rom::Backend_base::handle_ethernet(void* src, Genode::size_t size)
{ {
try { try {
@@ -51,23 +73,17 @@ void Remote_rom::Backend_base::handle_arp(Ethernet_frame &eth,
/* look whether the IP address is our's */ /* look whether the IP address is our's */
if (arp.dst_ip() == _accept_ip) { if (arp.dst_ip() == _accept_ip) {
if (arp.opcode() == Arp_packet::REQUEST) { switch (arp.opcode()) {
/* case Arp_packet::REQUEST:
* The ARP packet gets re-written, we interchange source _handle_arp_request(eth, edguard, arp);
* and destination MAC and IP addresses, and set the opcode break;
* to reply, and then push the packet back to the NIC driver. case Arp_packet::REPLY:
*/ if (_arp_waiting && arp.src_ip() == _dst_ip) {
Ipv4_address old_src_ip = arp.src_ip(); _dst_mac = arp.src_mac();
arp.opcode(Arp_packet::REPLY); _arp_waiting = false;
arp.dst_mac(arp.src_mac()); }
arp.src_mac(_mac_address); break;
arp.src_ip(arp.dst_ip()); default: break;
arp.dst_ip(old_src_ip);
eth.dst(arp.dst_mac());
/* set our MAC as sender */
eth.src(_mac_address);
send(&eth, edguard.total_size());
} }
} }
} }
@@ -80,6 +96,9 @@ void Remote_rom::Backend_base::handle_ip(Ethernet_frame &eth,
|| _accept_ip == ip.dst()) { || _accept_ip == ip.dst()) {
if (ip.protocol() == Ipv4_packet::Protocol::UDP) { 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 */ /* remote_rom protocol is wrapped in UDP */
Udp_packet &udp = ip.data<Udp_packet>(edguard); Udp_packet &udp = ip.data<Udp_packet>(edguard);
if (udp.dst_port() == _udp_port) if (udp.dst_port() == _udp_port)

View File

@@ -54,6 +54,10 @@ class Remote_rom::Backend_base : public Genode::Interface
/* rx packet handler */ /* rx packet handler */
void _handle_rx_packet(); void _handle_rx_packet();
void _handle_arp_request(Ethernet_frame &eth,
Size_guard &guard,
Arp_packet &arp);
void _handle_link_state() void _handle_link_state()
{ {
Genode::log("link state changed"); Genode::log("link state changed");
@@ -79,6 +83,7 @@ class Remote_rom::Backend_base : public Genode::Interface
Timer::Connection _timer; Timer::Connection _timer;
const bool _verbose = false; const bool _verbose = false;
bool _arp_waiting { false };
Nic::Packet_allocator _tx_block_alloc; Nic::Packet_allocator _tx_block_alloc;
Nic::Connection _nic; Nic::Connection _nic;
Mac_address _mac_address; Mac_address _mac_address;
@@ -93,8 +98,41 @@ class Remote_rom::Backend_base : public Genode::Interface
*/ */
virtual void receive(Packet &packet, Size_guard &) = 0; 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 &eth = 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<Arp_packet>(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) Ethernet_frame &prepare_eth(void *base, Size_guard &size_guard)
{ {
arp_request();
Ethernet_frame &eth = Ethernet_frame::construct_at(base, size_guard); Ethernet_frame &eth = Ethernet_frame::construct_at(base, size_guard);
eth.src(_mac_address); eth.src(_mac_address);
eth.dst(_dst_mac); eth.dst(_dst_mac);