remote_rom: implement ARP requests
This commit is contained in:
committed by
Norman Feske
parent
8ed98b8459
commit
92ef8619c7
@@ -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<Udp_packet>(edguard);
|
||||
if (udp.dst_port() == _udp_port)
|
||||
|
||||
@@ -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<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)
|
||||
{
|
||||
arp_request();
|
||||
|
||||
Ethernet_frame ð = Ethernet_frame::construct_at(base, size_guard);
|
||||
eth.src(_mac_address);
|
||||
eth.dst(_dst_mac);
|
||||
|
||||
Reference in New Issue
Block a user