genode/repos/os/src/server/nic_bridge/component.cc
Martin Stein 0ce79f3a8a udp: rename method calc_checksum update_checksum
In other contexts (IPv4) 'calc_checksum' merely returns a new checksum that is
then installed via 'checksum'. Thus, the UDP 'calc_checksum' that calculates AND
installs a new checksum is misleading.

Ref #114
2016-08-29 17:29:38 +02:00

156 lines
4.3 KiB
C++

/*
* \brief Proxy-ARP session and root component
* \author Stefan Kalkowski
* \date 2010-08-18
*/
/*
* Copyright (C) 2010-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.
*/
/* Genode */
#include <net/arp.h>
#include <net/dhcp.h>
#include <net/udp.h>
#include <component.h>
using namespace Net;
bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
{
Arp_packet *arp =
new (eth->data<void>()) Arp_packet(size - sizeof(Ethernet_frame));
if (arp->ethernet_ipv4() &&
arp->opcode() == Arp_packet::REQUEST) {
/*
* 'Gratuitous ARP' broadcast messages are used to announce newly created
* IP<->MAC address mappings to other hosts. nic_bridge-internal hosts
* would expect a nic_bridge-internal MAC address in this message, whereas
* external hosts would expect the NIC's MAC address in this message.
* The simplest solution to this problem is to just drop those messages,
* since they are not really necessary.
*/
if (arp->src_ip() == arp->dst_ip())
return false;
Ipv4_address_node *node = vlan().ip_tree.first();
if (node)
node = node->find_by_address(arp->dst_ip());
if (!node) {
arp->src_mac(_nic.mac());
}
}
return true;
}
bool Session_component::handle_ip(Ethernet_frame *eth, Genode::size_t size)
{
Ipv4_packet *ip =
new (eth->data<void>()) Ipv4_packet(size - sizeof(Ethernet_frame));
if (ip->protocol() == Udp_packet::IP_ID)
{
Udp_packet *udp = new (ip->data<void>())
Udp_packet(size - sizeof(Ipv4_packet));
if (Dhcp_packet::is_dhcp(udp)) {
Dhcp_packet *dhcp = new (udp->data<void>())
Dhcp_packet(size - sizeof(Ipv4_packet) - sizeof(Udp_packet));
if (dhcp->op() == Dhcp_packet::REQUEST) {
dhcp->broadcast(true);
udp->update_checksum(ip->src(), ip->dst());
}
}
}
return true;
}
void Session_component::finalize_packet(Ethernet_frame *eth,
Genode::size_t size)
{
Mac_address_node *node = vlan().mac_tree.first();
if (node)
node = node->find_by_address(eth->dst());
if (node)
node->component().send(eth, size);
else {
/* set our MAC as sender */
eth->src(_nic.mac());
_nic.send(eth, size);
}
}
void Session_component::_unset_ipv4_node()
{
Ipv4_address_node * first = vlan().ip_tree.first();
if (!first) return;
if (first->find_by_address(_ipv4_node.addr()))
vlan().ip_tree.remove(&_ipv4_node);
}
bool Session_component::link_state() { return _nic.link_state(); }
void Session_component::set_ipv4_address(Ipv4_address ip_addr)
{
_unset_ipv4_node();
_ipv4_node.addr(ip_addr);
vlan().ip_tree.insert(&_ipv4_node);
}
Session_component::Session_component(Genode::Ram_session &ram,
Genode::Region_map &rm,
Genode::Entrypoint &ep,
Genode::size_t amount,
Genode::size_t tx_buf_size,
Genode::size_t rx_buf_size,
Mac_address vmac,
Net::Nic &nic,
char *ip_addr)
: Stream_allocator(ram, rm, amount),
Stream_dataspaces(ram, tx_buf_size, rx_buf_size),
Session_rpc_object(Stream_dataspaces::tx_ds,
Stream_dataspaces::rx_ds,
Stream_allocator::range_allocator(), ep.rpc_ep()),
Packet_handler(ep, nic.vlan()),
_mac_node(*this, vmac),
_ipv4_node(*this),
_nic(nic)
{
vlan().mac_tree.insert(&_mac_node);
vlan().mac_list.insert(&_mac_node);
/* static ip parsing */
if (ip_addr != 0 && Genode::strlen(ip_addr)) {
Ipv4_address ip = Ipv4_packet::ip_from_string(ip_addr);
if (ip == Ipv4_address()) {
Genode::warning("Empty or error ip address. Skipped.");
} else {
set_ipv4_address(ip);
Genode::log("vmac = ", vmac, " ip = ", ip);
}
}
_tx.sigh_ready_to_ack(_sink_ack);
_tx.sigh_packet_avail(_sink_submit);
_rx.sigh_ack_avail(_source_ack);
_rx.sigh_ready_to_submit(_source_submit);
}
Session_component::~Session_component() {
vlan().mac_tree.remove(&_mac_node);
vlan().mac_list.remove(&_mac_node);
_unset_ipv4_node();
}