mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-23 12:58:02 +00:00
0f8a39e5ac
Ref #114
136 lines
3.6 KiB
C++
136 lines
3.6 KiB
C++
/*
|
|
* \brief NIC handler
|
|
* \author Stefan Kalkowski
|
|
* \date 2013-05-24
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2013 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU General Public License version 2.
|
|
*/
|
|
|
|
#include <base/env.h>
|
|
#include <net/ethernet.h>
|
|
#include <net/arp.h>
|
|
#include <net/ipv4.h>
|
|
#include <net/udp.h>
|
|
#include <net/dhcp.h>
|
|
|
|
#include <component.h>
|
|
|
|
using namespace Net;
|
|
|
|
|
|
bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
|
|
Arp_packet *arp = new (eth->data<void>())
|
|
Arp_packet(size - sizeof(Ethernet_frame));
|
|
|
|
/* ignore broken packets */
|
|
if (!arp->ethernet_ipv4())
|
|
return true;
|
|
|
|
/* look whether the IP address is one of our client's */
|
|
Ipv4_address_node *node = vlan().ip_tree.first();
|
|
if (node)
|
|
node = node->find_by_address(arp->dst_ip());
|
|
if (node) {
|
|
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());
|
|
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());
|
|
send(eth, size);
|
|
} else {
|
|
/* overwrite destination MAC */
|
|
arp->dst_mac(node->component().mac_address().addr);
|
|
eth->dst(node->component().mac_address().addr);
|
|
node->component().send(eth, size);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Net::Nic::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
|
|
Ipv4_packet *ip = new (eth->data<void>())
|
|
Ipv4_packet(size - sizeof(Ethernet_frame));
|
|
|
|
/* is it an UDP packet ? */
|
|
if (ip->protocol() == Udp_packet::IP_ID)
|
|
{
|
|
Udp_packet *udp = new (ip->data<void>())
|
|
Udp_packet(size - sizeof(Ipv4_packet));
|
|
|
|
/* is it a DHCP packet ? */
|
|
if (Dhcp_packet::is_dhcp(udp)) {
|
|
Dhcp_packet *dhcp = new (udp->data<void>())
|
|
Dhcp_packet(size - sizeof(Ipv4_packet) - sizeof(Udp_packet));
|
|
|
|
/* check for DHCP ACKs containing new client ips */
|
|
if (dhcp->op() == Dhcp_packet::REPLY) {
|
|
Dhcp_packet::Option *ext = dhcp->option(Dhcp_packet::MSG_TYPE);
|
|
if (ext) {
|
|
/*
|
|
* extract the IP address and set it in the
|
|
* client's session-component
|
|
*/
|
|
Genode::uint8_t *msg_type = (Genode::uint8_t*) ext->value();
|
|
if (*msg_type == Dhcp_packet::DHCP_ACK) {
|
|
Mac_address_node *node =
|
|
vlan().mac_tree.first();
|
|
if (node)
|
|
node = node->find_by_address(dhcp->client_mac());
|
|
if (node)
|
|
node->component().set_ipv4_address(dhcp->yiaddr());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* is it an unicast message to one of our clients ? */
|
|
if (eth->dst() == mac()) {
|
|
Ipv4_address_node *node = vlan().ip_tree.first();
|
|
if (node) {
|
|
node = node->find_by_address(ip->dst());
|
|
if (node) {
|
|
/* overwrite destination MAC */
|
|
eth->dst(node->component().mac_address().addr);
|
|
|
|
/* deliver the packet to the client */
|
|
node->component().send(eth, size);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
Net::Nic::Nic(Genode::Entrypoint &ep, Genode::Heap &heap, Net::Vlan &vlan)
|
|
: Packet_handler(ep, vlan),
|
|
_tx_block_alloc(&heap),
|
|
_nic(&_tx_block_alloc, BUF_SIZE, BUF_SIZE),
|
|
_mac(_nic.mac_address().addr)
|
|
{
|
|
_nic.rx_channel()->sigh_ready_to_ack(_sink_ack);
|
|
_nic.rx_channel()->sigh_packet_avail(_sink_submit);
|
|
_nic.tx_channel()->sigh_ack_avail(_source_ack);
|
|
_nic.tx_channel()->sigh_ready_to_submit(_source_submit);
|
|
_nic.link_state_sigh(_client_link_state);
|
|
}
|