mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 14:37:50 +00:00
Replace Nic driver interface by customizable component
Removed the Nic::Driver implementation. All nic servers now inherit from Nic::Session_component. Packet stream signals are dispatched to the 'handle_packet_stream' function within a session component. Thus, nic servers now have direct access to the packet stream channels, making handling more flexible. Adjusted nic_loobpack, dde_ipxe, wifi, usb, lan9118, Linux nic, and OpenVPN to the new interface. Fixes #1602
This commit is contained in:
parent
cc4febd1c2
commit
463c9bec17
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief NIC driver based on iPXE
|
||||
* \author Christian Helmuth
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2011-11-17
|
||||
*/
|
||||
|
||||
@ -17,131 +18,133 @@
|
||||
#include <base/printf.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <nic/component.h>
|
||||
#include <nic/root.h>
|
||||
#include <os/server.h>
|
||||
|
||||
#include <dde_ipxe/nic.h>
|
||||
|
||||
|
||||
namespace Ipxe {
|
||||
class Ipxe_session_component : public Nic::Session_component
|
||||
{
|
||||
public:
|
||||
|
||||
class Driver : public Nic::Driver
|
||||
{
|
||||
public:
|
||||
static Ipxe_session_component *instance;
|
||||
|
||||
static Driver *instance;
|
||||
private:
|
||||
|
||||
private:
|
||||
Nic::Mac_address _mac_addr;
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
static void _rx_callback(unsigned if_index,
|
||||
const char *packet,
|
||||
unsigned packet_len)
|
||||
{
|
||||
if (instance)
|
||||
instance->_receive(packet, packet_len);
|
||||
}
|
||||
|
||||
Nic::Mac_address _mac_addr;
|
||||
Nic::Rx_buffer_alloc &_alloc;
|
||||
Nic::Driver_notification &_notify;
|
||||
static void _link_callback()
|
||||
{
|
||||
if (instance)
|
||||
instance->_link_state_changed();
|
||||
}
|
||||
|
||||
static void _rx_callback(unsigned if_index,
|
||||
const char *packet,
|
||||
unsigned packet_len)
|
||||
{
|
||||
instance->rx_handler(packet, packet_len);
|
||||
bool _send()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!_tx.sink()->ready_to_ack())
|
||||
return false;
|
||||
|
||||
if (!_tx.sink()->packet_avail())
|
||||
return false;
|
||||
|
||||
Packet_descriptor packet = _tx.sink()->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("Invalid tx packet");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void _link_callback() { instance->link_state_changed(); }
|
||||
if (dde_ipxe_nic_tx(1, _tx.sink()->packet_content(packet), packet.size()))
|
||||
PWRN("Sending packet failed!");
|
||||
|
||||
public:
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
Driver(Server::Entrypoint &ep, Nic::Rx_buffer_alloc &alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
: _ep(ep), _alloc(alloc), _notify(notify)
|
||||
{
|
||||
PINF("--- init callbacks");
|
||||
dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback);
|
||||
void _receive(const char *packet, unsigned packet_len)
|
||||
{
|
||||
_handle_packet_stream();
|
||||
|
||||
dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr);
|
||||
PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
_mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff,
|
||||
_mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff,
|
||||
_mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff);
|
||||
if (!_rx.source()->ready_to_submit())
|
||||
return;
|
||||
|
||||
try {
|
||||
Nic::Packet_descriptor p = _rx.source()->alloc_packet(packet_len);
|
||||
Genode::memcpy(_rx.source()->packet_content(p), packet, packet_len);
|
||||
_rx.source()->submit_packet(p);
|
||||
} catch (...) {
|
||||
PDBG("failed to process received packet");
|
||||
}
|
||||
}
|
||||
|
||||
~Driver() { dde_ipxe_nic_unregister_callbacks(); }
|
||||
void _handle_packet_stream() override
|
||||
{
|
||||
while (_rx.source()->ack_avail())
|
||||
_rx.source()->release_packet(_rx.source()->get_acked_packet());
|
||||
|
||||
void rx_handler(const char *packet, unsigned packet_len)
|
||||
{
|
||||
try {
|
||||
void *buffer = _alloc.alloc(packet_len);
|
||||
Genode::memcpy(buffer, packet, packet_len);
|
||||
_alloc.submit();
|
||||
} catch (...) {
|
||||
PDBG("failed to process received packet");
|
||||
}
|
||||
}
|
||||
while (_send()) ;
|
||||
}
|
||||
|
||||
void link_state_changed() { _notify.link_state_changed(); }
|
||||
public:
|
||||
|
||||
Ipxe_session_component(Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep)
|
||||
: Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep)
|
||||
{
|
||||
instance = this;
|
||||
|
||||
PINF("--- init callbacks");
|
||||
dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback);
|
||||
|
||||
dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr);
|
||||
PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
_mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff,
|
||||
_mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff,
|
||||
_mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff);
|
||||
}
|
||||
|
||||
~Ipxe_session_component()
|
||||
{
|
||||
instance = nullptr;
|
||||
dde_ipxe_nic_unregister_callbacks();
|
||||
}
|
||||
|
||||
/**************************************
|
||||
** Nic::Session_component interface **
|
||||
**************************************/
|
||||
|
||||
Nic::Mac_address mac_address() override { return _mac_addr; }
|
||||
|
||||
bool link_state() override
|
||||
{
|
||||
return dde_ipxe_nic_link_state(1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/***************************
|
||||
** Nic::Driver interface **
|
||||
***************************/
|
||||
|
||||
Nic::Mac_address mac_address() override { return _mac_addr; }
|
||||
|
||||
bool link_state() override
|
||||
{
|
||||
return dde_ipxe_nic_link_state(1);
|
||||
}
|
||||
|
||||
void tx(char const *packet, Genode::size_t size)
|
||||
{
|
||||
if (dde_ipxe_nic_tx(1, packet, size))
|
||||
PWRN("Sending packet failed!");
|
||||
}
|
||||
|
||||
/******************************
|
||||
** Irq_activation interface **
|
||||
******************************/
|
||||
|
||||
void handle_irq(int) { /* not used */ }
|
||||
};
|
||||
|
||||
} /* namespace Ipxe */
|
||||
|
||||
|
||||
Ipxe::Driver * Ipxe::Driver::instance = 0;
|
||||
Ipxe_session_component *Ipxe_session_component::instance;
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Server::Entrypoint &ep;
|
||||
Genode::Sliced_heap sliced_heap;
|
||||
Server::Entrypoint &ep;
|
||||
|
||||
struct Factory : public Nic::Driver_factory
|
||||
{
|
||||
Server::Entrypoint &ep;
|
||||
Nic::Root<Ipxe_session_component> root {ep, *Genode::env()->heap() };
|
||||
|
||||
Factory(Server::Entrypoint &ep) : ep(ep) { }
|
||||
|
||||
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
{
|
||||
Ipxe::Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(ep, alloc, notify);
|
||||
return Ipxe::Driver::instance;
|
||||
}
|
||||
|
||||
void destroy(Nic::Driver *)
|
||||
{
|
||||
Genode::destroy(Genode::env()->heap(), Ipxe::Driver::instance);
|
||||
Ipxe::Driver::instance = 0;
|
||||
}
|
||||
} factory;
|
||||
|
||||
Nic::Root root;
|
||||
|
||||
Main(Server::Entrypoint &ep)
|
||||
:
|
||||
ep(ep),
|
||||
sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()),
|
||||
factory(ep),
|
||||
root(&ep.rpc_ep(), &sliced_heap, factory)
|
||||
Main(Server::Entrypoint &ep) : ep(ep)
|
||||
{
|
||||
PINF("--- iPXE NIC driver started ---\n");
|
||||
|
||||
|
@ -1,181 +0,0 @@
|
||||
/*
|
||||
* \brief NIC driver based on iPXE for performance measurements solely
|
||||
* \author Christian Helmuth
|
||||
* \date 2011-11-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-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 */
|
||||
#include <base/env.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/printf.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <nic/component.h>
|
||||
#include <os/server.h>
|
||||
|
||||
#include <nic/stat.h>
|
||||
#include <nic/packet_allocator.h>
|
||||
#include <nic_session/connection.h>
|
||||
|
||||
/* DDE */
|
||||
extern "C" {
|
||||
#include <dde_ipxe/nic.h>
|
||||
}
|
||||
|
||||
|
||||
namespace Ipxe {
|
||||
|
||||
class Driver : public Nic::Driver
|
||||
{
|
||||
public:
|
||||
|
||||
static Driver *instance;
|
||||
|
||||
private:
|
||||
|
||||
Nic::Mac_address _mac_addr;
|
||||
Nic::Rx_buffer_alloc &_alloc;
|
||||
Nic::Driver_notification &_notify;
|
||||
|
||||
Timer::Connection _timer;
|
||||
Nic::Measurement _stat;
|
||||
|
||||
static void _rx_callback(unsigned if_index,
|
||||
const char *packet,
|
||||
unsigned packet_len)
|
||||
{
|
||||
instance->rx_handler_stat(packet, packet_len);
|
||||
}
|
||||
|
||||
static void _link_callback() { instance->link_state_changed(); }
|
||||
|
||||
public:
|
||||
|
||||
Driver(Server::Entrypoint &ep, Nic::Rx_buffer_alloc &alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
: _alloc(alloc), _notify(notify), _stat(_timer)
|
||||
{
|
||||
PINF("--- init iPXE NIC");
|
||||
int cnt = dde_ipxe_nic_init(&ep);
|
||||
PINF(" number of devices: %d", cnt);
|
||||
|
||||
PINF("--- init callbacks");
|
||||
dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback);
|
||||
|
||||
dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr);
|
||||
PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
_mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff,
|
||||
_mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff,
|
||||
_mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff);
|
||||
|
||||
_stat.set_mac(_mac_addr.addr);
|
||||
}
|
||||
|
||||
void rx_handler_stat(const char *packet, unsigned packet_len)
|
||||
{
|
||||
Genode::addr_t test = reinterpret_cast<Genode::addr_t>(packet);
|
||||
void * buffer = reinterpret_cast<void *>(test);
|
||||
|
||||
Net::Ethernet_frame *eth =
|
||||
new (buffer) Net::Ethernet_frame(packet_len);
|
||||
_stat.data(eth, packet_len);
|
||||
}
|
||||
|
||||
void rx_handler(const char *packet, unsigned packet_len)
|
||||
{
|
||||
void *buffer = _alloc.alloc(packet_len);
|
||||
Genode::memcpy(buffer, packet, packet_len);
|
||||
|
||||
_alloc.submit();
|
||||
}
|
||||
|
||||
void link_state_changed() { _notify.link_state_changed(); }
|
||||
|
||||
|
||||
/***************************
|
||||
** Nic::Driver interface **
|
||||
***************************/
|
||||
|
||||
Nic::Mac_address mac_address() { return _mac_addr; }
|
||||
|
||||
bool link_state() override
|
||||
{
|
||||
return dde_ipxe_nic_link_state(1);
|
||||
}
|
||||
|
||||
void tx(char const *packet, Genode::size_t size)
|
||||
{
|
||||
if (dde_ipxe_nic_tx(1, packet, size))
|
||||
PWRN("Sending packet failed!");
|
||||
}
|
||||
|
||||
/******************************
|
||||
** Irq_activation interface **
|
||||
******************************/
|
||||
|
||||
void handle_irq(int) { /* not used */ }
|
||||
};
|
||||
} /* namespace Ipxe */
|
||||
|
||||
|
||||
Ipxe::Driver * Ipxe::Driver::instance = 0;
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Server::Entrypoint &ep;
|
||||
Genode::Sliced_heap sliced_heap;
|
||||
|
||||
struct Factory : public Nic::Driver_factory
|
||||
{
|
||||
Server::Entrypoint &ep;
|
||||
|
||||
Factory(Server::Entrypoint &ep) : ep(ep) { }
|
||||
|
||||
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
{
|
||||
Ipxe::Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(ep, alloc, notify);
|
||||
return Ipxe::Driver::instance;
|
||||
}
|
||||
|
||||
void destroy(Nic::Driver *)
|
||||
{
|
||||
Genode::destroy(Genode::env()->heap(), Ipxe::Driver::instance);
|
||||
Ipxe::Driver::instance = 0;
|
||||
}
|
||||
} factory;
|
||||
|
||||
Nic::Root root;
|
||||
|
||||
Main(Server::Entrypoint &ep)
|
||||
:
|
||||
ep(ep),
|
||||
sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()),
|
||||
factory(ep),
|
||||
root(&ep.rpc_ep(), &sliced_heap, factory)
|
||||
{
|
||||
PINF("--- iPXE NIC driver started ---\n");
|
||||
Genode::env()->parent()->announce(ep.manage(root));
|
||||
|
||||
root.session("ram_quota=155648, tx_buf_size=65536, rx_buf_size=65536",
|
||||
Genode::Affinity());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/************
|
||||
** Server **
|
||||
************/
|
||||
|
||||
namespace Server {
|
||||
char const *name() { return "nic_drv_stat_ep"; }
|
||||
size_t stack_size() { return 2*1024*sizeof(long); }
|
||||
void construct(Entrypoint &ep) { static Main server(ep); }
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
TARGET = nic_drv_stat
|
||||
LIBS = base server dde_ipxe_nic net-stat
|
||||
SRC_CC = main.cc
|
@ -1,327 +0,0 @@
|
||||
/*
|
||||
* \brief Block-session implementation for network devices
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-07-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-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 _NIC__COMPONENT_H_
|
||||
#define _NIC__COMPONENT_H_
|
||||
|
||||
#include <root/component.h>
|
||||
#include <nic/packet_allocator.h>
|
||||
#include <nic_session/rpc_object.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <signal/dispatch.h>
|
||||
|
||||
#define BENCH 0
|
||||
|
||||
namespace Nic {
|
||||
|
||||
using namespace Genode;
|
||||
class Session_component;
|
||||
|
||||
#if BENCH
|
||||
struct Counter : public Genode::Thread<8192>
|
||||
{
|
||||
char const *prefix;
|
||||
int cnt;
|
||||
int burst;
|
||||
size_t size;
|
||||
|
||||
void entry()
|
||||
{
|
||||
Timer::Connection _timer;
|
||||
int interval = 5;
|
||||
while(1) {
|
||||
_timer.msleep(interval * 1000);
|
||||
PDBG("%s: Packets %d/s (in %d burst packets) bytes/s: %d",
|
||||
prefix, cnt / interval, burst / interval, size / interval);
|
||||
cnt = 0;
|
||||
size = 0;
|
||||
burst = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void inc(size_t s) { cnt++; size += s; }
|
||||
void inc_burst() { burst++; }
|
||||
|
||||
Counter(char const *prefix)
|
||||
: Thread("counter"), prefix(prefix), cnt(0), burst(0), size(0)
|
||||
{ start(); }
|
||||
};
|
||||
#else
|
||||
struct Counter
|
||||
{
|
||||
Counter(char const *) { };
|
||||
void inc(size_t) { }
|
||||
void inc_burst() { }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct Device : ::Device
|
||||
{
|
||||
Session_component *_session;
|
||||
|
||||
/**
|
||||
* Transmit data to driver
|
||||
*/
|
||||
virtual bool tx(addr_t virt, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Return mac address of device
|
||||
*/
|
||||
virtual Mac_address mac_address() = 0;
|
||||
|
||||
/**
|
||||
* Return current link-state (true if link detected)
|
||||
*/
|
||||
virtual bool link_state() = 0;
|
||||
|
||||
/**
|
||||
* Set session belonging to this driver
|
||||
*/
|
||||
void session(Session_component *s) { _session = s; }
|
||||
|
||||
/**
|
||||
* Check for session
|
||||
*/
|
||||
bool session() { return _session != 0; }
|
||||
|
||||
/**
|
||||
* Alloc an SKB
|
||||
*/
|
||||
virtual sk_buff *alloc_skb() = 0;
|
||||
|
||||
/**
|
||||
* Submit SKB to device
|
||||
*/
|
||||
virtual void tx_skb(sk_buff *skb) = 0;
|
||||
|
||||
/**
|
||||
* Setup SKB with 'data' of 'size', return 'false' if SKB is longer than
|
||||
* 'end'.
|
||||
*/
|
||||
virtual bool skb_fill(struct sk_buff *skb, unsigned char *data, Genode::size_t size, unsigned char *end) = 0;
|
||||
|
||||
/**
|
||||
* Call driver fixup function on SKB
|
||||
*/
|
||||
virtual void tx_fixup(struct sk_buff *skb) = 0;
|
||||
|
||||
/**
|
||||
* Return true if device supports burst operations
|
||||
*/
|
||||
virtual bool burst() = 0;
|
||||
|
||||
Device() : _session(0) { }
|
||||
};
|
||||
|
||||
|
||||
class Session_component : public Nic::Packet_allocator,
|
||||
public Packet_session_component<Session_rpc_object>
|
||||
{
|
||||
private:
|
||||
|
||||
Device *_device; /* device this session is using */
|
||||
Tx::Sink *_tx_sink; /* client packet sink */
|
||||
bool _tx_alloc; /* get next packet from client or use _tx_packet */
|
||||
Packet_descriptor _tx_packet; /* saved packet in case of driver errors */
|
||||
|
||||
Signal_context_capability _link_state_sigh;
|
||||
|
||||
void _send_packet_avail_signal() {
|
||||
Signal_transmitter(_tx.sigh_packet_avail()).submit(); }
|
||||
|
||||
protected:
|
||||
|
||||
void _process_packets(unsigned)
|
||||
{
|
||||
static sk_buff work_skb; /* dummy skb for fixup calls */
|
||||
static Counter counter("TX");
|
||||
|
||||
int tx_cnt = 0;
|
||||
unsigned size = 0;
|
||||
sk_buff *skb = 0;
|
||||
unsigned char *ptr = 0;
|
||||
|
||||
/* submit received packets to lower layer */
|
||||
while (_tx_sink->packet_avail())
|
||||
{
|
||||
Packet_descriptor packet = _tx_alloc ? _tx_sink->get_packet() : _tx_packet;
|
||||
addr_t virt = (addr_t)_tx_sink->packet_content(packet);
|
||||
|
||||
if (_device->burst()) {
|
||||
if (!ptr || !_device->skb_fill(&work_skb, ptr, packet.size(), skb->end)) {
|
||||
|
||||
/* submit batch to device */
|
||||
if (ptr) {
|
||||
_device->tx_skb(skb);
|
||||
tx_cnt++;
|
||||
counter.inc_burst();
|
||||
}
|
||||
|
||||
/* alloc new SKB */
|
||||
skb = _device->alloc_skb();
|
||||
|
||||
if (!skb) {
|
||||
_send_packet_avail_signal();
|
||||
_tx_alloc = false;
|
||||
_tx_packet = packet;
|
||||
return;
|
||||
}
|
||||
|
||||
_tx_alloc = true;
|
||||
|
||||
ptr = skb->data;
|
||||
work_skb.data = 0;
|
||||
_device->skb_fill(&work_skb, ptr, packet.size(), skb->end);
|
||||
}
|
||||
|
||||
/* copy packet to current data pos */
|
||||
Genode::memcpy(work_skb.data, (void *)virt, packet.size());
|
||||
/* call fixup on dummy SKB */
|
||||
_device->tx_fixup(&work_skb);
|
||||
/* advance to next slot */
|
||||
ptr = work_skb.end;
|
||||
skb->len += work_skb.truesize;
|
||||
} else {
|
||||
|
||||
/* send to driver */
|
||||
if (!(_device->tx(virt, packet.size()))) {
|
||||
_send_packet_avail_signal();
|
||||
_tx_alloc = false;
|
||||
_tx_packet = packet;
|
||||
return;
|
||||
}
|
||||
|
||||
_tx_alloc = true;
|
||||
|
||||
tx_cnt++;
|
||||
}
|
||||
|
||||
counter.inc(packet.size());
|
||||
|
||||
/* acknowledge to client */
|
||||
_tx_sink->acknowledge_packet(packet);
|
||||
|
||||
/* it's cooperative scheduling - be nice */
|
||||
if (tx_cnt == 20)
|
||||
break;
|
||||
}
|
||||
|
||||
/* sumbit last skb */
|
||||
if (skb) {
|
||||
_device->tx_skb(skb);
|
||||
counter.inc_burst();
|
||||
}
|
||||
|
||||
/* for large TCP/s check RX immediately */
|
||||
Irq::check_irq();
|
||||
|
||||
/* release acknowledged packets */
|
||||
_rx_ack(false);
|
||||
|
||||
if (_tx_sink->packet_avail())
|
||||
_send_packet_avail_signal();
|
||||
}
|
||||
|
||||
void _rx_ack(bool block = true)
|
||||
{
|
||||
while (_rx.source()->ack_avail() || block)
|
||||
{
|
||||
|
||||
Packet_descriptor packet = _rx.source()->get_acked_packet();
|
||||
|
||||
/* free packet buffer */
|
||||
_rx.source()->release_packet(packet);
|
||||
block = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Dataspace_capability tx_ds,
|
||||
Dataspace_capability rx_ds,
|
||||
Server::Entrypoint &ep,
|
||||
::Device *device)
|
||||
:
|
||||
Nic::Packet_allocator(Genode::env()->heap()),
|
||||
Packet_session_component(tx_ds, rx_ds, this, ep),
|
||||
_device(static_cast<Device *>(device)),
|
||||
_tx_sink(Session_rpc_object::_tx.sink()),
|
||||
_tx_alloc(true)
|
||||
{ _device->session(this); }
|
||||
|
||||
/**
|
||||
* Link state changed (called from driver)
|
||||
*/
|
||||
void link_state_changed()
|
||||
{
|
||||
if (_link_state_sigh.valid())
|
||||
Genode::Signal_transmitter(_link_state_sigh).submit();
|
||||
}
|
||||
|
||||
Mac_address mac_address() { return _device->mac_address(); }
|
||||
|
||||
bool link_state() override {
|
||||
return _device->link_state(); }
|
||||
|
||||
void link_state_sigh(Genode::Signal_context_capability sigh) {
|
||||
_link_state_sigh = sigh; }
|
||||
|
||||
/**
|
||||
* Send packet to client (called form driver)
|
||||
*/
|
||||
void rx(addr_t virt, size_t size)
|
||||
{
|
||||
static Counter counter("RX");
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
Packet_descriptor p =_rx.source()->alloc_packet(size);
|
||||
Genode::memcpy(_rx.source()->packet_content(p), (void*)virt, size);
|
||||
_rx.source()->submit_packet(p);
|
||||
counter.inc(size);
|
||||
} catch (...) {
|
||||
/* ack or block */
|
||||
_rx_ack();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_rx_ack(false);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Shortcut for single-client root component
|
||||
*/
|
||||
typedef Root_component<Session_component, Single_client> Root_component;
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
class Root : public Packet_root<Root_component, Session_component, CACHED>
|
||||
{
|
||||
public:
|
||||
|
||||
Root(Server::Entrypoint &ep, Allocator *md_alloc,
|
||||
Device *device)
|
||||
: Packet_root(ep, md_alloc, device) { }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NIC__COMPONENT_H_ */
|
@ -1,133 +0,0 @@
|
||||
/**
|
||||
* \brief Packet-stream-session components
|
||||
* \author Sebastian Sumpf
|
||||
* \author Norman Feske
|
||||
* \date 2012-07-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-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 _SIGNAL__DISPATCHER_H_
|
||||
#define _SIGNAL__DISPATCHER_H_
|
||||
|
||||
#include "signal.h"
|
||||
|
||||
#include "platform/lx_mem.h"
|
||||
|
||||
/**
|
||||
* Session components that overrides signal handlers
|
||||
*/
|
||||
template <typename RPC>
|
||||
class Packet_session_component : public RPC
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Signal_rpc_member<Packet_session_component> _dispatcher;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void _process_packets(unsigned) = 0;
|
||||
|
||||
public:
|
||||
|
||||
Packet_session_component(Genode::Dataspace_capability tx_ds,
|
||||
Server::Entrypoint &ep)
|
||||
: RPC(tx_ds, ep.rpc_ep()),
|
||||
_dispatcher(ep, *this, &Packet_session_component::_process_packets)
|
||||
{
|
||||
/*
|
||||
* Register '_process_packets' dispatch function as signal
|
||||
* handler for packet-avail and ready-to-ack signals.
|
||||
*/
|
||||
RPC::_tx.sigh_packet_avail(_dispatcher);
|
||||
RPC::_tx.sigh_ready_to_ack(_dispatcher);
|
||||
}
|
||||
|
||||
Packet_session_component(Genode::Dataspace_capability tx_ds,
|
||||
Genode::Dataspace_capability rx_ds,
|
||||
Genode::Range_allocator *rx_buffer_alloc,
|
||||
Server::Entrypoint &ep)
|
||||
: RPC(tx_ds, rx_ds, rx_buffer_alloc, ep.rpc_ep()),
|
||||
_dispatcher(ep, *this, &Packet_session_component::_process_packets)
|
||||
{
|
||||
/*
|
||||
* Register '_process_packets' dispatch function as signal
|
||||
* handler for packet-avail and ready-to-ack signals.
|
||||
*/
|
||||
RPC::_tx.sigh_packet_avail(_dispatcher);
|
||||
RPC::_tx.sigh_ready_to_ack(_dispatcher);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Abstract device
|
||||
*/
|
||||
struct Device { };
|
||||
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
template <typename ROOT_COMPONENT, typename SESSION_COMPONENT,
|
||||
Genode::Cache_attribute CACHEABILITY>
|
||||
class Packet_root : public ROOT_COMPONENT
|
||||
{
|
||||
private:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
Device *_device;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Always returns the singleton block-session component
|
||||
*/
|
||||
SESSION_COMPONENT *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
size_t ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size =
|
||||
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
size_t rx_buf_size =
|
||||
Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
/* delete ram quota by the memory needed for the session */
|
||||
size_t session_size = max((size_t)4096,
|
||||
sizeof(SESSION_COMPONENT)
|
||||
+ sizeof(Allocator_avl));
|
||||
if (ram_quota < session_size)
|
||||
throw Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both communication
|
||||
* buffers. Also check both sizes separately to handle a
|
||||
* possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + session_size);
|
||||
throw Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return new (ROOT_COMPONENT::md_alloc())
|
||||
SESSION_COMPONENT(Backend_memory::alloc(tx_buf_size, CACHEABILITY),
|
||||
Backend_memory::alloc(rx_buf_size, CACHEABILITY),
|
||||
_ep, _device);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Packet_root(Server::Entrypoint &ep, Genode::Allocator *md_alloc,
|
||||
Device *device)
|
||||
: ROOT_COMPONENT(&ep.rpc_ep(), md_alloc),
|
||||
_ep(ep), _device(device) { }
|
||||
};
|
||||
|
||||
#endif /* _SIGNAL__DISPATCHER_H_ */
|
272
repos/dde_linux/src/lib/usb/include/usb_nic_component.h
Normal file
272
repos/dde_linux/src/lib/usb/include/usb_nic_component.h
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* \brief Block-session implementation for network devices
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-07-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-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 _USB_NIC_COMPONENT_H_
|
||||
#define _USB_NIC_COMPONENT_H_
|
||||
|
||||
#include <nic/component.h>
|
||||
#include <root/component.h>
|
||||
|
||||
namespace Usb_nic {
|
||||
using namespace Genode;
|
||||
class Session_component;
|
||||
struct Device;
|
||||
};
|
||||
|
||||
|
||||
struct Usb_nic::Device
|
||||
{
|
||||
Session_component *_session;
|
||||
|
||||
/**
|
||||
* Transmit data to driver
|
||||
*/
|
||||
virtual bool tx(addr_t virt, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Return mac address of device
|
||||
*/
|
||||
virtual Nic::Mac_address mac_address() = 0;
|
||||
|
||||
/**
|
||||
* Return current link-state (true if link detected)
|
||||
*/
|
||||
virtual bool link_state() = 0;
|
||||
|
||||
/**
|
||||
* Set session belonging to this driver
|
||||
*/
|
||||
void session(Session_component *s) { _session = s; }
|
||||
|
||||
/**
|
||||
* Check for session
|
||||
*/
|
||||
bool session() { return _session != 0; }
|
||||
|
||||
/**
|
||||
* Alloc an SKB
|
||||
*/
|
||||
virtual sk_buff *alloc_skb() = 0;
|
||||
|
||||
/**
|
||||
* Submit SKB to device
|
||||
*/
|
||||
virtual void tx_skb(sk_buff *skb) = 0;
|
||||
|
||||
/**
|
||||
* Setup SKB with 'data' of 'size', return 'false' if SKB is longer than
|
||||
* 'end'.
|
||||
*/
|
||||
virtual bool skb_fill(struct sk_buff *skb, unsigned char *data, Genode::size_t size, unsigned char *end) = 0;
|
||||
|
||||
/**
|
||||
* Call driver fixup function on SKB
|
||||
*/
|
||||
virtual void tx_fixup(struct sk_buff *skb) = 0;
|
||||
|
||||
/**
|
||||
* Return true if device supports burst operations
|
||||
*/
|
||||
virtual bool burst() = 0;
|
||||
|
||||
Device() : _session(0) { }
|
||||
};
|
||||
|
||||
|
||||
class Usb_nic::Session_component : public Nic::Session_component
|
||||
{
|
||||
private:
|
||||
|
||||
Device *_device; /* device this session is using */
|
||||
|
||||
protected:
|
||||
|
||||
void _send_burst()
|
||||
{
|
||||
static sk_buff work_skb; /* dummy skb for fixup calls */
|
||||
static Packet_descriptor save;
|
||||
|
||||
sk_buff *skb = nullptr;
|
||||
unsigned char *ptr = nullptr;
|
||||
|
||||
/* submit received packets to lower layer */
|
||||
while (((_tx.sink()->packet_avail() || save.valid()) && _tx.sink()->ready_to_ack()))
|
||||
{
|
||||
/* alloc skb */
|
||||
if (!skb) {
|
||||
if (!(skb = _device->alloc_skb()))
|
||||
return;
|
||||
|
||||
ptr = skb->data;
|
||||
work_skb.data = nullptr;
|
||||
}
|
||||
|
||||
Packet_descriptor packet = save.valid() ? save : _tx.sink()->get_packet();
|
||||
save = Packet_descriptor();
|
||||
|
||||
if (!_device->skb_fill(&work_skb, ptr, packet.size(), skb->end)) {
|
||||
/* submit batch */
|
||||
_device->tx_skb(skb);
|
||||
skb = nullptr;
|
||||
save = packet;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy packet to current data pos */
|
||||
Genode::memcpy(work_skb.data, _tx.sink()->packet_content(packet), packet.size());
|
||||
/* call fixup on dummy SKB */
|
||||
_device->tx_fixup(&work_skb);
|
||||
/* advance to next slot */
|
||||
ptr = work_skb.end;
|
||||
skb->len += work_skb.truesize;
|
||||
/* acknowledge to client */
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
}
|
||||
|
||||
/* submit last skb */
|
||||
if (skb)
|
||||
_device->tx_skb(skb);
|
||||
}
|
||||
|
||||
bool _send()
|
||||
{
|
||||
if (!_tx.sink()->ready_to_ack())
|
||||
return false;
|
||||
|
||||
if (!_tx.sink()->packet_avail())
|
||||
return false;
|
||||
|
||||
Genode::Packet_descriptor packet = _tx.sink()->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("Invalid tx packet");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ret = _device->tx((addr_t)_tx.sink()->packet_content(packet), packet.size());
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void _handle_packet_stream() override
|
||||
{
|
||||
while (_rx.source()->ack_avail())
|
||||
_rx.source()->release_packet(_rx.source()->get_acked_packet());
|
||||
|
||||
if (_device->burst())
|
||||
_send_burst();
|
||||
else
|
||||
while (_send());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep,
|
||||
Device *device)
|
||||
: Nic::Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep),
|
||||
_device(device)
|
||||
{ _device->session(this); }
|
||||
|
||||
|
||||
Nic::Mac_address mac_address() override { return _device->mac_address(); }
|
||||
bool link_state() override { return _device->link_state(); }
|
||||
void link_state_changed() { _link_state_changed(); }
|
||||
|
||||
/**
|
||||
* Send packet to client (called from driver)
|
||||
*/
|
||||
void rx(addr_t virt, size_t size)
|
||||
{
|
||||
_handle_packet_stream();
|
||||
|
||||
if (!_rx.source()->ready_to_submit())
|
||||
return;
|
||||
|
||||
try {
|
||||
Packet_descriptor p =_rx.source()->alloc_packet(size);
|
||||
Genode::memcpy(_rx.source()->packet_content(p), (void*)virt, size);
|
||||
_rx.source()->submit_packet(p);
|
||||
} catch (...) {
|
||||
/* drop */
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Shortcut for single-client root component
|
||||
*/
|
||||
typedef Genode::Root_component<Usb_nic::Session_component, Genode::Single_client> Root_component;
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
class Root : public Root_component
|
||||
{
|
||||
private:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
Usb_nic::Device *_device;
|
||||
|
||||
protected:
|
||||
|
||||
Usb_nic::Session_component *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
/* deplete ram quota by the memory needed for the session structure */
|
||||
size_t session_size = max(4096UL, (unsigned long)sizeof(Usb_nic::Session_component));
|
||||
if (ram_quota < session_size)
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both communication
|
||||
* buffers. Also check both sizes separately to handle a
|
||||
* possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size
|
||||
|| rx_buf_size > ram_quota - session_size
|
||||
|| tx_buf_size + rx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + rx_buf_size + session_size);
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return new (Root::md_alloc())
|
||||
Usb_nic::Session_component(tx_buf_size, rx_buf_size,
|
||||
*env()->heap(),
|
||||
*env()->ram_session(),
|
||||
_ep, _device);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc,
|
||||
Usb_nic::Device *device)
|
||||
: Root_component(&ep.rpc_ep(), &md_alloc),
|
||||
_ep(ep), _device(device)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _USB_NIC_COMPONENT_H_ */
|
@ -25,7 +25,7 @@
|
||||
#include <linux/usb/usbnet.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
#include <nic/component.h>
|
||||
#include <usb_nic_component.h>
|
||||
#include "signal.h"
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ typedef struct sk_buff* (*fixup_t)(struct usbnet *, struct sk_buff *, gfp_t);
|
||||
/**
|
||||
* Net_device to session glue code
|
||||
*/
|
||||
class Nic_device : public Nic::Device
|
||||
class Nic_device : public Usb_nic::Device
|
||||
{
|
||||
public:
|
||||
|
||||
@ -320,7 +320,7 @@ int register_netdev(struct net_device *ndev)
|
||||
|
||||
/* XXX: move to 'main' */
|
||||
if (!announce) {
|
||||
static Nic::Root root(_signal->ep(), env()->heap(), nic);
|
||||
static ::Root root(_signal->ep(), *env()->heap(), nic);
|
||||
|
||||
announce = true;
|
||||
|
||||
@ -333,10 +333,6 @@ int register_netdev(struct net_device *ndev)
|
||||
if (ndev->netdev_ops->ndo_set_rx_mode)
|
||||
ndev->netdev_ops->ndo_set_rx_mode(ndev);
|
||||
|
||||
/*
|
||||
if(ndev->netdev_ops->ndo_change_mtu)
|
||||
ndev->netdev_ops->ndo_change_mtu(ndev, 4000);
|
||||
*/
|
||||
_nic = nic;
|
||||
env()->parent()->announce(_signal->ep().rpc_ep().manage(&root));
|
||||
}
|
||||
|
@ -1,214 +0,0 @@
|
||||
/*
|
||||
* \brief Nic-session implementation for network devices
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-07-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-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 _NIC__COMPONENT_H_
|
||||
#define _NIC__COMPONENT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <nic/packet_allocator.h>
|
||||
#include <nic_session/rpc_object.h>
|
||||
#include <root/component.h>
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <nic/dispatch.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
# include <linux/skbuff.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
|
||||
namespace Nic {
|
||||
|
||||
using namespace Genode; /* FIXME */
|
||||
|
||||
struct Session_component;
|
||||
struct Device;
|
||||
|
||||
typedef Genode::Root_component<Session_component, Single_client> Root_component;
|
||||
|
||||
struct Root;
|
||||
}
|
||||
|
||||
|
||||
struct Nic::Device
|
||||
{
|
||||
/**
|
||||
* Transmit data to driver
|
||||
*/
|
||||
virtual bool tx(addr_t virt, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Return mac address of device
|
||||
*/
|
||||
virtual Mac_address mac_address() = 0;
|
||||
|
||||
/**
|
||||
* Return link state (true if link detected)
|
||||
*/
|
||||
virtual bool link_state() = 0;
|
||||
|
||||
/**
|
||||
* Set session belonging to this driver
|
||||
*/
|
||||
virtual void session(Session_component *s) = 0;
|
||||
|
||||
Device() { }
|
||||
virtual ~Device() { }
|
||||
};
|
||||
|
||||
|
||||
class Nic::Session_component : public Nic::Packet_allocator,
|
||||
public Packet_session_component<Session_rpc_object>
|
||||
{
|
||||
private:
|
||||
|
||||
Device &_device; /* device this session is using */
|
||||
Tx::Sink *_tx_sink; /* client packet sink */
|
||||
bool _tx_alloc; /* get next packet from client or use _tx_packet */
|
||||
Packet_descriptor _tx_packet; /* saved packet in case of driver errors */
|
||||
|
||||
Signal_context_capability _link_state_sigh;
|
||||
|
||||
void _send_packet_avail_signal() {
|
||||
Signal_transmitter(_tx.sigh_packet_avail()).submit(); }
|
||||
|
||||
protected:
|
||||
|
||||
void _process_packets(unsigned)
|
||||
{
|
||||
int tx_cnt = 0;
|
||||
|
||||
/* submit received packets to lower layer */
|
||||
while (_tx_sink->packet_avail()) {
|
||||
Packet_descriptor packet = _tx_alloc ? _tx_sink->get_packet() : _tx_packet;
|
||||
addr_t virt = (addr_t)_tx_sink->packet_content(packet);
|
||||
|
||||
/* send to driver */
|
||||
if (!(_device.tx(virt, packet.size()))) {
|
||||
_send_packet_avail_signal();
|
||||
_tx_alloc = false;
|
||||
_tx_packet = packet;
|
||||
return;
|
||||
}
|
||||
|
||||
_tx_alloc = true;
|
||||
tx_cnt++;
|
||||
|
||||
/* acknowledge to client */
|
||||
_tx_sink->acknowledge_packet(packet);
|
||||
}
|
||||
|
||||
/* release acknowledged packets */
|
||||
_rx_ack(false);
|
||||
|
||||
if (_tx_sink->packet_avail())
|
||||
_send_packet_avail_signal();
|
||||
}
|
||||
|
||||
void _rx_ack(bool block = true)
|
||||
{
|
||||
while (_rx.source()->ack_avail() || block) {
|
||||
Packet_descriptor packet = _rx.source()->get_acked_packet();
|
||||
|
||||
/* free packet buffer */
|
||||
_rx.source()->release_packet(packet);
|
||||
block = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Dataspace_capability tx_ds,
|
||||
Dataspace_capability rx_ds,
|
||||
Server::Entrypoint &ep,
|
||||
Device &device)
|
||||
:
|
||||
Nic::Packet_allocator(Genode::env()->heap()),
|
||||
Packet_session_component(tx_ds, rx_ds, this, ep),
|
||||
_device(device),
|
||||
_tx_sink(Session_rpc_object::_tx.sink()),
|
||||
_tx_alloc(true)
|
||||
{ _device.session(this); }
|
||||
|
||||
/**
|
||||
* Send packet to client (called from driver)
|
||||
*/
|
||||
void rx(addr_t packet, size_t psize, addr_t frag, size_t fsize)
|
||||
{
|
||||
size_t size = psize + fsize;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
Packet_descriptor p =_rx.source()->alloc_packet(size);
|
||||
|
||||
Genode::memcpy(_rx.source()->packet_content(p), (void*)packet, psize);
|
||||
|
||||
if (fsize)
|
||||
Genode::memcpy(_rx.source()->packet_content(p)+psize, (void*)frag, fsize);
|
||||
|
||||
_rx.source()->submit_packet(p);
|
||||
} catch (...) {
|
||||
/* ack or block */
|
||||
_rx_ack();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_rx_ack(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Link state changed (called from driver)
|
||||
*/
|
||||
void link_state_changed()
|
||||
{
|
||||
if (_link_state_sigh.valid())
|
||||
Genode::Signal_transmitter(_link_state_sigh).submit();
|
||||
}
|
||||
|
||||
/***************************
|
||||
** Nic-session interface **
|
||||
***************************/
|
||||
|
||||
Mac_address mac_address() override
|
||||
{
|
||||
return _device.mac_address();
|
||||
}
|
||||
|
||||
bool link_state() // override
|
||||
{
|
||||
return _device.link_state();
|
||||
}
|
||||
|
||||
void link_state_sigh(Genode::Signal_context_capability sigh)
|
||||
{
|
||||
_link_state_sigh = sigh;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
struct Nic::Root : Packet_root<Root_component, Session_component, Device, CACHED>
|
||||
{
|
||||
Root(Server::Entrypoint &ep, Allocator *md_alloc, Device &device)
|
||||
: Packet_root(ep, md_alloc, device) { }
|
||||
};
|
||||
|
||||
#endif /* _NIC__COMPONENT_H_ */
|
@ -1,143 +0,0 @@
|
||||
/**
|
||||
* \brief Packet-stream-session components
|
||||
* \author Sebastian Sumpf
|
||||
* \author Norman Feske
|
||||
* \date 2012-07-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-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 _SIGNAL__DISPATCHER_H_
|
||||
#define _SIGNAL__DISPATCHER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/signal.h>
|
||||
|
||||
/* local includes */
|
||||
#include <lx.h>
|
||||
|
||||
|
||||
/**
|
||||
* Session components that overrides signal handlers
|
||||
*/
|
||||
template <typename SESSION_RPC_OBJECT>
|
||||
class Packet_session_component : public SESSION_RPC_OBJECT
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Signal_rpc_member<Packet_session_component> _tx_ready_to_ack_dispatcher;
|
||||
Genode::Signal_rpc_member<Packet_session_component> _tx_packet_avail_dispatcher;
|
||||
Genode::Signal_rpc_member<Packet_session_component> _rx_ack_avail_dispatcher;
|
||||
Genode::Signal_rpc_member<Packet_session_component> _rx_ready_to_submit_dispatcher;
|
||||
|
||||
void _tx_ready_to_ack(unsigned)
|
||||
{
|
||||
_process_packets(0);
|
||||
}
|
||||
|
||||
void _tx_packet_avail(unsigned)
|
||||
{
|
||||
_process_packets(0);
|
||||
}
|
||||
|
||||
void _rx_ack_avail(unsigned)
|
||||
{
|
||||
_process_packets(0);
|
||||
}
|
||||
|
||||
void _rx_ready_to_submit(unsigned)
|
||||
{
|
||||
_process_packets(0);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void _process_packets(unsigned) = 0;
|
||||
|
||||
public:
|
||||
|
||||
Packet_session_component(Genode::Dataspace_capability tx_ds,
|
||||
Genode::Dataspace_capability rx_ds,
|
||||
Genode::Range_allocator *rx_buffer_alloc,
|
||||
Server::Entrypoint &ep)
|
||||
:
|
||||
SESSION_RPC_OBJECT(tx_ds, rx_ds, rx_buffer_alloc, ep.rpc_ep()),
|
||||
_tx_ready_to_ack_dispatcher(ep, *this, &Packet_session_component::_tx_ready_to_ack),
|
||||
_tx_packet_avail_dispatcher(ep, *this, &Packet_session_component::_tx_packet_avail),
|
||||
_rx_ack_avail_dispatcher(ep, *this, &Packet_session_component::_rx_ack_avail),
|
||||
_rx_ready_to_submit_dispatcher(ep, *this, &Packet_session_component::_rx_ready_to_submit)
|
||||
{
|
||||
SESSION_RPC_OBJECT::_tx.sigh_ready_to_ack(_tx_ready_to_ack_dispatcher);
|
||||
SESSION_RPC_OBJECT::_tx.sigh_packet_avail(_tx_packet_avail_dispatcher);
|
||||
SESSION_RPC_OBJECT::_rx.sigh_ack_avail(_rx_ack_avail_dispatcher);
|
||||
SESSION_RPC_OBJECT::_rx.sigh_ready_to_submit(_rx_ready_to_submit_dispatcher);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
template <typename ROOT_COMPONENT,
|
||||
typename SESSION_COMPONENT,
|
||||
typename DEVICE,
|
||||
Genode::Cache_attribute CACHEABILITY>
|
||||
class Packet_root : public ROOT_COMPONENT
|
||||
{
|
||||
private:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
DEVICE &_device;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Always returns the singleton block-session component
|
||||
*/
|
||||
SESSION_COMPONENT *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
size_t ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size =
|
||||
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
size_t rx_buf_size =
|
||||
Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
/* delete ram quota by the memory needed for the session */
|
||||
size_t session_size = max((size_t)4096,
|
||||
sizeof(SESSION_COMPONENT)
|
||||
+ sizeof(Allocator_avl));
|
||||
if (ram_quota < session_size)
|
||||
throw Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both communication
|
||||
* buffers. Also check both sizes separately to handle a
|
||||
* possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + session_size);
|
||||
throw Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return new (ROOT_COMPONENT::md_alloc())
|
||||
SESSION_COMPONENT(Lx::backend_alloc(tx_buf_size, CACHEABILITY),
|
||||
Lx::backend_alloc(rx_buf_size, CACHEABILITY),
|
||||
_ep, _device);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Packet_root(Server::Entrypoint &ep, Genode::Allocator *md_alloc, DEVICE &device)
|
||||
: ROOT_COMPONENT(&ep.rpc_ep(), md_alloc),
|
||||
_ep(ep), _device(device) { }
|
||||
};
|
||||
|
||||
#endif /* _SIGNAL__DISPATCHER_H_ */
|
@ -17,17 +17,17 @@
|
||||
#include <base/snprintf.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <nic/xml_node.h>
|
||||
#include <nic_session/nic_session.h>
|
||||
#include <os/config.h>
|
||||
#include <nic/component.h>
|
||||
#include <root/component.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
/* local includes */
|
||||
#include <lx.h>
|
||||
#include <nic/component.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
# include <lx_emul.h>
|
||||
# include <net/cfg80211.h>
|
||||
#include <lx_emul.h>
|
||||
#include <net/cfg80211.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
extern bool config_verbose;
|
||||
@ -37,22 +37,91 @@ enum {
|
||||
};
|
||||
|
||||
/**
|
||||
* Net_device to session glue code
|
||||
* Nic::Session implementation
|
||||
*/
|
||||
class Nic_device : public Nic::Device
|
||||
class Wifi_session_component : public Nic::Session_component
|
||||
{
|
||||
public: /* FIXME */
|
||||
private:
|
||||
|
||||
struct net_device *_ndev;
|
||||
Nic::Session_component *_session = nullptr;
|
||||
bool _has_link = false;
|
||||
net_device *_ndev;
|
||||
bool _has_link = !(_ndev->state & 1UL << __LINK_STATE_NOCARRIER);
|
||||
|
||||
protected:
|
||||
|
||||
bool _send()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!_tx.sink()->ready_to_ack())
|
||||
return false;
|
||||
|
||||
if (!_tx.sink()->packet_avail())
|
||||
return false;
|
||||
|
||||
Packet_descriptor packet = _tx.sink()->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("Invalid tx packet");
|
||||
return true;
|
||||
}
|
||||
|
||||
struct sk_buff *skb = ::alloc_skb(packet.size() + HEAD_ROOM, GFP_KERNEL);
|
||||
skb_reserve(skb, HEAD_ROOM);
|
||||
|
||||
unsigned char *data = skb_put(skb, packet.size());
|
||||
Genode::memcpy(data, _tx.sink()->packet_content(packet), packet.size());
|
||||
|
||||
_ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _handle_packet_stream()
|
||||
{
|
||||
while (_rx.source()->ack_avail())
|
||||
_rx.source()->release_packet(_rx.source()->get_acked_packet());
|
||||
|
||||
while (_send()) ;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Nic_device(struct net_device *ndev) : _ndev(ndev) { }
|
||||
|
||||
void rx(sk_buff *skb)
|
||||
Wifi_session_component(Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep, net_device *ndev)
|
||||
: Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep),
|
||||
_ndev(ndev)
|
||||
{
|
||||
_ndev->lx_nic_device = this;
|
||||
}
|
||||
|
||||
~Wifi_session_component()
|
||||
{
|
||||
_ndev->lx_nic_device = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report link state
|
||||
*/
|
||||
void link_state(bool link)
|
||||
{
|
||||
/* only report changes of the link state */
|
||||
if (link == _has_link)
|
||||
return;
|
||||
|
||||
_has_link = link;
|
||||
_link_state_changed();
|
||||
}
|
||||
|
||||
void receive(struct sk_buff *skb)
|
||||
{
|
||||
_handle_packet_stream();
|
||||
|
||||
if (!_rx.source()->ready_to_submit())
|
||||
return;
|
||||
|
||||
/* get mac header back */
|
||||
skb_push(skb, ETH_HLEN);
|
||||
|
||||
@ -77,29 +146,24 @@ class Nic_device : public Nic::Device
|
||||
else
|
||||
packet_size += skb->len;
|
||||
|
||||
_session->rx((Genode::addr_t)packet, packet_size, (Genode::addr_t)frag, frag_size);
|
||||
|
||||
try {
|
||||
Nic::Packet_descriptor p = _rx.source()->alloc_packet(packet_size + frag_size);
|
||||
void *buffer = _rx.source()->packet_content(p);
|
||||
memcpy(buffer, packet, packet_size);
|
||||
if (frag_size)
|
||||
memcpy((char *)buffer + packet_size, frag, frag_size);
|
||||
|
||||
_rx.source()->submit_packet(p);
|
||||
} catch (...) {
|
||||
PDBG("failed to process received packet");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Report link state
|
||||
*/
|
||||
void link_state(bool link)
|
||||
{
|
||||
/* only report changes of the link state */
|
||||
if (link == _has_link)
|
||||
return;
|
||||
|
||||
_has_link = link;
|
||||
|
||||
if (_session)
|
||||
_session->link_state_changed();
|
||||
}
|
||||
|
||||
/**********************
|
||||
** Device interface **
|
||||
**********************/
|
||||
|
||||
void session(Nic::Session_component *s) override { _session = s; }
|
||||
/*****************************
|
||||
** NIC-component interface **
|
||||
*****************************/
|
||||
|
||||
Nic::Mac_address mac_address() override
|
||||
{
|
||||
@ -109,32 +173,83 @@ class Nic_device : public Nic::Device
|
||||
}
|
||||
|
||||
bool link_state() override { return _has_link; }
|
||||
|
||||
bool tx(Genode::addr_t virt, Genode::size_t size) override
|
||||
{
|
||||
struct sk_buff *skb = ::alloc_skb(size + HEAD_ROOM, GFP_KERNEL);
|
||||
skb_reserve(skb, HEAD_ROOM);
|
||||
|
||||
unsigned char *data = skb_put(skb, size);
|
||||
Genode::memcpy(data, (void*)virt, size);
|
||||
|
||||
_ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static Nic_device *_nic = 0;
|
||||
/**
|
||||
* NIC root implementation
|
||||
*/
|
||||
class Root : public Genode::Root_component<Wifi_session_component,
|
||||
Genode::Single_client>
|
||||
{
|
||||
private:
|
||||
|
||||
static Server::Entrypoint *_ep;
|
||||
Server::Entrypoint &_ep;
|
||||
|
||||
void Lx::nic_init(Server::Entrypoint &ep) {
|
||||
_ep = &ep; }
|
||||
protected:
|
||||
|
||||
Wifi_session_component *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
/* deplete ram quota by the memory needed for the session structure */
|
||||
size_t session_size = max(4096UL, (unsigned long)sizeof(Wifi_session_component));
|
||||
if (ram_quota < session_size)
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both communication
|
||||
* buffers. Also check both sizes separately to handle a
|
||||
* possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size
|
||||
|| rx_buf_size > ram_quota - session_size
|
||||
|| tx_buf_size + rx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + rx_buf_size + session_size);
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
session = new (md_alloc())
|
||||
Wifi_session_component(tx_buf_size, rx_buf_size,
|
||||
*env()->heap(),
|
||||
*env()->ram_session(),
|
||||
_ep, device);
|
||||
return session;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
net_device *device = nullptr;
|
||||
Wifi_session_component *session = nullptr;
|
||||
static Root *instance;
|
||||
|
||||
Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
|
||||
: Genode::Root_component<Wifi_session_component, Genode::Single_client>(&ep.rpc_ep(), &md_alloc),
|
||||
_ep(ep)
|
||||
{ }
|
||||
|
||||
void announce() { Genode::env()->parent()->announce(_ep.rpc_ep().manage(this)); }
|
||||
};
|
||||
|
||||
|
||||
Root *Root::instance;
|
||||
|
||||
|
||||
void Lx::nic_init(Server::Entrypoint &ep)
|
||||
{
|
||||
static Root root(ep, *Genode::env()->heap());
|
||||
Root::instance = &root;
|
||||
}
|
||||
|
||||
|
||||
void Lx::get_mac_address(unsigned char *addr)
|
||||
{
|
||||
Genode::memcpy(addr, _nic->_ndev->perm_addr, ETH_ALEN);
|
||||
memcpy(addr, Root::instance->device->perm_addr, ETH_ALEN);
|
||||
}
|
||||
|
||||
|
||||
@ -319,12 +434,12 @@ extern "C" void __dev_remove_pack(struct packet_type *pt)
|
||||
|
||||
extern "C" struct net_device *__dev_get_by_index(struct net *net, int ifindex)
|
||||
{
|
||||
if (!_nic || !_nic->_ndev) {
|
||||
if (!Root::instance->device) {
|
||||
PERR("no net device registered!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _nic->_ndev;
|
||||
return Root::instance->device;
|
||||
}
|
||||
|
||||
|
||||
@ -387,18 +502,10 @@ extern "C" int register_netdevice(struct net_device *ndev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static Nic_device nic_device(ndev);
|
||||
static Nic::Root nic_root(*_ep, Genode::env()->heap(), nic_device);
|
||||
|
||||
/*
|
||||
* XXX This is just a starting point for removing all the static stuff from
|
||||
* this file...
|
||||
*/
|
||||
ndev->lx_nic_device = (void *)&nic_device;
|
||||
_nic = &nic_device;
|
||||
|
||||
already_registered = true;
|
||||
|
||||
Root::instance->device = ndev;
|
||||
|
||||
ndev->state |= 1UL << __LINK_STATE_START;
|
||||
netif_carrier_off(ndev);
|
||||
|
||||
@ -424,7 +531,7 @@ extern "C" int register_netdevice(struct net_device *ndev)
|
||||
if (ndev->netdev_ops->ndo_set_rx_mode)
|
||||
ndev->netdev_ops->ndo_set_rx_mode(ndev);
|
||||
|
||||
Genode::env()->parent()->announce(_ep->rpc_ep().manage(&nic_root));
|
||||
Root::instance->announce();
|
||||
|
||||
list_add_tail_rcu(&ndev->dev_list, &init_net.dev_base_head);
|
||||
|
||||
@ -451,9 +558,10 @@ extern "C" void netif_carrier_on(struct net_device *dev)
|
||||
{
|
||||
dev->state &= ~(1UL << __LINK_STATE_NOCARRIER);
|
||||
|
||||
Nic_device *nic = (Nic_device *)dev->lx_nic_device;
|
||||
Wifi_session_component *session = (Wifi_session_component *)dev->lx_nic_device;
|
||||
|
||||
nic->link_state(true);
|
||||
if (session)
|
||||
session->link_state(true);
|
||||
}
|
||||
|
||||
|
||||
@ -464,9 +572,10 @@ extern "C" void netif_carrier_off(struct net_device *dev)
|
||||
|
||||
dev->state |= 1UL << __LINK_STATE_NOCARRIER;
|
||||
|
||||
Nic_device *nic = (Nic_device *)dev->lx_nic_device;
|
||||
Wifi_session_component *session = (Wifi_session_component *)dev->lx_nic_device;
|
||||
|
||||
nic->link_state(false);
|
||||
if (session)
|
||||
session->link_state(false);
|
||||
}
|
||||
|
||||
|
||||
@ -481,14 +590,13 @@ extern "C" int netif_receive_skb(struct sk_buff *skb)
|
||||
if (ntohs(skb->protocol) == ETH_P_PAE) {
|
||||
/* XXX call only AF_PACKET hook */
|
||||
for (Proto_hook* ph = proto_hook_list().first(); ph; ph = ph->next()) {
|
||||
ph->pt.func(skb, _nic->_ndev, &ph->pt, _nic->_ndev);
|
||||
ph->pt.func(skb, Root::instance->device, &ph->pt, Root::instance->device);
|
||||
}
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
if (_nic && _nic->_session) {
|
||||
_nic->rx(skb);
|
||||
}
|
||||
if (Root::instance->session)
|
||||
Root::instance->session->receive(skb);
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
return NET_RX_SUCCESS;
|
||||
@ -567,12 +675,6 @@ extern "C" struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/inerrupt.h **
|
||||
**********************/
|
||||
|
||||
|
||||
|
||||
/*************************
|
||||
** linux/etherdevice.h **
|
||||
*************************/
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief Glue between device-specific NIC driver code and Genode
|
||||
* \brief Server::Entrypoint based NIC session component
|
||||
* \author Norman Feske
|
||||
* \date 2011-05-21
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||
* Copyright (C) 2015 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.
|
||||
@ -14,101 +15,64 @@
|
||||
#ifndef _INCLUDE__NIC__COMPONENT_H_
|
||||
#define _INCLUDE__NIC__COMPONENT_H_
|
||||
|
||||
#include <base/env.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <os/server.h>
|
||||
#include <nic/packet_allocator.h>
|
||||
#include <nic_session/rpc_object.h>
|
||||
#include <base/allocator_avl.h>
|
||||
#include <util/arg_string.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <root/component.h>
|
||||
#include <nic/driver.h>
|
||||
|
||||
enum { VERBOSE_RX = false };
|
||||
|
||||
namespace Nic {
|
||||
|
||||
class Communication_buffers;
|
||||
class Session_component;
|
||||
|
||||
/**
|
||||
* Shortcut for single-client NIC root component
|
||||
*/
|
||||
typedef Genode::Root_component<Session_component, Genode::Single_client>
|
||||
Root_component;
|
||||
|
||||
class Root;
|
||||
}
|
||||
|
||||
|
||||
class Nic::Session_component : public Genode::Allocator_avl,
|
||||
public Session_rpc_object, public Rx_buffer_alloc,
|
||||
public Driver_notification
|
||||
class Nic::Communication_buffers
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
|
||||
Driver_factory &_driver_factory;
|
||||
Driver &_driver;
|
||||
Nic::Packet_allocator _rx_packet_alloc;
|
||||
Genode::Attached_ram_dataspace _tx_ds, _rx_ds;
|
||||
|
||||
Communication_buffers(Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Genode::size_t tx_size, Genode::size_t rx_size)
|
||||
:
|
||||
_rx_packet_alloc(&rx_block_md_alloc),
|
||||
_tx_ds(&ram_session, tx_size),
|
||||
_rx_ds(&ram_session, rx_size)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
class Nic::Session_component : Communication_buffers, public Session_rpc_object
|
||||
{
|
||||
protected:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
Genode::Signal_context_capability _link_state_sigh;
|
||||
|
||||
/* rx packet descriptor */
|
||||
Genode::Packet_descriptor _curr_rx_packet;
|
||||
|
||||
enum { TX_STACK_SIZE = 8*1024 };
|
||||
class Tx_thread : public Genode::Thread<TX_STACK_SIZE>
|
||||
/**
|
||||
* Signal link-state change to client
|
||||
*/
|
||||
void _link_state_changed()
|
||||
{
|
||||
private:
|
||||
|
||||
Tx::Sink *_tx_sink;
|
||||
Driver &_driver;
|
||||
|
||||
public:
|
||||
|
||||
Tx_thread(Tx::Sink *tx_sink, Driver &driver)
|
||||
:
|
||||
Genode::Thread<TX_STACK_SIZE>("tx"),
|
||||
_tx_sink(tx_sink), _driver(driver)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void entry()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
while (true) {
|
||||
|
||||
/* block for packet from client */
|
||||
Packet_descriptor packet = _tx_sink->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("received invalid packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
_driver.tx(_tx_sink->packet_content(packet),
|
||||
packet.size());
|
||||
|
||||
/* acknowledge packet to the client */
|
||||
if (!_tx_sink->ready_to_ack())
|
||||
PDBG("need to wait until ready-for-ack");
|
||||
_tx_sink->acknowledge_packet(packet);
|
||||
}
|
||||
}
|
||||
} _tx_thread;
|
||||
|
||||
void dump()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!VERBOSE_RX) return;
|
||||
|
||||
char *buf = (char *)_rx.source()->packet_content(_curr_rx_packet);
|
||||
size_t size = _curr_rx_packet.size();
|
||||
|
||||
printf("rx packet:");
|
||||
for (unsigned i = 0; i < size; i++)
|
||||
printf("%02x,", buf[i]);
|
||||
printf("\n");
|
||||
if (_link_state_sigh.valid())
|
||||
Genode::Signal_transmitter(_link_state_sigh).submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-classes must implement this function, it is called upon all
|
||||
* packet-stream signals.
|
||||
*/
|
||||
virtual void _handle_packet_stream() = 0;
|
||||
|
||||
void _dispatch(unsigned) { _handle_packet_stream(); }
|
||||
|
||||
Genode::Signal_rpc_member<Session_component> _packet_stream_dispatcher {
|
||||
_ep, *this, &Session_component::_dispatch };
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -116,149 +80,47 @@ class Nic::Session_component : public Genode::Allocator_avl,
|
||||
*
|
||||
* \param tx_buf_size buffer size for tx channel
|
||||
* \param rx_buf_size buffer size for rx channel
|
||||
* \param rx_block_alloc rx block allocator
|
||||
* \param rx_block_md_alloc backing store of the meta data of the
|
||||
* rx block allocator
|
||||
* \param ram_session RAM session to allocate tx and rx buffers
|
||||
* \param ep entry point used for packet stream
|
||||
* channels
|
||||
*/
|
||||
Session_component(Genode::size_t tx_buf_size,
|
||||
Genode::size_t rx_buf_size,
|
||||
Nic::Driver_factory &driver_factory,
|
||||
Genode::Rpc_entrypoint &ep)
|
||||
Session_component(Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep)
|
||||
:
|
||||
Genode::Allocator_avl(Genode::env()->heap()),
|
||||
Session_rpc_object(Genode::env()->ram_session()->alloc(tx_buf_size),
|
||||
Genode::env()->ram_session()->alloc(rx_buf_size),
|
||||
static_cast<Genode::Range_allocator *>(this), ep),
|
||||
_driver_factory(driver_factory),
|
||||
_driver(*driver_factory.create(*this, *this)),
|
||||
_tx_thread(_tx.sink(), _driver)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Session_component()
|
||||
Communication_buffers(rx_block_md_alloc, ram_session,
|
||||
tx_buf_size, rx_buf_size),
|
||||
Session_rpc_object(_tx_ds.cap(),
|
||||
_rx_ds.cap(),
|
||||
&_rx_packet_alloc, ep.rpc_ep()),
|
||||
_ep(ep)
|
||||
{
|
||||
_driver_factory.destroy(&_driver);
|
||||
/* install data-flow signal handlers for both packet streams */
|
||||
_tx.sigh_ready_to_ack(_packet_stream_dispatcher);
|
||||
_tx.sigh_packet_avail(_packet_stream_dispatcher);
|
||||
_rx.sigh_ready_to_submit(_packet_stream_dispatcher);
|
||||
_rx.sigh_ack_avail(_packet_stream_dispatcher);
|
||||
}
|
||||
|
||||
/***********************************
|
||||
** Driver-notification interface **
|
||||
***********************************/
|
||||
|
||||
void link_state_changed() override
|
||||
{
|
||||
if (_link_state_sigh.valid())
|
||||
Genode::Signal_transmitter(_link_state_sigh).submit();
|
||||
}
|
||||
|
||||
/*******************************
|
||||
** Rx_buffer_alloc interface **
|
||||
*******************************/
|
||||
|
||||
void *alloc(Genode::size_t size) override
|
||||
{
|
||||
/* assign rx packet descriptor */
|
||||
_curr_rx_packet = _rx.source()->alloc_packet(size);
|
||||
|
||||
return _rx.source()->packet_content(_curr_rx_packet);
|
||||
}
|
||||
|
||||
void submit() override
|
||||
{
|
||||
/* check for acknowledgements from the client */
|
||||
while (_rx.source()->ack_avail()) {
|
||||
Genode::Packet_descriptor packet = _rx.source()->get_acked_packet();
|
||||
|
||||
/* free packet buffer */
|
||||
_rx.source()->release_packet(packet);
|
||||
}
|
||||
|
||||
dump();
|
||||
|
||||
_rx.source()->submit_packet(_curr_rx_packet);
|
||||
|
||||
/* invalidate rx packet descriptor */
|
||||
_curr_rx_packet = Packet_descriptor();
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
** Nic::Session interface **
|
||||
****************************/
|
||||
|
||||
Mac_address mac_address() { return _driver.mac_address(); }
|
||||
bool link_state() { return _driver.link_state(); }
|
||||
Tx::Sink* tx_sink() { return _tx.sink(); }
|
||||
Rx::Source* rx_source() { return _rx.source(); }
|
||||
|
||||
void link_state_sigh(Genode::Signal_context_capability sigh) override
|
||||
void link_state_sigh(Genode::Signal_context_capability sigh)
|
||||
{
|
||||
_link_state_sigh = sigh;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Root component, handling new session requests.
|
||||
*/
|
||||
class Nic::Root : public Root_component
|
||||
{
|
||||
private:
|
||||
|
||||
Driver_factory &_driver_factory;
|
||||
Genode::Rpc_entrypoint &_ep;
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
* Always returns the singleton nic-session component.
|
||||
/**
|
||||
* Return the current link state
|
||||
*/
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
virtual bool link_state() = 0;
|
||||
|
||||
Genode::size_t ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
Genode::size_t tx_buf_size =
|
||||
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
Genode::size_t rx_buf_size =
|
||||
Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
/* delete ram quota by the memory needed for the session */
|
||||
Genode::size_t session_size = max((Genode::size_t)4096, sizeof(Session_component)
|
||||
+ sizeof(Allocator_avl));
|
||||
if (ram_quota < session_size)
|
||||
throw Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both
|
||||
* communication buffers. Also check both sizes separately
|
||||
* to handle a possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size
|
||||
|| rx_buf_size > ram_quota - session_size
|
||||
|| tx_buf_size + rx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + rx_buf_size + session_size);
|
||||
throw Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return new (md_alloc()) Session_component(tx_buf_size,
|
||||
rx_buf_size,
|
||||
_driver_factory,
|
||||
_ep);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Genode::Rpc_entrypoint *session_ep,
|
||||
Genode::Allocator *md_alloc,
|
||||
Nic::Driver_factory &driver_factory)
|
||||
:
|
||||
Root_component(session_ep, md_alloc),
|
||||
_driver_factory(driver_factory),
|
||||
_ep(*session_ep)
|
||||
{ }
|
||||
/**
|
||||
* Return the MAC address of the device
|
||||
*/
|
||||
virtual Mac_address mac_address() = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif /* _INCLUDE__NIC__COMPONENT_H_ */
|
||||
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* \brief Interfaces used internally in NIC drivers
|
||||
* \author Norman Feske
|
||||
* \date 2011-05-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-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 _INCLUDE__NIC__DRIVER_H_
|
||||
#define _INCLUDE__NIC__DRIVER_H_
|
||||
|
||||
#include <os/irq_activation.h> /* for 'Genode::Irq_handler' type */
|
||||
#include <nic_session/nic_session.h> /* for 'Nic::Mac_address' type */
|
||||
|
||||
namespace Nic {
|
||||
|
||||
struct Rx_buffer_alloc;
|
||||
struct Driver;
|
||||
struct Driver_factory;
|
||||
struct Driver_notification;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface for allocating the backing store for incoming packets
|
||||
*/
|
||||
struct Nic::Rx_buffer_alloc
|
||||
{
|
||||
/**
|
||||
* Allocate packet buffer
|
||||
*/
|
||||
virtual void *alloc(Genode::size_t) = 0;
|
||||
|
||||
/**
|
||||
* Submit packet to client
|
||||
*/
|
||||
virtual void submit() = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Interface for driver-to-component notifications
|
||||
*/
|
||||
struct Nic::Driver_notification { virtual void link_state_changed() = 0; };
|
||||
|
||||
|
||||
/**
|
||||
* Interface to be implemented by the device-specific driver code
|
||||
*/
|
||||
struct Nic::Driver : Genode::Irq_handler
|
||||
{
|
||||
/**
|
||||
* Return MAC address of the network interface
|
||||
*/
|
||||
virtual Mac_address mac_address() = 0;
|
||||
|
||||
/**
|
||||
* Return link state (true if link detected)
|
||||
*/
|
||||
virtual bool link_state() = 0;
|
||||
|
||||
/**
|
||||
* Transmit packet
|
||||
*
|
||||
* \param packet start of packet
|
||||
* \param size packet size
|
||||
*
|
||||
* If the packet size is not a multiple of 4 bytes, this method
|
||||
* accesses the bytes after the packet buffer up to the next 4-byte
|
||||
* length (in the worst case, 3 bytes after the packet end).
|
||||
*/
|
||||
virtual void tx(char const *packet, Genode::size_t size) = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Interface for constructing the driver object
|
||||
*
|
||||
* The driver object requires an rx-packet allocator at construction time.
|
||||
* This allocator, however, exists not before the creation of a NIC session
|
||||
* because the client pays for it. Therefore, the driver must be created at
|
||||
* session-construction time. Because drivers may differ with regard to
|
||||
* their constructor arguments, the 'Driver_factory' interface allows for
|
||||
* unifying the session-creation among these drivers.
|
||||
*/
|
||||
struct Nic::Driver_factory
|
||||
{
|
||||
/**
|
||||
* Construct new driver
|
||||
*
|
||||
* \param rx_buffer_alloc buffer allocator used for storing incoming
|
||||
* packets
|
||||
* \param notifier callback for notifications
|
||||
*/
|
||||
virtual Driver *create(Rx_buffer_alloc &rx_buffer_alloc,
|
||||
Driver_notification ¬ify) = 0;
|
||||
|
||||
/**
|
||||
* Destroy driver
|
||||
*/
|
||||
virtual void destroy(Driver *driver) = 0;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__NIC__DRIVER_H_ */
|
77
repos/os/include/nic/root.h
Normal file
77
repos/os/include/nic/root.h
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* \brief Simple single client NIC Root
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2015-06-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015 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 _INCLUDE__NIC__ROOT_H_
|
||||
#define _INCLUDE__NIC__ROOT_H_
|
||||
|
||||
#include <nic/component.h>
|
||||
#include <root/component.h>
|
||||
|
||||
namespace Nic {
|
||||
|
||||
template <class SESSION_COMPONENT> class Root;
|
||||
};
|
||||
|
||||
|
||||
template <class SESSION_COMPONENT>
|
||||
class Nic::Root : public Genode::Root_component<SESSION_COMPONENT,
|
||||
Genode::Single_client>
|
||||
{
|
||||
private:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
|
||||
protected:
|
||||
|
||||
SESSION_COMPONENT *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
/* deplete ram quota by the memory needed for the session structure */
|
||||
size_t session_size = max(4096UL, (unsigned long)sizeof(SESSION_COMPONENT));
|
||||
if (ram_quota < session_size)
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both communication
|
||||
* buffers. Also check both sizes separately to handle a
|
||||
* possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size
|
||||
|| rx_buf_size > ram_quota - session_size
|
||||
|| tx_buf_size + rx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + rx_buf_size + session_size);
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return new (Root::md_alloc())
|
||||
SESSION_COMPONENT(tx_buf_size, rx_buf_size,
|
||||
*env()->heap(),
|
||||
*env()->ram_session(),
|
||||
_ep);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
|
||||
: Genode::Root_component<SESSION_COMPONENT, Genode::Single_client>(&ep.rpc_ep(), &md_alloc),
|
||||
_ep(ep)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__NIC__ROOT_H_ */
|
@ -19,9 +19,10 @@
|
||||
#include <os/attached_io_mem_dataspace.h>
|
||||
#include <os/irq_activation.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <nic/driver.h>
|
||||
#include <nic/component.h>
|
||||
|
||||
class Lan9118 : public Nic::Driver
|
||||
class Lan9118 : public Nic::Session_component,
|
||||
public Genode::Irq_handler
|
||||
{
|
||||
private:
|
||||
|
||||
@ -70,9 +71,7 @@ class Lan9118 : public Nic::Driver
|
||||
Genode::Attached_io_mem_dataspace _mmio;
|
||||
volatile Genode::uint32_t *_reg_base;
|
||||
Timer::Connection _timer;
|
||||
Nic::Rx_buffer_alloc &_rx_buffer_alloc;
|
||||
Nic::Mac_address _mac_addr;
|
||||
Nic::Driver_notification &_notify;
|
||||
|
||||
enum { IRQ_STACK_SIZE = 4096 };
|
||||
Genode::Irq_activation _irq_activation;
|
||||
@ -189,6 +188,67 @@ class Lan9118 : public Nic::Driver
|
||||
return _reg_read(RX_FIFO_INF) & 0xffff;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool _send()
|
||||
{
|
||||
if (!_tx.sink()->ready_to_ack())
|
||||
return false;
|
||||
|
||||
if (!_tx.sink()->packet_avail())
|
||||
return false;
|
||||
|
||||
Genode::Packet_descriptor packet = _tx.sink()->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("Invalid tx packet");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* limit size to 11 bits, the maximum supported by lan9118 */
|
||||
enum { MAX_PACKET_SIZE_LOG2 = 11 };
|
||||
Genode::size_t const max_size = (1 << MAX_PACKET_SIZE_LOG2) - 1;
|
||||
if (packet.size() > max_size) {
|
||||
PERR("packet size %zd too large, limit is %zd", packet.size(), max_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
enum { FIRST_SEG = (1 << 13),
|
||||
LAST_SEG = (1 << 12) };
|
||||
|
||||
Genode::uint32_t const cmd_a = packet.size() | FIRST_SEG | LAST_SEG,
|
||||
cmd_b = packet.size();
|
||||
|
||||
unsigned count = Genode::align_addr(packet.size(), 2) >> 2;
|
||||
Genode::uint32_t *src = (Genode::uint32_t *)_tx.sink()->packet_content(packet);
|
||||
|
||||
/* check space left in tx data fifo */
|
||||
Genode::size_t const fifo_avail = _reg_read(TX_FIFO_INF) & 0xffff;
|
||||
if (fifo_avail < count*4 + sizeof(cmd_a) + sizeof(cmd_b)) {
|
||||
PERR("tx fifo overrun, ignore packet");
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
return false;
|
||||
}
|
||||
|
||||
_reg_write(TX_DATA_FIFO, cmd_a);
|
||||
_reg_write(TX_DATA_FIFO, cmd_b);
|
||||
|
||||
/* supply payload to transmit fifo */
|
||||
for (; count--; src++)
|
||||
_reg_write(TX_DATA_FIFO, *src);
|
||||
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
return true;
|
||||
}
|
||||
|
||||
void _handle_packet_stream() override
|
||||
{
|
||||
while (_rx.source()->ack_avail())
|
||||
_rx.source()->release_packet(_rx.source()->get_acked_packet());
|
||||
|
||||
while (_send()) ;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -202,13 +262,14 @@ class Lan9118 : public Nic::Driver
|
||||
* \throw Device_not_supported
|
||||
*/
|
||||
Lan9118(Genode::addr_t mmio_base, Genode::size_t mmio_size, int irq,
|
||||
Nic::Rx_buffer_alloc &rx_buffer_alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
:
|
||||
Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep)
|
||||
: Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep),
|
||||
_mmio(mmio_base, mmio_size),
|
||||
_reg_base(_mmio.local_addr<Genode::uint32_t>()),
|
||||
_rx_buffer_alloc(rx_buffer_alloc),
|
||||
_notify(notify),
|
||||
_irq_activation(irq, *this, IRQ_STACK_SIZE)
|
||||
{
|
||||
unsigned long const id_rev = _reg_read(ID_REV),
|
||||
@ -290,58 +351,21 @@ class Lan9118 : public Nic::Driver
|
||||
_mac_csr_write(MAC_CR, 0);
|
||||
}
|
||||
|
||||
void link_state_changed() { _notify.link_state_changed(); }
|
||||
/**************************************
|
||||
** Nic::Session_component interface **
|
||||
**************************************/
|
||||
|
||||
|
||||
/***************************
|
||||
** Nic::Driver interface **
|
||||
***************************/
|
||||
|
||||
Nic::Mac_address mac_address()
|
||||
Nic::Mac_address mac_address() override
|
||||
{
|
||||
return _mac_addr;
|
||||
}
|
||||
|
||||
bool link_state()
|
||||
bool link_state() override
|
||||
{
|
||||
/* XXX always return true for now */
|
||||
return true;
|
||||
}
|
||||
|
||||
void tx(char const *packet, Genode::size_t size)
|
||||
{
|
||||
/* limit size to 11 bits, the maximum supported by lan9118 */
|
||||
enum { MAX_PACKET_SIZE_LOG2 = 11 };
|
||||
Genode::size_t const max_size = (1 << MAX_PACKET_SIZE_LOG2) - 1;
|
||||
if (size > max_size) {
|
||||
PERR("packet size %zd too large, limit is %zd", size, max_size);
|
||||
return;
|
||||
}
|
||||
|
||||
enum { FIRST_SEG = (1 << 13),
|
||||
LAST_SEG = (1 << 12) };
|
||||
|
||||
Genode::uint32_t const cmd_a = size | FIRST_SEG | LAST_SEG,
|
||||
cmd_b = size;
|
||||
|
||||
unsigned count = Genode::align_addr(size, 2) >> 2;
|
||||
Genode::uint32_t *src = (Genode::uint32_t *)packet;
|
||||
|
||||
/* check space left in tx data fifo */
|
||||
Genode::size_t const fifo_avail = _reg_read(TX_FIFO_INF) & 0xffff;
|
||||
if (fifo_avail < count*4 + sizeof(cmd_a) + sizeof(cmd_b)) {
|
||||
PERR("tx fifo overrun, ignore packet");
|
||||
return;
|
||||
}
|
||||
|
||||
_reg_write(TX_DATA_FIFO, cmd_a);
|
||||
_reg_write(TX_DATA_FIFO, cmd_b);
|
||||
|
||||
/* supply payload to transmit fifo */
|
||||
for (; count--; src++)
|
||||
_reg_write(TX_DATA_FIFO, *src);
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
** Irq_activation interface **
|
||||
@ -351,7 +375,9 @@ class Lan9118 : public Nic::Driver
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
while (_rx_packet_avail()) {
|
||||
_handle_packet_stream();
|
||||
|
||||
while (_rx_packet_avail() && _rx.source()->ready_to_submit()) {
|
||||
|
||||
/* read packet from NIC, copy to client buffer */
|
||||
Rx_packet_info packet = _rx_packet_info();
|
||||
@ -360,7 +386,12 @@ class Lan9118 : public Nic::Driver
|
||||
size_t const size = align_addr(packet.size, 2);
|
||||
|
||||
/* allocate rx packet buffer */
|
||||
uint32_t *dst = (uint32_t *)_rx_buffer_alloc.alloc(size);
|
||||
Nic::Packet_descriptor p;
|
||||
try {
|
||||
p = _rx.source()->alloc_packet(size);
|
||||
} catch (Session::Rx::Source::Packet_alloc_failed) { return; }
|
||||
|
||||
uint32_t *dst = (uint32_t *)_rx.source()->packet_content(p);
|
||||
|
||||
/* calculate number of words to be read from rx fifo */
|
||||
size_t count = min(size, _rx_data_pending()) >> 2;
|
||||
@ -369,7 +400,7 @@ class Lan9118 : public Nic::Driver
|
||||
for (; count--; )
|
||||
*dst++ = _reg_read(RX_DATA_FIFO);
|
||||
|
||||
_rx_buffer_alloc.submit();
|
||||
_rx.source()->submit_packet(p);
|
||||
}
|
||||
|
||||
/* acknowledge all pending irqs */
|
||||
|
@ -18,6 +18,8 @@
|
||||
#include <base/sleep.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <nic/component.h>
|
||||
#include <os/server.h>
|
||||
#include <root/component.h>
|
||||
|
||||
/* device definitions */
|
||||
#include <lan9118_defs.h>
|
||||
@ -25,39 +27,80 @@
|
||||
/* driver code */
|
||||
#include <lan9118.h>
|
||||
|
||||
namespace Server { struct Main; }
|
||||
|
||||
int main(int, char **)
|
||||
class Root : public Genode::Root_component<Lan9118, Genode::Single_client>
|
||||
{
|
||||
using namespace Genode;
|
||||
private:
|
||||
|
||||
printf("--- LAN9118 NIC driver started ---\n");
|
||||
Server::Entrypoint &_ep;
|
||||
|
||||
/**
|
||||
* Factory used by 'Nic::Root' at session creation/destruction time
|
||||
*/
|
||||
struct Lan9118_driver_factory : Nic::Driver_factory
|
||||
protected:
|
||||
|
||||
Lan9118 *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
/* deplete ram quota by the memory needed for the session structure */
|
||||
size_t session_size = max(4096UL, (unsigned long)sizeof(Lan9118));
|
||||
if (ram_quota < session_size)
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both communication
|
||||
* buffers. Also check both sizes separately to handle a
|
||||
* possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size
|
||||
|| rx_buf_size > ram_quota - session_size
|
||||
|| tx_buf_size + rx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + rx_buf_size + session_size);
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return new (Root::md_alloc())
|
||||
Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ,
|
||||
tx_buf_size, rx_buf_size,
|
||||
*env()->heap(),
|
||||
*env()->ram_session(),
|
||||
_ep);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
|
||||
: Genode::Root_component<Lan9118, Genode::Single_client>(&ep.rpc_ep(), &md_alloc),
|
||||
_ep(ep)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct Server::Main
|
||||
{
|
||||
Entrypoint &ep;
|
||||
::Root nic_root{ ep, *Genode::env()->heap() };
|
||||
|
||||
Main(Entrypoint &ep) : ep(ep)
|
||||
{
|
||||
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
{
|
||||
return new (env()->heap())
|
||||
Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ, alloc, notify);
|
||||
}
|
||||
printf("--- LAN9118 NIC driver started ---\n");
|
||||
Genode::env()->parent()->announce(ep.manage(nic_root));
|
||||
}
|
||||
};
|
||||
|
||||
void destroy(Nic::Driver *driver)
|
||||
{
|
||||
Genode::destroy(env()->heap(), static_cast<Lan9118 *>(driver));
|
||||
}
|
||||
|
||||
} driver_factory;
|
||||
namespace Server {
|
||||
|
||||
enum { STACK_SIZE = 4096 };
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_ep");
|
||||
char const *name() { return "nic_ep"; }
|
||||
|
||||
static Nic::Root nic_root(&ep, env()->heap(), driver_factory);
|
||||
env()->parent()->announce(ep.manage(&nic_root));
|
||||
size_t stack_size() { return 2*1024*sizeof(long); }
|
||||
|
||||
Genode::sleep_forever();
|
||||
return 0;
|
||||
void construct(Entrypoint &ep)
|
||||
{
|
||||
static Main main(ep);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
REQUIRES = lan9118
|
||||
TARGET = nic_drv
|
||||
SRC_CC = main.cc
|
||||
LIBS = base
|
||||
LIBS = base server
|
||||
INC_DIR += $(PRG_DIR)
|
||||
|
@ -2,6 +2,7 @@
|
||||
* \brief NIC driver for Linux TUN/TAP device
|
||||
* \author Stefan Kalkowski
|
||||
* \author Christian Helmuth
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2011-08-08
|
||||
*
|
||||
* Configuration options are:
|
||||
@ -23,9 +24,8 @@
|
||||
*/
|
||||
|
||||
/* Genode */
|
||||
#include <base/sleep.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <nic/component.h>
|
||||
#include <base/thread.h>
|
||||
#include <nic/root.h>
|
||||
#include <nic/xml_node.h>
|
||||
#include <os/config.h>
|
||||
|
||||
@ -37,18 +37,20 @@
|
||||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
|
||||
namespace Server { struct Main; }
|
||||
|
||||
class Linux_driver : public Nic::Driver
|
||||
|
||||
class Linux_session_component : public Nic::Session_component
|
||||
{
|
||||
private:
|
||||
|
||||
struct Rx_thread : Genode::Thread<0x2000>
|
||||
struct Rx_signal_thread : Genode::Thread<0x1000>
|
||||
{
|
||||
int fd;
|
||||
Nic::Driver &driver;
|
||||
int fd;
|
||||
Genode::Signal_context_capability sigh;
|
||||
|
||||
Rx_thread(int fd, Nic::Driver &driver)
|
||||
: Genode::Thread<0x2000>("rx"), fd(fd), driver(driver) { }
|
||||
Rx_signal_thread(int fd, Genode::Signal_context_capability sigh)
|
||||
: Genode::Thread<0x1000>("rx_signal"), fd(fd), sigh(sigh) { }
|
||||
|
||||
void entry()
|
||||
{
|
||||
@ -61,19 +63,15 @@ class Linux_driver : public Nic::Driver
|
||||
FD_SET(fd, &rfds);
|
||||
do { ret = select(fd + 1, &rfds, 0, 0, 0); } while (ret < 0);
|
||||
|
||||
/* inform driver about incoming packet */
|
||||
driver.handle_irq(fd);
|
||||
/* signal incoming packet */
|
||||
Genode::Signal_transmitter(sigh).submit();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Nic::Mac_address _mac_addr;
|
||||
Nic::Rx_buffer_alloc &_alloc;
|
||||
Nic::Driver_notification &_notify;
|
||||
|
||||
char _packet_buffer[1514]; /* maximum ethernet packet length */
|
||||
int _tap_fd;
|
||||
Rx_thread _rx_thread;
|
||||
Nic::Mac_address _mac_addr;
|
||||
int _tap_fd;
|
||||
Rx_signal_thread _rx_thread;
|
||||
|
||||
int _setup_tap_fd()
|
||||
{
|
||||
@ -88,6 +86,12 @@ class Linux_driver : public Nic::Driver
|
||||
throw Genode::Exception();
|
||||
}
|
||||
|
||||
/* set fd to non-blocking */
|
||||
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
|
||||
PERR("could not set /dev/net/tun to non-blocking");
|
||||
throw Genode::Exception();
|
||||
}
|
||||
|
||||
Genode::memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
|
||||
@ -113,13 +117,85 @@ class Linux_driver : public Nic::Driver
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool _send()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!_tx.sink()->ready_to_ack())
|
||||
return false;
|
||||
|
||||
if (!_tx.sink()->packet_avail())
|
||||
return false;
|
||||
|
||||
Packet_descriptor packet = _tx.sink()->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("Invalid tx packet");
|
||||
return true;
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
/* non-blocking-write packet to TAP */
|
||||
do {
|
||||
ret = write(_tap_fd, _tx.sink()->packet_content(packet), packet.size());
|
||||
/* drop packet if write would block */
|
||||
if (ret < 0 && errno == EAGAIN)
|
||||
continue;
|
||||
|
||||
if (ret < 0) PERR("write: errno=%d", errno);
|
||||
} while (ret < 0);
|
||||
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _receive()
|
||||
{
|
||||
unsigned const max_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE;
|
||||
|
||||
if (!_rx.source()->ready_to_submit())
|
||||
return false;
|
||||
|
||||
Nic::Packet_descriptor p;
|
||||
try {
|
||||
p = _rx.source()->alloc_packet(max_size);
|
||||
} catch (Session::Rx::Source::Packet_alloc_failed) { return false; }
|
||||
|
||||
int size = read(_tap_fd, _rx.source()->packet_content(p), max_size);
|
||||
if (size <= 0) {
|
||||
_rx.source()->release_packet(p);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* adjust packet size */
|
||||
Nic::Packet_descriptor p_adjust(p.offset(), size);
|
||||
_rx.source()->submit_packet(p_adjust);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void _handle_packet_stream() override
|
||||
{
|
||||
while (_rx.source()->ack_avail())
|
||||
_rx.source()->release_packet(_rx.source()->get_acked_packet());
|
||||
|
||||
while (_send()) ;
|
||||
while (_receive()) ;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Linux_driver(Nic::Rx_buffer_alloc &alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
Linux_session_component(Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep)
|
||||
:
|
||||
_alloc(alloc), _notify(notify),
|
||||
_tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, *this)
|
||||
Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep),
|
||||
_tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, _packet_stream_dispatcher)
|
||||
{
|
||||
/* try using configured MAC address */
|
||||
try {
|
||||
@ -145,93 +221,23 @@ class Linux_driver : public Nic::Driver
|
||||
_rx_thread.start();
|
||||
}
|
||||
|
||||
void link_state_changed() { _notify.link_state_changed(); }
|
||||
|
||||
|
||||
/***************************
|
||||
** Nic::Driver interface **
|
||||
***************************/
|
||||
|
||||
Nic::Mac_address mac_address() { return _mac_addr; }
|
||||
|
||||
bool link_state()
|
||||
{
|
||||
/* XXX return always true for now */
|
||||
return true;
|
||||
}
|
||||
|
||||
void tx(char const *packet, Genode::size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* blocking-write packet to TAP */
|
||||
do {
|
||||
ret = write(_tap_fd, packet, size);
|
||||
if (ret < 0) PERR("write: errno=%d", errno);
|
||||
} while (ret < 0);
|
||||
}
|
||||
|
||||
|
||||
/******************************
|
||||
** Irq_activation interface **
|
||||
******************************/
|
||||
|
||||
void handle_irq(int)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* blocking read incoming packet */
|
||||
do {
|
||||
ret = read(_tap_fd, _packet_buffer, sizeof(_packet_buffer));
|
||||
if (ret < 0) PERR("read: errno=%d", errno);
|
||||
} while (ret < 0);
|
||||
|
||||
void *buffer = _alloc.alloc(ret);
|
||||
Genode::memcpy(buffer, _packet_buffer, ret);
|
||||
_alloc.submit();
|
||||
}
|
||||
bool link_state() override { return true; }
|
||||
Nic::Mac_address mac_address() override { return _mac_addr; }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Manually initialize the 'lx_environ' pointer, needed because 'nic_drv' is not
|
||||
* using the normal Genode startup code.
|
||||
*/
|
||||
extern char **environ;
|
||||
char **lx_environ = environ;
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
struct Server::Main
|
||||
{
|
||||
using namespace Genode;
|
||||
Entrypoint &ep;
|
||||
Nic::Root<Linux_session_component> nic_root{ ep, *Genode::env()->heap() };
|
||||
|
||||
printf("--- Linux/tap NIC driver started ---\n");
|
||||
|
||||
/**
|
||||
* Factory used by 'Nic::Root' at session creation/destruction time
|
||||
*/
|
||||
struct Linux_driver_factory : Nic::Driver_factory
|
||||
Main(Entrypoint &ep) : ep(ep)
|
||||
{
|
||||
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
{
|
||||
return new (env()->heap()) Linux_driver(alloc, notify);
|
||||
}
|
||||
Genode::env()->parent()->announce(ep.manage(nic_root));
|
||||
}
|
||||
};
|
||||
|
||||
void destroy(Nic::Driver *driver)
|
||||
{
|
||||
Genode::destroy(env()->heap(), static_cast<Linux_driver *>(driver));
|
||||
}
|
||||
} driver_factory;
|
||||
|
||||
enum { STACK_SIZE = 2*4096 };
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_ep");
|
||||
|
||||
static Nic::Root nic_root(&ep, env()->heap(), driver_factory);
|
||||
env()->parent()->announce(ep.manage(&nic_root));
|
||||
|
||||
sleep_forever();
|
||||
return 0;
|
||||
}
|
||||
|
||||
char const * Server::name() { return "nic_ep"; }
|
||||
size_t Server::stack_size() { return 2*1024*sizeof(long); }
|
||||
void Server::construct(Entrypoint &ep) { static Main main(ep); }
|
||||
|
@ -1,4 +1,4 @@
|
||||
TARGET = nic_drv
|
||||
REQUIRES = linux
|
||||
LIBS = lx_hybrid config
|
||||
LIBS = lx_hybrid config server
|
||||
SRC_CC = main.cc
|
||||
|
@ -15,19 +15,16 @@
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/sleep.h>
|
||||
#include <os/attached_ram_dataspace.h>
|
||||
#include <os/server.h>
|
||||
#include <os/signal_rpc_dispatcher.h>
|
||||
#include <root/component.h>
|
||||
#include <util/arg_string.h>
|
||||
#include <util/misc_math.h>
|
||||
#include <nic_session/rpc_object.h>
|
||||
#include <nic_session/client.h>
|
||||
#include <nic/component.h>
|
||||
#include <nic/packet_allocator.h>
|
||||
|
||||
namespace Nic {
|
||||
|
||||
class Communication_buffers;
|
||||
class Session_component;
|
||||
class Loopback_component;
|
||||
class Root;
|
||||
}
|
||||
|
||||
@ -35,36 +32,8 @@ namespace Nic {
|
||||
namespace Server { struct Main; }
|
||||
|
||||
|
||||
class Nic::Communication_buffers
|
||||
class Nic::Loopback_component : public Nic::Session_component
|
||||
{
|
||||
protected:
|
||||
|
||||
Genode::Allocator_avl _rx_packet_alloc;
|
||||
|
||||
Genode::Attached_ram_dataspace _tx_ds, _rx_ds;
|
||||
|
||||
Communication_buffers(Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Genode::size_t tx_size, Genode::size_t rx_size)
|
||||
:
|
||||
_rx_packet_alloc(&rx_block_md_alloc),
|
||||
_tx_ds(&ram_session, tx_size),
|
||||
_rx_ds(&ram_session, rx_size)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
class Nic::Session_component : Communication_buffers, public Session_rpc_object
|
||||
{
|
||||
private:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
|
||||
void _handle_packet_stream(unsigned);
|
||||
|
||||
Genode::Signal_rpc_member<Session_component> _packet_stream_dispatcher {
|
||||
_ep, *this, &Session_component::_handle_packet_stream };
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -78,46 +47,37 @@ class Nic::Session_component : Communication_buffers, public Session_rpc_object
|
||||
* \param ep entry point used for packet stream
|
||||
* channels
|
||||
*/
|
||||
Session_component(Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep)
|
||||
:
|
||||
Communication_buffers(rx_block_md_alloc, ram_session,
|
||||
tx_buf_size, rx_buf_size),
|
||||
Session_rpc_object(this->_tx_ds.cap(),
|
||||
this->_rx_ds.cap(),
|
||||
&this->_rx_packet_alloc, ep.rpc_ep()),
|
||||
_ep(ep)
|
||||
{
|
||||
/* install data-flow signal handlers for both packet streams */
|
||||
_tx.sigh_ready_to_ack(_packet_stream_dispatcher);
|
||||
_tx.sigh_packet_avail(_packet_stream_dispatcher);
|
||||
_rx.sigh_ready_to_submit(_packet_stream_dispatcher);
|
||||
_rx.sigh_ack_avail(_packet_stream_dispatcher);
|
||||
}
|
||||
Loopback_component(Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep)
|
||||
: Session_component(tx_buf_size, rx_buf_size,
|
||||
rx_block_md_alloc, ram_session, ep)
|
||||
{ }
|
||||
|
||||
Mac_address mac_address()
|
||||
Mac_address mac_address() override
|
||||
{
|
||||
Mac_address result = {{1,2,3,4,5,6}};
|
||||
return result;
|
||||
}
|
||||
|
||||
bool link_state()
|
||||
bool link_state() override
|
||||
{
|
||||
/* XXX always return true, for now */
|
||||
return true;
|
||||
}
|
||||
|
||||
void link_state_sigh(Genode::Signal_context_capability sigh) { }
|
||||
void _handle_packet_stream() override;
|
||||
};
|
||||
|
||||
|
||||
void Nic::Session_component::_handle_packet_stream(unsigned)
|
||||
void Nic::Loopback_component::_handle_packet_stream()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
unsigned const alloc_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE;
|
||||
|
||||
/* loop unless we cannot make any progress */
|
||||
for (;;) {
|
||||
|
||||
@ -154,35 +114,36 @@ void Nic::Session_component::_handle_packet_stream(unsigned)
|
||||
* We are safe to process one packet without blocking.
|
||||
*/
|
||||
|
||||
|
||||
Packet_descriptor packet_to_client;
|
||||
try {
|
||||
packet_to_client = _rx.source()->alloc_packet(alloc_size);
|
||||
} catch (Session::Rx::Source::Packet_alloc_failed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* obtain packet */
|
||||
Packet_descriptor const packet_from_client = _tx.sink()->get_packet();
|
||||
if (!packet_from_client.valid()) {
|
||||
PWRN("received invalid packet");
|
||||
_rx.source()->release_packet(packet_to_client);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
size_t const packet_size = packet_from_client.size();
|
||||
|
||||
Packet_descriptor const packet_to_client =
|
||||
_rx.source()->alloc_packet(packet_size);
|
||||
|
||||
Genode::memcpy(_rx.source()->packet_content(packet_to_client),
|
||||
_tx.sink()->packet_content(packet_from_client),
|
||||
packet_size);
|
||||
packet_from_client.size());
|
||||
|
||||
packet_to_client = Packet_descriptor(packet_to_client.offset(), packet_from_client.size());
|
||||
_rx.source()->submit_packet(packet_to_client);
|
||||
|
||||
} catch (Session::Rx::Source::Packet_alloc_failed) {
|
||||
PWRN("transmit packet allocation failed, drop packet");
|
||||
}
|
||||
|
||||
_tx.sink()->acknowledge_packet(packet_from_client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Nic::Root : public Genode::Root_component<Session_component>
|
||||
class Nic::Root : public Genode::Root_component<Loopback_component>
|
||||
{
|
||||
private:
|
||||
|
||||
@ -190,7 +151,7 @@ class Nic::Root : public Genode::Root_component<Session_component>
|
||||
|
||||
protected:
|
||||
|
||||
Session_component *_create_session(const char *args)
|
||||
Loopback_component*_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
@ -216,7 +177,7 @@ class Nic::Root : public Genode::Root_component<Session_component>
|
||||
throw Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return new (md_alloc()) Session_component(tx_buf_size, rx_buf_size,
|
||||
return new (md_alloc()) Loopback_component(tx_buf_size, rx_buf_size,
|
||||
*env()->heap(),
|
||||
*env()->ram_session(),
|
||||
_ep);
|
||||
@ -226,7 +187,7 @@ class Nic::Root : public Genode::Root_component<Session_component>
|
||||
|
||||
Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
|
||||
:
|
||||
Genode::Root_component<Session_component>(&ep.rpc_ep(), &md_alloc),
|
||||
Genode::Root_component<Loopback_component>(&ep.rpc_ep(), &md_alloc),
|
||||
_ep(ep)
|
||||
{ }
|
||||
};
|
||||
|
@ -82,14 +82,12 @@ Tuntap_device *tuntap_dev()
|
||||
** Implementation of the Nic service **
|
||||
***************************************/
|
||||
|
||||
class Nic_driver : public Tuntap_device,
|
||||
public Nic::Driver
|
||||
class Openvpn_component : public Tuntap_device,
|
||||
public Nic::Session_component
|
||||
{
|
||||
private:
|
||||
|
||||
Nic::Mac_address _mac_addr {{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }};
|
||||
Nic::Rx_buffer_alloc &_alloc;
|
||||
Nic::Driver_notification &_notify;
|
||||
|
||||
char const *_packet;
|
||||
|
||||
@ -99,12 +97,52 @@ class Nic_driver : public Tuntap_device,
|
||||
Genode::Semaphore _startup_lock;
|
||||
Genode::Semaphore _tx_lock;
|
||||
|
||||
protected:
|
||||
|
||||
bool _send()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (!_tx.sink()->ready_to_ack())
|
||||
return false;
|
||||
|
||||
if (!_tx.sink()->packet_avail())
|
||||
return false;
|
||||
|
||||
Packet_descriptor packet = _tx.sink()->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("Invalid tx packet");
|
||||
return true;
|
||||
}
|
||||
|
||||
_packet = _tx.sink()->packet_content(packet);
|
||||
|
||||
/* notify openvpn */
|
||||
::write(_pipefd[WRITE], "1", 1);
|
||||
|
||||
/* block while openvpn handles the packet */
|
||||
_tx_lock.down();
|
||||
_tx.sink()->acknowledge_packet(packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _handle_packet_stream() override
|
||||
{
|
||||
while (_rx.source()->ack_avail())
|
||||
_rx.source()->release_packet(_rx.source()->get_acked_packet());
|
||||
|
||||
while (_send()) ;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Nic_driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification ¬ify)
|
||||
:
|
||||
_alloc(alloc), _notify(notify), _packet(0)
|
||||
Openvpn_component(Genode::size_t const tx_buf_size,
|
||||
Genode::size_t const rx_buf_size,
|
||||
Genode::Allocator &rx_block_md_alloc,
|
||||
Genode::Ram_session &ram_session,
|
||||
Server::Entrypoint &ep)
|
||||
: Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep)
|
||||
{
|
||||
if (pipe(_pipefd)) {
|
||||
PERR("could not create pipe");
|
||||
@ -112,41 +150,18 @@ class Nic_driver : public Tuntap_device,
|
||||
}
|
||||
}
|
||||
|
||||
~Nic_driver() { PDBG("should probably be implemented"); }
|
||||
/**************************************
|
||||
** Nic::Session_component interface **
|
||||
**************************************/
|
||||
|
||||
void link_state_changed() { _notify.link_state_changed(); }
|
||||
Nic::Mac_address mac_address() override { return _mac_addr; }
|
||||
|
||||
/***************************
|
||||
** Nic::Driver interface **
|
||||
***************************/
|
||||
|
||||
Nic::Mac_address mac_address() { return _mac_addr; }
|
||||
|
||||
bool link_state()
|
||||
bool link_state() override
|
||||
{
|
||||
/* XXX always return true for now */
|
||||
return true;
|
||||
}
|
||||
|
||||
void tx(char const *packet, Genode::size_t size)
|
||||
{
|
||||
PDBGV("packet:0x%p size:%zu", packet, size);
|
||||
|
||||
_packet = packet;
|
||||
|
||||
/* notify openvpn */
|
||||
::write(_pipefd[WRITE], "1", 1);
|
||||
|
||||
/* block while openvpn handles the packet */
|
||||
_tx_lock.down();
|
||||
}
|
||||
|
||||
/******************************
|
||||
** Irq_activation interface **
|
||||
******************************/
|
||||
|
||||
void handle_irq(int) { }
|
||||
|
||||
/***********************
|
||||
** TUN/TAP interface **
|
||||
***********************/
|
||||
@ -171,10 +186,16 @@ class Nic_driver : public Tuntap_device,
|
||||
int write(char const *buf, Genode::size_t len)
|
||||
{
|
||||
PDBGV("buf:0x%p len:%zu", len);
|
||||
_handle_packet_stream();
|
||||
|
||||
void *buffer = _alloc.alloc(len);
|
||||
Genode::memcpy(buffer, buf, len);
|
||||
_alloc.submit();
|
||||
if (!_rx.source()->ready_to_submit())
|
||||
return 0;
|
||||
|
||||
try {
|
||||
Genode::Packet_descriptor packet = _rx.source()->alloc_packet(len);
|
||||
Genode::memcpy(_rx.source()->packet_content(packet), buf, len);
|
||||
_rx.source()->submit_packet(packet);
|
||||
} catch (...) { return 0; }
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -185,57 +206,86 @@ class Nic_driver : public Tuntap_device,
|
||||
};
|
||||
|
||||
|
||||
struct Main
|
||||
class Root : public Genode::Root_component<Openvpn_component, Genode::Single_client>
|
||||
{
|
||||
struct Nic_driver_factory : Nic::Driver_factory
|
||||
{
|
||||
Nic_driver *drv { 0 };
|
||||
Openvpn_thread *openvpn { 0 };
|
||||
private:
|
||||
|
||||
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
|
||||
Nic::Driver_notification ¬ify)
|
||||
Server::Entrypoint &_ep;
|
||||
Openvpn_thread *_thread = nullptr;
|
||||
|
||||
protected:
|
||||
|
||||
Openvpn_component *_create_session(const char *args)
|
||||
{
|
||||
/* there can be only one */
|
||||
if (!drv) {
|
||||
drv = new (Genode::env()->heap()) Nic_driver(alloc, notify);
|
||||
using namespace Genode;
|
||||
|
||||
/**
|
||||
* Setting the pointer in this manner is quite hackish but it has
|
||||
* to be valid before OpenVPN calls open_tun(), which unfortunatly
|
||||
* is early.
|
||||
*/
|
||||
_tuntap_dev = drv;
|
||||
size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
PDBGV("start OpenVPN main thread");
|
||||
Openvpn_thread *openvpn = new (Genode::env()->heap()) Openvpn_thread(genode_argc,
|
||||
genode_argv);
|
||||
/* deplete ram quota by the memory needed for the session structure */
|
||||
size_t session_size = max(4096UL, (unsigned long)sizeof(Openvpn_component));
|
||||
if (ram_quota < session_size)
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
|
||||
openvpn->start();
|
||||
|
||||
/* wait until OpenVPN configured the TUN/TAP device for the first time */
|
||||
_tuntap_dev->down();
|
||||
|
||||
return drv;
|
||||
/*
|
||||
* Check if donated ram quota suffices for both communication
|
||||
* buffers. Also check both sizes separately to handle a
|
||||
* possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size
|
||||
|| rx_buf_size > ram_quota - session_size
|
||||
|| tx_buf_size + rx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + rx_buf_size + session_size);
|
||||
throw Genode::Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return 0;
|
||||
Openvpn_component *component = new (Root::md_alloc())
|
||||
Openvpn_component(tx_buf_size, rx_buf_size,
|
||||
*env()->heap(),
|
||||
*env()->ram_session(),
|
||||
_ep);
|
||||
/**
|
||||
* Setting the pointer in this manner is quite hackish but it has
|
||||
* to be valid before OpenVPN calls open_tun(), which unfortunatly
|
||||
* is early.
|
||||
*/
|
||||
_tuntap_dev = component;
|
||||
|
||||
PDBGV("start OpenVPN main thread");
|
||||
_thread = new (Genode::env()->heap()) Openvpn_thread(genode_argc, genode_argv);
|
||||
_thread->start();
|
||||
|
||||
/* wait until OpenVPN configured the TUN/TAP device for the first time */
|
||||
_tuntap_dev->down();
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
void destroy(Nic::Driver *driver)
|
||||
void _destroy_session(Openvpn_component *session)
|
||||
{
|
||||
Genode::destroy(Genode::env()->heap(), static_cast<Nic_driver *>(driver));
|
||||
drv = 0;
|
||||
Genode::destroy(Genode::env()->heap(), openvpn);
|
||||
openvpn = 0;
|
||||
Genode::destroy(Root::md_alloc(), session);
|
||||
Genode::destroy(Root::md_alloc(), _thread);
|
||||
_thread = nullptr;
|
||||
}
|
||||
} driver_factory;
|
||||
|
||||
public:
|
||||
|
||||
Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
|
||||
: Genode::Root_component<Openvpn_component, Genode::Single_client>(&ep.rpc_ep(), &md_alloc),
|
||||
_ep(ep)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
Server::Entrypoint &ep;
|
||||
::Root nic_root { ep, *Genode::env()->heap() };
|
||||
|
||||
Main(Server::Entrypoint &ep) : ep(ep)
|
||||
{
|
||||
static Nic::Root nic_root(&ep.rpc_ep(), Genode::env()->heap(), driver_factory);
|
||||
|
||||
Genode::env()->parent()->announce(ep.manage(nic_root));
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user