mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-11 15:04:20 +00:00
Let the nic_bridge work event driven (fix #749)
This commit is contained in:
parent
153429268e
commit
853d541340
@ -57,6 +57,8 @@ namespace Net {
|
|||||||
static const Ipv4_address CURRENT; /* current network */
|
static const Ipv4_address CURRENT; /* current network */
|
||||||
static const Ipv4_address BROADCAST; /* broadcast address */
|
static const Ipv4_address BROADCAST; /* broadcast address */
|
||||||
|
|
||||||
|
static Ipv4_address ip_from_string(const char *ip);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
SRC_CC = ethernet.cc
|
SRC_CC = ethernet.cc ipv4.cc
|
||||||
|
|
||||||
vpath %.cc $(REP_DIR)/src/lib/net
|
vpath %.cc $(REP_DIR)/src/lib/net
|
@ -11,7 +11,57 @@
|
|||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <util/token.h>
|
||||||
|
#include <util/string.h>
|
||||||
|
|
||||||
#include <net/ipv4.h>
|
#include <net/ipv4.h>
|
||||||
|
|
||||||
const Net::Ipv4_packet::Ipv4_address Net::Ipv4_packet::CURRENT(0x00);
|
using namespace Net;
|
||||||
const Net::Ipv4_packet::Ipv4_address Net::Ipv4_packet::BROADCAST(0xFF);
|
|
||||||
|
struct Scanner_policy_number
|
||||||
|
{
|
||||||
|
static bool identifier_char(char c, unsigned i ) {
|
||||||
|
return Genode::is_digit(c) && c !='.'; }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ::Genode::Token<Scanner_policy_number> Token;
|
||||||
|
|
||||||
|
|
||||||
|
Ipv4_packet::Ipv4_address Ipv4_packet::ip_from_string(const char *ip)
|
||||||
|
{
|
||||||
|
Ipv4_address ip_addr;
|
||||||
|
Token t(ip);
|
||||||
|
char tmpstr[4];
|
||||||
|
int cnt = 0;
|
||||||
|
unsigned char ipb[4] = {0};
|
||||||
|
|
||||||
|
while(t) {
|
||||||
|
if (t.type() == Token::WHITESPACE || t[0] == '.') {
|
||||||
|
t = t.next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
t.string(tmpstr, sizeof(tmpstr));
|
||||||
|
|
||||||
|
unsigned long tmpc = 0;
|
||||||
|
Genode::ascii_to(tmpstr, &tmpc, 10);
|
||||||
|
ipb[cnt] = tmpc & 0xFF;
|
||||||
|
t = t.next();
|
||||||
|
|
||||||
|
if (cnt == 4)
|
||||||
|
break;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt == 4) {
|
||||||
|
ip_addr.addr[0] = ipb[0];
|
||||||
|
ip_addr.addr[1] = ipb[1];
|
||||||
|
ip_addr.addr[2] = ipb[2];
|
||||||
|
ip_addr.addr[3] = ipb[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ip_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Ipv4_packet::Ipv4_address Ipv4_packet::CURRENT((Genode::uint8_t)0x00);
|
||||||
|
const Ipv4_packet::Ipv4_address Ipv4_packet::BROADCAST((Genode::uint8_t)0xFF);
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Address-node holds a client-specific session-component.
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2010-08-25
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base/lock_guard.h>
|
|
||||||
|
|
||||||
#include "address_node.h"
|
|
||||||
#include "component.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Let the client a receive a network packet.
|
|
||||||
*
|
|
||||||
* \param addr start address network packet.
|
|
||||||
* \param size size of network packet.
|
|
||||||
*/
|
|
||||||
template <unsigned LEN>
|
|
||||||
void Net::Address_node<LEN>::receive_packet(void *addr, Genode::size_t size)
|
|
||||||
{
|
|
||||||
Genode::Lock::Guard lock_guard(*_component->rx_lock());
|
|
||||||
|
|
||||||
Nic::Session::Rx::Source *source = _component->rx_source();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
/* flush remaining acknowledgements */
|
|
||||||
while (source->ack_avail())
|
|
||||||
source->release_packet(source->get_acked_packet());
|
|
||||||
|
|
||||||
try {
|
|
||||||
/* allocate packet in rx channel */
|
|
||||||
Packet_descriptor rx_packet = source->alloc_packet(size);
|
|
||||||
|
|
||||||
Genode::memcpy((void*)source->packet_content(rx_packet),
|
|
||||||
(void*)addr, size);
|
|
||||||
source->submit_packet(rx_packet);
|
|
||||||
return;
|
|
||||||
} catch (Nic::Session::Rx::Source::Packet_alloc_failed) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Let the compiler know, for which template instances this implementation
|
|
||||||
* is used for.
|
|
||||||
*/
|
|
||||||
template void Net::Ipv4_address_node::receive_packet(void *addr, Genode::size_t size);
|
|
||||||
template void Net::Mac_address_node::receive_packet(void *addr, Genode::size_t size);
|
|
@ -65,14 +65,6 @@ namespace Net {
|
|||||||
Address addr() { return _addr; }
|
Address addr() { return _addr; }
|
||||||
Session_component *component() { return _component; }
|
Session_component *component() { return _component; }
|
||||||
|
|
||||||
/**
|
|
||||||
* Let this client node, receive a network-packet
|
|
||||||
*
|
|
||||||
* \param addr start address of network packet
|
|
||||||
* \param size size of network packet
|
|
||||||
*/
|
|
||||||
void receive_packet(void *addr, Genode::size_t size);
|
|
||||||
|
|
||||||
|
|
||||||
/************************
|
/************************
|
||||||
** Avl node interface **
|
** Avl node interface **
|
||||||
|
@ -16,44 +16,17 @@
|
|||||||
#include <net/dhcp.h>
|
#include <net/dhcp.h>
|
||||||
#include <net/udp.h>
|
#include <net/udp.h>
|
||||||
|
|
||||||
#include <util/token.h>
|
#include "env.h"
|
||||||
#include <util/string.h>
|
|
||||||
|
|
||||||
#include "component.h"
|
#include "component.h"
|
||||||
|
#include "nic.h"
|
||||||
#include "vlan.h"
|
#include "vlan.h"
|
||||||
|
|
||||||
using namespace Net;
|
using namespace Net;
|
||||||
|
|
||||||
const int Session_component::verbose = 1;
|
static const int verbose = 1;
|
||||||
|
|
||||||
void Session_component::Tx_handler::acknowledge_last_one()
|
|
||||||
{
|
|
||||||
if (!_tx_packet.valid())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_component->tx_sink()->ready_to_ack())
|
|
||||||
PDBG("need to wait until ready-for-ack");
|
|
||||||
_component->tx_sink()->acknowledge_packet(_tx_packet);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Session_component::Tx_handler::next_packet(void** src, Genode::size_t *size)
|
bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
|
||||||
{
|
|
||||||
while (true) {
|
|
||||||
/* block for a new packet */
|
|
||||||
_tx_packet = _component->tx_sink()->get_packet();
|
|
||||||
if (!_tx_packet.valid()) {
|
|
||||||
PWRN("received invalid packet");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*src = _component->tx_sink()->packet_content(_tx_packet);
|
|
||||||
*size = _tx_packet.size();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Session_component::Tx_handler::handle_arp(Ethernet_frame *eth, Genode::size_t size)
|
|
||||||
{
|
{
|
||||||
Arp_packet *arp =
|
Arp_packet *arp =
|
||||||
new (eth->data()) Arp_packet(size - sizeof(Ethernet_frame));
|
new (eth->data()) Arp_packet(size - sizeof(Ethernet_frame));
|
||||||
@ -71,18 +44,18 @@ bool Session_component::Tx_handler::handle_arp(Ethernet_frame *eth, Genode::size
|
|||||||
if (arp->src_ip() == arp->dst_ip())
|
if (arp->src_ip() == arp->dst_ip())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Ipv4_address_node *node = Vlan::vlan()->ip_tree()->first();
|
Ipv4_address_node *node = Env::vlan()->ip_tree()->first();
|
||||||
if (node)
|
if (node)
|
||||||
node = node->find_by_address(arp->dst_ip());
|
node = node->find_by_address(arp->dst_ip());
|
||||||
if (!node) {
|
if (!node) {
|
||||||
arp->src_mac(_mac);
|
arp->src_mac(Net::Env::nic()->mac());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Session_component::Tx_handler::handle_ip(Ethernet_frame *eth, Genode::size_t size)
|
bool Session_component::handle_ip(Ethernet_frame *eth, Genode::size_t size)
|
||||||
{
|
{
|
||||||
Ipv4_packet *ip =
|
Ipv4_packet *ip =
|
||||||
new (eth->data()) Ipv4_packet(size - sizeof(Ethernet_frame));
|
new (eth->data()) Ipv4_packet(size - sizeof(Ethernet_frame));
|
||||||
@ -104,137 +77,84 @@ bool Session_component::Tx_handler::handle_ip(Ethernet_frame *eth, Genode::size_
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Session_component::Tx_handler::finalize_packet(Ethernet_frame *eth,
|
void Session_component::finalize_packet(Ethernet_frame *eth,
|
||||||
Genode::size_t size)
|
Genode::size_t size)
|
||||||
{
|
{
|
||||||
Mac_address_node *node = Vlan::vlan()->mac_tree()->first();
|
Mac_address_node *node = Env::vlan()->mac_tree()->first();
|
||||||
if (node)
|
if (node)
|
||||||
node = node->find_by_address(eth->dst());
|
node = node->find_by_address(eth->dst());
|
||||||
if (node)
|
if (node)
|
||||||
node->receive_packet((void*) eth, size);
|
node->component()->send(eth, size);
|
||||||
else
|
else {
|
||||||
send_to_nic(eth, size);
|
/* set our MAC as sender */
|
||||||
|
eth->src(Net::Env::nic()->mac());
|
||||||
|
Net::Env::nic()->send(eth, size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Session_component::_free_ipv4_node()
|
void Session_component::_free_ipv4_node()
|
||||||
{
|
{
|
||||||
if (_ipv4_node) {
|
if (_ipv4_node) {
|
||||||
Vlan::vlan()->ip_tree()->remove(_ipv4_node);
|
Env::vlan()->ip_tree()->remove(_ipv4_node);
|
||||||
destroy(this->guarded_allocator(), _ipv4_node);
|
destroy(this->guarded_allocator(), _ipv4_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Scanner_policy_number
|
|
||||||
{
|
|
||||||
static bool identifier_char(char c, unsigned i )
|
|
||||||
{
|
|
||||||
return Genode::is_digit(c) && c !='.';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef ::Genode::Token<Scanner_policy_number> Token;
|
|
||||||
|
|
||||||
|
|
||||||
Ipv4_packet::Ipv4_address Session_component::ip_from_string(const char *ip)
|
|
||||||
{
|
|
||||||
Ipv4_packet::Ipv4_address ip_addr;
|
|
||||||
|
|
||||||
Token t(ip);
|
|
||||||
char tmpstr[4];
|
|
||||||
int cnt = 0;
|
|
||||||
unsigned char ipb[4] = {0};
|
|
||||||
|
|
||||||
while(t) {
|
|
||||||
|
|
||||||
if (t.type() == Token::WHITESPACE || t[0] == '.') {
|
|
||||||
t = t.next();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
t.string(tmpstr, sizeof(tmpstr));
|
|
||||||
|
|
||||||
unsigned long tmpc = 0;
|
|
||||||
Genode::ascii_to(tmpstr, &tmpc, 10);
|
|
||||||
|
|
||||||
ipb[cnt] = tmpc & 0xFF;
|
|
||||||
|
|
||||||
t = t.next();
|
|
||||||
|
|
||||||
if (cnt == 4)
|
|
||||||
break;
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cnt == 4) {
|
|
||||||
ip_addr.addr[0] = ipb[0];
|
|
||||||
ip_addr.addr[1] = ipb[1];
|
|
||||||
ip_addr.addr[2] = ipb[2];
|
|
||||||
ip_addr.addr[3] = ipb[3];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ip_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Session_component::Session_component(Genode::Allocator *allocator,
|
|
||||||
Genode::size_t amount,
|
|
||||||
Genode::size_t tx_buf_size,
|
|
||||||
Genode::size_t rx_buf_size,
|
|
||||||
Ethernet_frame::Mac_address vmac,
|
|
||||||
Nic::Connection *session,
|
|
||||||
Genode::Rpc_entrypoint &ep,
|
|
||||||
char *ip_addr)
|
|
||||||
: Guarded_range_allocator(allocator, amount),
|
|
||||||
Tx_rx_communication_buffers(tx_buf_size, rx_buf_size),
|
|
||||||
Session_rpc_object(Tx_rx_communication_buffers::tx_ds(),
|
|
||||||
Tx_rx_communication_buffers::rx_ds(),
|
|
||||||
this->range_allocator(), ep),
|
|
||||||
_tx_handler(session, this),
|
|
||||||
_mac_node(vmac, this),
|
|
||||||
_ipv4_node(0)
|
|
||||||
{
|
|
||||||
Vlan::vlan()->mac_tree()->insert(&_mac_node);
|
|
||||||
Vlan::vlan()->mac_list()->insert(&_mac_node);
|
|
||||||
|
|
||||||
/* start handler */
|
|
||||||
_tx_handler.start();
|
|
||||||
_tx_handler.wait_for_startup();
|
|
||||||
|
|
||||||
/* static ip parsing */
|
|
||||||
if (ip_addr != 0 && Genode::strlen(ip_addr)) {
|
|
||||||
|
|
||||||
Ipv4_packet::Ipv4_address ip = ip_from_string(ip_addr);
|
|
||||||
|
|
||||||
if (ip == Ipv4_packet::Ipv4_address()) {
|
|
||||||
PDBG("Empty or error ip address. Skipped.");
|
|
||||||
} else {
|
|
||||||
|
|
||||||
set_ipv4_address(ip);
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
PDBG("\nmac=%02x.%02x.%02x.%02x.%02x.%02x ip=%d.%d.%d.%d",
|
|
||||||
vmac.addr[0], vmac.addr[1], vmac.addr[2], vmac.addr[3], vmac.addr[4], vmac.addr[5],
|
|
||||||
ip.addr[0], ip.addr[1], ip.addr[2], ip.addr[3]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Session_component::~Session_component() {
|
|
||||||
Vlan::vlan()->mac_tree()->remove(&_mac_node);
|
|
||||||
Vlan::vlan()->mac_list()->remove(&_mac_node);
|
|
||||||
_free_ipv4_node();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Session_component::set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr)
|
void Session_component::set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr)
|
||||||
{
|
{
|
||||||
_free_ipv4_node();
|
_free_ipv4_node();
|
||||||
_ipv4_node = new (this->guarded_allocator())
|
_ipv4_node = new (this->guarded_allocator())
|
||||||
Ipv4_address_node(ip_addr, this);
|
Ipv4_address_node(ip_addr, this);
|
||||||
Vlan::vlan()->ip_tree()->insert(_ipv4_node);
|
Net::Env::vlan()->ip_tree()->insert(_ipv4_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Session_component::Session_component(Genode::Allocator *allocator,
|
||||||
|
Genode::size_t amount,
|
||||||
|
Genode::size_t tx_buf_size,
|
||||||
|
Genode::size_t rx_buf_size,
|
||||||
|
Ethernet_frame::Mac_address vmac,
|
||||||
|
Genode::Rpc_entrypoint &ep,
|
||||||
|
char *ip_addr)
|
||||||
|
: Guarded_range_allocator(allocator, amount),
|
||||||
|
Tx_rx_communication_buffers(tx_buf_size, rx_buf_size),
|
||||||
|
Session_rpc_object(Tx_rx_communication_buffers::tx_ds(),
|
||||||
|
Tx_rx_communication_buffers::rx_ds(),
|
||||||
|
this->range_allocator(), ep),
|
||||||
|
_mac_node(vmac, this),
|
||||||
|
_ipv4_node(0)
|
||||||
|
{
|
||||||
|
Env::vlan()->mac_tree()->insert(&_mac_node);
|
||||||
|
Env::vlan()->mac_list()->insert(&_mac_node);
|
||||||
|
|
||||||
|
/* static ip parsing */
|
||||||
|
if (ip_addr != 0 && Genode::strlen(ip_addr)) {
|
||||||
|
Ipv4_packet::Ipv4_address ip = Ipv4_packet::ip_from_string(ip_addr);
|
||||||
|
|
||||||
|
if (ip == Ipv4_packet::Ipv4_address()) {
|
||||||
|
PWRN("Empty or error ip address. Skipped.");
|
||||||
|
} else {
|
||||||
|
set_ipv4_address(ip);
|
||||||
|
|
||||||
|
if (verbose)
|
||||||
|
PDBG("\nmac=%02x.%02x.%02x.%02x.%02x.%02x ip=%d.%d.%d.%d",
|
||||||
|
vmac.addr[0], vmac.addr[1], vmac.addr[2],
|
||||||
|
vmac.addr[3], vmac.addr[4], vmac.addr[5],
|
||||||
|
ip.addr[0], ip.addr[1], ip.addr[2], ip.addr[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_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() {
|
||||||
|
Env::vlan()->mac_tree()->remove(&_mac_node);
|
||||||
|
Env::vlan()->mac_list()->remove(&_mac_node);
|
||||||
|
_free_ipv4_node();
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ namespace Net {
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
Genode::Allocator_guard _guarded_alloc;
|
Genode::Allocator_guard _guarded_alloc;
|
||||||
Nic::Packet_allocator _range_alloc;
|
::Nic::Packet_allocator _range_alloc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -97,41 +97,15 @@ namespace Net {
|
|||||||
*/
|
*/
|
||||||
class Session_component : public Guarded_range_allocator,
|
class Session_component : public Guarded_range_allocator,
|
||||||
private Tx_rx_communication_buffers,
|
private Tx_rx_communication_buffers,
|
||||||
public Nic::Session_rpc_object
|
public ::Nic::Session_rpc_object,
|
||||||
|
public Packet_handler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
class Tx_handler : public Packet_handler
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Packet_descriptor _tx_packet;
|
|
||||||
Session_component *_component;
|
|
||||||
|
|
||||||
void acknowledge_last_one();
|
|
||||||
void next_packet(void** src, Genode::size_t *size);
|
|
||||||
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
|
|
||||||
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
|
|
||||||
void finalize_packet(Ethernet_frame *eth, Genode::size_t size);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Tx_handler(Nic::Connection *session,
|
|
||||||
Session_component *component)
|
|
||||||
: Packet_handler(session), _component(component) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Tx_handler _tx_handler;
|
|
||||||
Mac_address_node _mac_node;
|
Mac_address_node _mac_node;
|
||||||
Ipv4_address_node *_ipv4_node;
|
Ipv4_address_node *_ipv4_node;
|
||||||
Genode::Lock _rx_lock;
|
|
||||||
|
|
||||||
static const int verbose;
|
|
||||||
|
|
||||||
void _free_ipv4_node();
|
void _free_ipv4_node();
|
||||||
|
|
||||||
Ipv4_packet::Ipv4_address ip_from_string(const char *ip);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -150,25 +124,34 @@ namespace Net {
|
|||||||
Genode::size_t tx_buf_size,
|
Genode::size_t tx_buf_size,
|
||||||
Genode::size_t rx_buf_size,
|
Genode::size_t rx_buf_size,
|
||||||
Ethernet_frame::Mac_address vmac,
|
Ethernet_frame::Mac_address vmac,
|
||||||
Nic::Connection *session,
|
|
||||||
Genode::Rpc_entrypoint &ep,
|
Genode::Rpc_entrypoint &ep,
|
||||||
char *ip_addr = 0);
|
char *ip_addr = 0);
|
||||||
|
|
||||||
~Session_component();
|
~Session_component();
|
||||||
|
|
||||||
Nic::Session::Tx::Sink* tx_sink() { return _tx.sink(); }
|
::Nic::Mac_address mac_address()
|
||||||
Nic::Session::Rx::Source* rx_source() { return _rx.source(); }
|
|
||||||
Genode::Lock* rx_lock() { return &_rx_lock; }
|
|
||||||
|
|
||||||
Nic::Mac_address mac_address()
|
|
||||||
{
|
{
|
||||||
Nic::Mac_address m;
|
::Nic::Mac_address m;
|
||||||
Mac_address_node::Address mac = _mac_node.addr();
|
Mac_address_node::Address mac = _mac_node.addr();
|
||||||
Genode::memcpy(&m, mac.addr, sizeof(m.addr));
|
Genode::memcpy(&m, mac.addr, sizeof(m.addr));
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr);
|
void set_ipv4_address(Ipv4_packet::Ipv4_address ip_addr);
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
** Packet_handler interface **
|
||||||
|
******************************/
|
||||||
|
|
||||||
|
Packet_stream_sink< ::Nic::Session::Policy> * sink() {
|
||||||
|
return _tx.sink(); }
|
||||||
|
|
||||||
|
Packet_stream_source< ::Nic::Session::Policy> * source() {
|
||||||
|
return _rx.source(); }
|
||||||
|
|
||||||
|
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
|
||||||
|
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
|
||||||
|
void finalize_packet(Ethernet_frame *eth, Genode::size_t size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -182,7 +165,6 @@ namespace Net {
|
|||||||
enum { verbose = 1 };
|
enum { verbose = 1 };
|
||||||
|
|
||||||
Mac_allocator _mac_alloc;
|
Mac_allocator _mac_alloc;
|
||||||
Nic::Connection *_session;
|
|
||||||
Genode::Rpc_entrypoint &_ep;
|
Genode::Rpc_entrypoint &_ep;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -240,10 +222,8 @@ namespace Net {
|
|||||||
tx_buf_size,
|
tx_buf_size,
|
||||||
rx_buf_size,
|
rx_buf_size,
|
||||||
_mac_alloc.alloc(),
|
_mac_alloc.alloc(),
|
||||||
_session,
|
|
||||||
_ep,
|
_ep,
|
||||||
ip_addr
|
ip_addr);
|
||||||
);
|
|
||||||
} catch(Mac_allocator::Alloc_failed) {
|
} catch(Mac_allocator::Alloc_failed) {
|
||||||
PWRN("Mac address allocation failed!");
|
PWRN("Mac address allocation failed!");
|
||||||
return (Session_component*) 0;
|
return (Session_component*) 0;
|
||||||
@ -253,10 +233,9 @@ namespace Net {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
Root(Genode::Rpc_entrypoint *session_ep,
|
Root(Genode::Rpc_entrypoint *session_ep,
|
||||||
Genode::Allocator *md_alloc,
|
Genode::Allocator *md_alloc)
|
||||||
Nic::Connection *session)
|
|
||||||
: Genode::Root_component<Session_component>(session_ep, md_alloc),
|
: Genode::Root_component<Session_component>(session_ep, md_alloc),
|
||||||
_session(session), _ep(*session_ep) { }
|
_ep(*session_ep) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
} /* namespace Net */
|
} /* namespace Net */
|
||||||
|
36
os/src/server/nic_bridge/env.cc
Normal file
36
os/src/server/nic_bridge/env.cc
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* \brief Nic-bridge global environment
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2013-05-23
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 "env.h"
|
||||||
|
#include "nic.h"
|
||||||
|
#include "vlan.h"
|
||||||
|
|
||||||
|
Genode::Signal_receiver* Net::Env::receiver()
|
||||||
|
{
|
||||||
|
static Genode::Signal_receiver receiver;
|
||||||
|
return &receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Net::Vlan* Net::Env::vlan()
|
||||||
|
{
|
||||||
|
static Net::Vlan vlan;
|
||||||
|
return &vlan;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Net::Nic* Net::Env::nic()
|
||||||
|
{
|
||||||
|
static Net::Nic nic;
|
||||||
|
return &nic;
|
||||||
|
}
|
36
os/src/server/nic_bridge/env.h
Normal file
36
os/src/server/nic_bridge/env.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* \brief Proxy-ARP environment
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2013-05-24
|
||||||
|
*
|
||||||
|
* A database containing all clients sorted by IP and MAC addresses.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SRC__SERVER__NIC_BRIDGE__ENV_H_
|
||||||
|
#define _SRC__SERVER__NIC_BRIDGE__ENV_H_
|
||||||
|
|
||||||
|
#include <base/signal.h>
|
||||||
|
|
||||||
|
namespace Net {
|
||||||
|
class Vlan;
|
||||||
|
class Nic;
|
||||||
|
class Env;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Net::Env
|
||||||
|
{
|
||||||
|
static Genode::Signal_receiver* receiver();
|
||||||
|
|
||||||
|
static Vlan *vlan();
|
||||||
|
|
||||||
|
static Net::Nic *nic();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _SRC__SERVER__NIC_BRIDGE__ENV_H_ */
|
@ -13,32 +13,21 @@
|
|||||||
|
|
||||||
/* Genode */
|
/* Genode */
|
||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
#include <base/sleep.h>
|
|
||||||
#include <cap_session/connection.h>
|
#include <cap_session/connection.h>
|
||||||
#include <nic_session/connection.h>
|
#include <nic_session/connection.h>
|
||||||
#include <nic/packet_allocator.h>
|
#include <nic/packet_allocator.h>
|
||||||
#include <nic/xml_node.h>
|
#include <nic/xml_node.h>
|
||||||
#include <os/config.h>
|
#include <os/config.h>
|
||||||
|
|
||||||
#include "packet_handler.h"
|
/* local includes */
|
||||||
#include "component.h"
|
#include "component.h"
|
||||||
|
#include "env.h"
|
||||||
|
|
||||||
|
|
||||||
int main(int, char **)
|
int main(int, char **)
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
enum { STACK_SIZE = 4096 };
|
|
||||||
static Cap_connection cap;
|
|
||||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_bridge_ep");
|
|
||||||
|
|
||||||
static Nic::Packet_allocator tx_block_alloc(env()->heap());
|
|
||||||
|
|
||||||
enum {
|
|
||||||
PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
|
|
||||||
BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* read MAC address prefix from config file */
|
/* read MAC address prefix from config file */
|
||||||
try {
|
try {
|
||||||
Nic::Mac_address mac;
|
Nic::Mac_address mac;
|
||||||
@ -47,23 +36,22 @@ int main(int, char **)
|
|||||||
sizeof(Net::Mac_allocator::mac_addr_base));
|
sizeof(Net::Mac_allocator::mac_addr_base));
|
||||||
} catch(...) {}
|
} catch(...) {}
|
||||||
|
|
||||||
Root_capability nic_root_cap;
|
|
||||||
try {
|
try {
|
||||||
static Nic::Connection nic(&tx_block_alloc, BUF_SIZE, BUF_SIZE);
|
enum { STACK_SIZE = 4096 };
|
||||||
static Net::Rx_handler rx_handler(&nic);
|
static Cap_connection cap;
|
||||||
static Net::Root nic_root(&ep, env()->heap(), &nic);
|
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_bridge_ep");
|
||||||
|
static Net::Root nic_root(&ep, env()->heap());
|
||||||
/* start receiver thread handling packets from the NIC driver */
|
|
||||||
rx_handler.start();
|
|
||||||
rx_handler.wait_for_startup();
|
|
||||||
|
|
||||||
/* announce NIC service */
|
/* announce NIC service */
|
||||||
env()->parent()->announce(ep.manage(&nic_root));
|
env()->parent()->announce(ep.manage(&nic_root));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Signal s = Net::Env::receiver()->wait_for_signal();
|
||||||
|
static_cast<Signal_dispatcher_base *>(s.context())->dispatch(s.num());
|
||||||
|
}
|
||||||
} catch (Parent::Service_denied) {
|
} catch (Parent::Service_denied) {
|
||||||
PERR("Could not connect to uplink NIC");
|
PERR("Could not connect to uplink NIC");
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep_forever();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
136
os/src/server/nic_bridge/nic.cc
Normal file
136
os/src/server/nic_bridge/nic.cc
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
* \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 "address_node.h"
|
||||||
|
#include "component.h"
|
||||||
|
#include "env.h"
|
||||||
|
#include "nic.h"
|
||||||
|
#include "vlan.h"
|
||||||
|
|
||||||
|
using namespace Net;
|
||||||
|
|
||||||
|
|
||||||
|
bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
|
||||||
|
Arp_packet *arp = new (eth->data())
|
||||||
|
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 = Env::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_packet::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())
|
||||||
|
Ipv4_packet(size - sizeof(Ethernet_frame));
|
||||||
|
|
||||||
|
/* is it an UDP packet ? */
|
||||||
|
if (ip->protocol() == Udp_packet::IP_ID)
|
||||||
|
{
|
||||||
|
Udp_packet *udp = new (ip->data())
|
||||||
|
Udp_packet(size - sizeof(Ipv4_packet));
|
||||||
|
|
||||||
|
/* is it a DHCP packet ? */
|
||||||
|
if (Dhcp_packet::is_dhcp(udp)) {
|
||||||
|
Dhcp_packet *dhcp = new (udp->data())
|
||||||
|
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 =
|
||||||
|
Env::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() == Net::Env::nic()->mac()) {
|
||||||
|
Ipv4_address_node *node = Env::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()
|
||||||
|
: _tx_block_alloc(Genode::env()->heap()),
|
||||||
|
_nic(&_tx_block_alloc, BUF_SIZE, BUF_SIZE)
|
||||||
|
{
|
||||||
|
_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);
|
||||||
|
}
|
64
os/src/server/nic_bridge/nic.h
Normal file
64
os/src/server/nic_bridge/nic.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* \brief Proxy-ARP NIC session handler
|
||||||
|
* \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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SRC__SERVER__NIC_BRIDGE__NIC_H_
|
||||||
|
#define _SRC__SERVER__NIC_BRIDGE__NIC_H_
|
||||||
|
|
||||||
|
#include <nic_session/connection.h>
|
||||||
|
#include <nic/packet_allocator.h>
|
||||||
|
|
||||||
|
#include "env.h"
|
||||||
|
#include "packet_handler.h"
|
||||||
|
|
||||||
|
namespace Net {
|
||||||
|
class Nic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Net::Nic : public Net::Packet_handler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PACKET_SIZE = ::Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
|
||||||
|
BUF_SIZE = ::Nic::Session::QUEUE_SIZE * PACKET_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
::Nic::Packet_allocator _tx_block_alloc;
|
||||||
|
::Nic::Connection _nic;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Nic();
|
||||||
|
|
||||||
|
::Nic::Connection *nic() { return &_nic; }
|
||||||
|
|
||||||
|
Ethernet_frame::Mac_address mac() { return _nic.mac_address().addr; }
|
||||||
|
|
||||||
|
|
||||||
|
/******************************
|
||||||
|
** Packet_handler interface **
|
||||||
|
******************************/
|
||||||
|
|
||||||
|
Packet_stream_sink< ::Nic::Session::Policy> * sink() {
|
||||||
|
return _nic.rx(); }
|
||||||
|
|
||||||
|
Packet_stream_source< ::Nic::Session::Policy> * source() {
|
||||||
|
return _nic.tx(); }
|
||||||
|
|
||||||
|
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
|
||||||
|
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
|
||||||
|
void finalize_packet(Ethernet_frame *eth, Genode::size_t size) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _SRC__SERVER__NIC_BRIDGE__NIC_H_ */
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Thread implementations handling network packets.
|
* \brief Packet handler handling network packets.
|
||||||
* \author Stefan Kalkowski
|
* \author Stefan Kalkowski
|
||||||
* \date 2010-08-18
|
* \date 2010-08-18
|
||||||
*/
|
*/
|
||||||
@ -18,14 +18,40 @@
|
|||||||
#include <net/ipv4.h>
|
#include <net/ipv4.h>
|
||||||
#include <net/udp.h>
|
#include <net/udp.h>
|
||||||
|
|
||||||
|
#include "env.h"
|
||||||
#include "component.h"
|
#include "component.h"
|
||||||
#include "packet_handler.h"
|
#include "packet_handler.h"
|
||||||
#include "vlan.h"
|
#include "vlan.h"
|
||||||
|
|
||||||
using namespace Net;
|
using namespace Net;
|
||||||
|
|
||||||
|
static const bool verbose = true;
|
||||||
|
|
||||||
static Genode::Lock _nic_lock;
|
void Packet_handler::_ready_to_submit(unsigned)
|
||||||
|
{
|
||||||
|
/* as long as packets are available, and we can ack them */
|
||||||
|
while (sink()->packet_avail()) {
|
||||||
|
_packet = sink()->get_packet();
|
||||||
|
if (!_packet.valid()) continue;
|
||||||
|
handle_ethernet(sink()->packet_content(_packet), _packet.size());
|
||||||
|
|
||||||
|
if (!sink()->ready_to_ack()) {
|
||||||
|
if (verbose)
|
||||||
|
PWRN("ack state FULL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sink()->acknowledge_packet(_packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Packet_handler::_ready_to_ack(unsigned)
|
||||||
|
{
|
||||||
|
/* check for acknowledgements */
|
||||||
|
while (source()->ack_avail())
|
||||||
|
source()->release_packet(source()->get_acked_packet());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Packet_handler::broadcast_to_clients(Ethernet_frame *eth, Genode::size_t size)
|
void Packet_handler::broadcast_to_clients(Ethernet_frame *eth, Genode::size_t size)
|
||||||
@ -34,202 +60,66 @@ void Packet_handler::broadcast_to_clients(Ethernet_frame *eth, Genode::size_t si
|
|||||||
if (eth->dst() == Ethernet_frame::BROADCAST) {
|
if (eth->dst() == Ethernet_frame::BROADCAST) {
|
||||||
/* iterate through the list of clients */
|
/* iterate through the list of clients */
|
||||||
Mac_address_node *node =
|
Mac_address_node *node =
|
||||||
Vlan::vlan()->mac_list()->first();
|
Env::vlan()->mac_list()->first();
|
||||||
while (node) {
|
while (node) {
|
||||||
/* deliver packet */
|
/* deliver packet */
|
||||||
node->receive_packet((void*) eth, size);
|
node->component()->send(eth, size);
|
||||||
node = node->next();
|
node = node->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Packet_handler::send_to_nic(Ethernet_frame *eth, Genode::size_t size)
|
void Packet_handler::handle_ethernet(void* src, Genode::size_t size)
|
||||||
{
|
{
|
||||||
Genode::Lock::Guard lock_guard(_nic_lock);
|
try {
|
||||||
|
/* parse ethernet frame header */
|
||||||
while (true) {
|
Ethernet_frame *eth = new (src) Ethernet_frame(size);
|
||||||
/* check for acknowledgements */
|
switch (eth->type()) {
|
||||||
while (_session->tx()->ack_avail()) {
|
case Ethernet_frame::ARP:
|
||||||
Packet_descriptor p =
|
if (!handle_arp(eth, size)) return;
|
||||||
_session->tx()->get_acked_packet();
|
break;
|
||||||
_session->tx()->release_packet(p);
|
case Ethernet_frame::IPV4:
|
||||||
|
if(!handle_ip(eth, size)) return;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
broadcast_to_clients(eth, size);
|
||||||
/* set our MAC as sender */
|
finalize_packet(eth, size);
|
||||||
eth->src(_mac);
|
} catch(Arp_packet::No_arp_packet) {
|
||||||
|
PWRN("Invalid ARP packet!");
|
||||||
/* allocate packet to NIC driver */
|
} catch(Ethernet_frame::No_ethernet_frame) {
|
||||||
Packet_descriptor tx_packet = _session->tx()->alloc_packet(size);
|
PWRN("Invalid ethernet frame");
|
||||||
char *tx_content = _session->tx()->packet_content(tx_packet);
|
} catch(Dhcp_packet::No_dhcp_packet) {
|
||||||
|
PWRN("Invalid IPv4 packet!");
|
||||||
/* copy and submit packet */
|
} catch(Ipv4_packet::No_ip_packet) {
|
||||||
Genode::memcpy((void*)tx_content, (void*)eth, size);
|
PWRN("Invalid IPv4 packet!");
|
||||||
_session->tx()->submit_packet(tx_packet);
|
} catch(Udp_packet::No_udp_packet) {
|
||||||
return;
|
PWRN("Invalid UDP packet!");
|
||||||
} catch(Nic::Session::Tx::Source::Packet_alloc_failed) { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Packet_handler::entry()
|
void Packet_handler::send(Ethernet_frame *eth, Genode::size_t size)
|
||||||
{
|
{
|
||||||
void* src;
|
try {
|
||||||
Genode::size_t eth_sz;
|
/* copy and submit packet */
|
||||||
|
Packet_descriptor packet = source()->alloc_packet(size);
|
||||||
/* signal preparedness */
|
char *content = source()->packet_content(packet);
|
||||||
_startup_sem.up();
|
Genode::memcpy((void*)content, (void*)eth, size);
|
||||||
|
source()->submit_packet(packet);
|
||||||
/* loop for new packets */
|
} catch(Packet_stream_source< ::Nic::Session::Policy>::Packet_alloc_failed) {
|
||||||
while (true) {
|
if (verbose)
|
||||||
try {
|
PWRN("Packet dropped");
|
||||||
acknowledge_last_one();
|
|
||||||
next_packet(&src, ð_sz);
|
|
||||||
|
|
||||||
/* parse ethernet frame header */
|
|
||||||
Ethernet_frame *eth = new (src) Ethernet_frame(eth_sz);
|
|
||||||
switch (eth->type()) {
|
|
||||||
case Ethernet_frame::ARP:
|
|
||||||
{
|
|
||||||
if (!handle_arp(eth, eth_sz))
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Ethernet_frame::IPV4:
|
|
||||||
{
|
|
||||||
if(!handle_ip(eth, eth_sz))
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* broadcast packet ? */
|
|
||||||
broadcast_to_clients(eth, eth_sz);
|
|
||||||
|
|
||||||
finalize_packet(eth, eth_sz);
|
|
||||||
} catch(Arp_packet::No_arp_packet) {
|
|
||||||
PWRN("Invalid ARP packet!");
|
|
||||||
} catch(Ethernet_frame::No_ethernet_frame) {
|
|
||||||
PWRN("Invalid ethernet frame");
|
|
||||||
} catch(Dhcp_packet::No_dhcp_packet) {
|
|
||||||
PWRN("Invalid IPv4 packet!");
|
|
||||||
} catch(Ipv4_packet::No_ip_packet) {
|
|
||||||
PWRN("Invalid IPv4 packet!");
|
|
||||||
} catch(Udp_packet::No_udp_packet) {
|
|
||||||
PWRN("Invalid UDP packet!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Rx_handler::acknowledge_last_one() {
|
Packet_handler::Packet_handler()
|
||||||
/* acknowledge packet to NIC driver */
|
: _sink_ack(*Net::Env::receiver(), *this, &Packet_handler::_ack_avail),
|
||||||
if(_rx_packet.valid())
|
_sink_submit(*Net::Env::receiver(), *this, &Packet_handler::_ready_to_submit),
|
||||||
_session->rx()->acknowledge_packet(_rx_packet);
|
_source_ack(*Net::Env::receiver(), *this, &Packet_handler::_ready_to_ack),
|
||||||
}
|
_source_submit(*Net::Env::receiver(), *this, &Packet_handler::_packet_avail)
|
||||||
|
{ }
|
||||||
|
|
||||||
void Rx_handler::next_packet(void** src, Genode::size_t *size) {
|
|
||||||
/* get next packet from NIC driver */
|
|
||||||
_rx_packet = _session->rx()->get_packet();
|
|
||||||
*src = _session->rx()->packet_content(_rx_packet);
|
|
||||||
*size = _rx_packet.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Rx_handler::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
|
|
||||||
Arp_packet *arp = new (eth->data())
|
|
||||||
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::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_packet::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());
|
|
||||||
send_to_nic(eth, size);
|
|
||||||
} else {
|
|
||||||
/* overwrite destination MAC */
|
|
||||||
arp->dst_mac(node->component()->mac_address().addr);
|
|
||||||
eth->dst(node->component()->mac_address().addr);
|
|
||||||
node->receive_packet((void*) eth, size);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Rx_handler::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
|
|
||||||
Ipv4_packet *ip = new (eth->data())
|
|
||||||
Ipv4_packet(size - sizeof(Ethernet_frame));
|
|
||||||
|
|
||||||
/* is it an UDP packet ? */
|
|
||||||
if (ip->protocol() == Udp_packet::IP_ID)
|
|
||||||
{
|
|
||||||
Udp_packet *udp = new (ip->data())
|
|
||||||
Udp_packet(size - sizeof(Ipv4_packet));
|
|
||||||
|
|
||||||
/* is it a DHCP packet ? */
|
|
||||||
if (Dhcp_packet::is_dhcp(udp)) {
|
|
||||||
Dhcp_packet *dhcp = new (udp->data())
|
|
||||||
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::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::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->receive_packet((void*) eth, size);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Thread implementations handling network packets.
|
* \brief Signal driven NIC packet handler
|
||||||
* \author Stefan Kalkowski
|
* \author Stefan Kalkowski
|
||||||
* \date 2010-08-18
|
* \date 2010-08-18
|
||||||
*/
|
*/
|
||||||
@ -22,147 +22,111 @@
|
|||||||
#include <net/ipv4.h>
|
#include <net/ipv4.h>
|
||||||
|
|
||||||
namespace Net {
|
namespace Net {
|
||||||
|
class Packet_handler;
|
||||||
/**
|
|
||||||
* Generic thread-implementation used as base for
|
|
||||||
* global receiver thread and client's transmit-threads.
|
|
||||||
*/
|
|
||||||
class Packet_handler : public Genode::Thread<8192>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Genode::Semaphore _startup_sem; /* thread startup sync */
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Nic::Connection *_session; /* session to nic driver */
|
|
||||||
Ethernet_frame::Mac_address _mac; /* real nic's mac */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Broadcasts ethernet frame to all clients,
|
|
||||||
* as long as its really a broadcast packtet.
|
|
||||||
*
|
|
||||||
* \param eth ethernet frame to send.
|
|
||||||
* \param size ethernet frame's size.
|
|
||||||
*/
|
|
||||||
void inline broadcast_to_clients(Ethernet_frame *eth,
|
|
||||||
Genode::size_t size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send ethernet frame to NIC driver.
|
|
||||||
*
|
|
||||||
* \param eth ethernet frame to send.
|
|
||||||
* \param size ethernet frame's size.
|
|
||||||
*/
|
|
||||||
void send_to_nic(Ethernet_frame *eth, Genode::size_t size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledge the last processed packet.
|
|
||||||
*/
|
|
||||||
virtual void acknowledge_last_one() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block for the next packet to process.
|
|
||||||
*/
|
|
||||||
virtual void next_packet(void** src,
|
|
||||||
Genode::size_t *size) = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle an ARP packet
|
|
||||||
*
|
|
||||||
* \param eth ethernet frame containing the ARP packet.
|
|
||||||
* \param size ethernet frame's size.
|
|
||||||
*/
|
|
||||||
virtual bool handle_arp(Ethernet_frame *eth,
|
|
||||||
Genode::size_t size) = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle an IP packet
|
|
||||||
*
|
|
||||||
* \param eth ethernet frame containing the IP packet.
|
|
||||||
* \param size ethernet frame's size.
|
|
||||||
*/
|
|
||||||
virtual bool handle_ip(Ethernet_frame *eth,
|
|
||||||
Genode::size_t size) = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Finalize handling of ethernet frame.
|
|
||||||
*
|
|
||||||
* \param eth ethernet frame to handle.
|
|
||||||
* \param size ethernet frame's size.
|
|
||||||
*/
|
|
||||||
virtual void finalize_packet(Ethernet_frame *eth,
|
|
||||||
Genode::size_t size) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Packet_handler(Nic::Connection *session)
|
|
||||||
: _session(session), _mac(session->mac_address().addr) {}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Thread's entry code.
|
|
||||||
*/
|
|
||||||
void entry();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Block until thread is ready to execute.
|
|
||||||
*/
|
|
||||||
void wait_for_startup() { _startup_sem.down(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receiver thread handling network packets from the NIC driver
|
|
||||||
*/
|
|
||||||
class Rx_handler : public Packet_handler
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Packet_descriptor _rx_packet; /* actual processed packet */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledge the last processed packet.
|
|
||||||
*/
|
|
||||||
void acknowledge_last_one();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Block for the next packet to process.
|
|
||||||
*
|
|
||||||
* \param src buffer the network packet gets written to.
|
|
||||||
* \param size size of packet gets written to.
|
|
||||||
*/
|
|
||||||
void next_packet(void** src, Genode::size_t *size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle an ARP packet.
|
|
||||||
* If it's an ARP request for an IP of one of our client's,
|
|
||||||
* reply directly with the NIC's MAC address.
|
|
||||||
*
|
|
||||||
* \param eth ethernet frame containing the ARP packet.
|
|
||||||
* \param size ethernet frame's size.
|
|
||||||
*/
|
|
||||||
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle an IP packet.
|
|
||||||
* IP packets have to be inspected for DHCP replies.
|
|
||||||
* If an reply contains a new IP address for one of our
|
|
||||||
* client's, the client's database needs to be updated.
|
|
||||||
*
|
|
||||||
* \param eth ethernet frame containing the IP packet.
|
|
||||||
* \param size ethernet frame's size.
|
|
||||||
*/
|
|
||||||
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* \param session session to NIC driver.
|
|
||||||
*/
|
|
||||||
Rx_handler(Nic::Connection *session) : Packet_handler(session) {}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic packet handler used as base for NIC and client packet handlers.
|
||||||
|
*/
|
||||||
|
class Net::Packet_handler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Packet_descriptor _packet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* submit queue not empty anymore
|
||||||
|
*/
|
||||||
|
void _ready_to_submit(unsigned);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acknoledgement queue not full anymore
|
||||||
|
*
|
||||||
|
* TODO: by now, we assume ACK and SUBMIT queue to be equally
|
||||||
|
* dimensioned. That's why we ignore this signal by now.
|
||||||
|
*/
|
||||||
|
void _ack_avail(unsigned) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acknoledgement queue not empty anymore
|
||||||
|
*/
|
||||||
|
void _ready_to_ack(unsigned);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* submit queue not full anymore
|
||||||
|
*
|
||||||
|
* TODO: by now, we just drop packets that cannot be transferred
|
||||||
|
* to the other side, that's why we ignore this signal.
|
||||||
|
*/
|
||||||
|
void _packet_avail(unsigned) { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Genode::Signal_dispatcher<Packet_handler> _sink_ack;
|
||||||
|
Genode::Signal_dispatcher<Packet_handler> _sink_submit;
|
||||||
|
Genode::Signal_dispatcher<Packet_handler> _source_ack;
|
||||||
|
Genode::Signal_dispatcher<Packet_handler> _source_submit;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Packet_handler();
|
||||||
|
|
||||||
|
virtual Packet_stream_sink< ::Nic::Session::Policy> * sink() = 0;
|
||||||
|
virtual Packet_stream_source< ::Nic::Session::Policy> * source() = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcasts ethernet frame to all clients,
|
||||||
|
* as long as its really a broadcast packtet.
|
||||||
|
*
|
||||||
|
* \param eth ethernet frame to send.
|
||||||
|
* \param size ethernet frame's size.
|
||||||
|
*/
|
||||||
|
void inline broadcast_to_clients(Ethernet_frame *eth,
|
||||||
|
Genode::size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send ethernet frame
|
||||||
|
*
|
||||||
|
* \param eth ethernet frame to send.
|
||||||
|
* \param size ethernet frame's size.
|
||||||
|
*/
|
||||||
|
void send(Ethernet_frame *eth, Genode::size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle an ethernet packet
|
||||||
|
*
|
||||||
|
* \param src ethernet frame's address
|
||||||
|
* \param size ethernet frame's size.
|
||||||
|
*/
|
||||||
|
void handle_ethernet(void* src, Genode::size_t size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle an ARP packet
|
||||||
|
*
|
||||||
|
* \param eth ethernet frame containing the ARP packet.
|
||||||
|
* \param size ethernet frame's size.
|
||||||
|
*/
|
||||||
|
virtual bool handle_arp(Ethernet_frame *eth,
|
||||||
|
Genode::size_t size) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle an IP packet
|
||||||
|
*
|
||||||
|
* \param eth ethernet frame containing the IP packet.
|
||||||
|
* \param size ethernet frame's size.
|
||||||
|
*/
|
||||||
|
virtual bool handle_ip(Ethernet_frame *eth,
|
||||||
|
Genode::size_t size) = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finalize handling of ethernet frame.
|
||||||
|
*
|
||||||
|
* \param eth ethernet frame to handle.
|
||||||
|
* \param size ethernet frame's size.
|
||||||
|
*/
|
||||||
|
virtual void finalize_packet(Ethernet_frame *eth,
|
||||||
|
Genode::size_t size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _PACKET_HANDLER_H_ */
|
#endif /* _PACKET_HANDLER_H_ */
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
TARGET = nic_bridge
|
TARGET = nic_bridge
|
||||||
LIBS = base net
|
LIBS = base net
|
||||||
SRC_CC = address_node.cc component.cc mac.cc \
|
SRC_CC = component.cc env.cc mac.cc main.cc nic.cc packet_handler.cc
|
||||||
main.cc packet_handler.cc vlan.cc
|
|
||||||
|
|
||||||
vpath *.cc $(REP_DIR)/src/server/proxy_arp
|
vpath *.cc $(REP_DIR)/src/server/proxy_arp
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* \brief Virtual local network.
|
|
||||||
* \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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "vlan.h"
|
|
||||||
|
|
||||||
Net::Vlan* Net::Vlan::vlan()
|
|
||||||
{
|
|
||||||
static Net::Vlan vlan;
|
|
||||||
return &vlan;
|
|
||||||
}
|
|
@ -40,17 +40,14 @@ namespace Net {
|
|||||||
Mac_address_list _mac_list;
|
Mac_address_list _mac_list;
|
||||||
Ipv4_address_tree _ip_tree;
|
Ipv4_address_tree _ip_tree;
|
||||||
|
|
||||||
Vlan() {}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
Vlan() {}
|
||||||
|
|
||||||
Mac_address_tree *mac_tree() { return &_mac_tree; }
|
Mac_address_tree *mac_tree() { return &_mac_tree; }
|
||||||
Mac_address_list *mac_list() { return &_mac_list; }
|
Mac_address_list *mac_list() { return &_mac_list; }
|
||||||
Ipv4_address_tree *ip_tree() { return &_ip_tree; }
|
Ipv4_address_tree *ip_tree() { return &_ip_tree; }
|
||||||
|
|
||||||
static Vlan *vlan();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _VLAN_H_ */
|
#endif /* _VLAN_H_ */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user