mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +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
|
* \brief NIC driver based on iPXE
|
||||||
* \author Christian Helmuth
|
* \author Christian Helmuth
|
||||||
|
* \author Sebastian Sumpf
|
||||||
* \date 2011-11-17
|
* \date 2011-11-17
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -17,131 +18,133 @@
|
|||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
#include <cap_session/connection.h>
|
#include <cap_session/connection.h>
|
||||||
#include <nic/component.h>
|
#include <nic/component.h>
|
||||||
|
#include <nic/root.h>
|
||||||
#include <os/server.h>
|
#include <os/server.h>
|
||||||
|
|
||||||
#include <dde_ipxe/nic.h>
|
#include <dde_ipxe/nic.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Ipxe {
|
class Ipxe_session_component : public Nic::Session_component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
class Driver : public Nic::Driver
|
static Ipxe_session_component *instance;
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
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;
|
static void _link_callback()
|
||||||
Nic::Rx_buffer_alloc &_alloc;
|
{
|
||||||
Nic::Driver_notification &_notify;
|
if (instance)
|
||||||
|
instance->_link_state_changed();
|
||||||
|
}
|
||||||
|
|
||||||
static void _rx_callback(unsigned if_index,
|
bool _send()
|
||||||
const char *packet,
|
{
|
||||||
unsigned packet_len)
|
using namespace Genode;
|
||||||
{
|
|
||||||
instance->rx_handler(packet, packet_len);
|
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,
|
void _receive(const char *packet, unsigned packet_len)
|
||||||
Nic::Driver_notification ¬ify)
|
{
|
||||||
: _ep(ep), _alloc(alloc), _notify(notify)
|
_handle_packet_stream();
|
||||||
{
|
|
||||||
PINF("--- init callbacks");
|
|
||||||
dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback);
|
|
||||||
|
|
||||||
dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr);
|
if (!_rx.source()->ready_to_submit())
|
||||||
PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x",
|
return;
|
||||||
_mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff,
|
|
||||||
_mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff,
|
try {
|
||||||
_mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff);
|
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)
|
while (_send()) ;
|
||||||
{
|
}
|
||||||
try {
|
|
||||||
void *buffer = _alloc.alloc(packet_len);
|
|
||||||
Genode::memcpy(buffer, packet, packet_len);
|
|
||||||
_alloc.submit();
|
|
||||||
} catch (...) {
|
|
||||||
PDBG("failed to process received packet");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/***************************
|
Ipxe_session_component *Ipxe_session_component::instance;
|
||||||
** 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;
|
|
||||||
|
|
||||||
|
|
||||||
struct Main
|
struct Main
|
||||||
{
|
{
|
||||||
Server::Entrypoint &ep;
|
Server::Entrypoint &ep;
|
||||||
Genode::Sliced_heap sliced_heap;
|
|
||||||
|
|
||||||
struct Factory : public Nic::Driver_factory
|
Nic::Root<Ipxe_session_component> root {ep, *Genode::env()->heap() };
|
||||||
{
|
|
||||||
Server::Entrypoint &ep;
|
|
||||||
|
|
||||||
Factory(Server::Entrypoint &ep) : ep(ep) { }
|
Main(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");
|
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 <linux/usb/usbnet.h>
|
||||||
#include <extern_c_end.h>
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
#include <nic/component.h>
|
#include <usb_nic_component.h>
|
||||||
#include "signal.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
|
* Net_device to session glue code
|
||||||
*/
|
*/
|
||||||
class Nic_device : public Nic::Device
|
class Nic_device : public Usb_nic::Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ int register_netdev(struct net_device *ndev)
|
|||||||
|
|
||||||
/* XXX: move to 'main' */
|
/* XXX: move to 'main' */
|
||||||
if (!announce) {
|
if (!announce) {
|
||||||
static Nic::Root root(_signal->ep(), env()->heap(), nic);
|
static ::Root root(_signal->ep(), *env()->heap(), nic);
|
||||||
|
|
||||||
announce = true;
|
announce = true;
|
||||||
|
|
||||||
@ -333,10 +333,6 @@ int register_netdev(struct net_device *ndev)
|
|||||||
if (ndev->netdev_ops->ndo_set_rx_mode)
|
if (ndev->netdev_ops->ndo_set_rx_mode)
|
||||||
ndev->netdev_ops->ndo_set_rx_mode(ndev);
|
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;
|
_nic = nic;
|
||||||
env()->parent()->announce(_signal->ep().rpc_ep().manage(&root));
|
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 <base/snprintf.h>
|
||||||
#include <cap_session/connection.h>
|
#include <cap_session/connection.h>
|
||||||
#include <nic/xml_node.h>
|
#include <nic/xml_node.h>
|
||||||
#include <nic_session/nic_session.h>
|
|
||||||
#include <os/config.h>
|
#include <os/config.h>
|
||||||
|
#include <nic/component.h>
|
||||||
|
#include <root/component.h>
|
||||||
#include <util/xml_node.h>
|
#include <util/xml_node.h>
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
#include <lx.h>
|
#include <lx.h>
|
||||||
#include <nic/component.h>
|
|
||||||
|
|
||||||
#include <extern_c_begin.h>
|
#include <extern_c_begin.h>
|
||||||
# include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
# include <net/cfg80211.h>
|
#include <net/cfg80211.h>
|
||||||
#include <extern_c_end.h>
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
extern bool config_verbose;
|
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;
|
net_device *_ndev;
|
||||||
Nic::Session_component *_session = nullptr;
|
bool _has_link = !(_ndev->state & 1UL << __LINK_STATE_NOCARRIER);
|
||||||
bool _has_link = false;
|
|
||||||
|
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:
|
public:
|
||||||
|
|
||||||
Nic_device(struct net_device *ndev) : _ndev(ndev) { }
|
Wifi_session_component(Genode::size_t const tx_buf_size,
|
||||||
|
Genode::size_t const rx_buf_size,
|
||||||
void rx(sk_buff *skb)
|
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 */
|
/* get mac header back */
|
||||||
skb_push(skb, ETH_HLEN);
|
skb_push(skb, ETH_HLEN);
|
||||||
|
|
||||||
@ -77,29 +146,24 @@ class Nic_device : public Nic::Device
|
|||||||
else
|
else
|
||||||
packet_size += skb->len;
|
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;
|
/*****************************
|
||||||
|
** NIC-component interface **
|
||||||
if (_session)
|
*****************************/
|
||||||
_session->link_state_changed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************
|
|
||||||
** Device interface **
|
|
||||||
**********************/
|
|
||||||
|
|
||||||
void session(Nic::Session_component *s) override { _session = s; }
|
|
||||||
|
|
||||||
Nic::Mac_address mac_address() override
|
Nic::Mac_address mac_address() override
|
||||||
{
|
{
|
||||||
@ -109,32 +173,83 @@ class Nic_device : public Nic::Device
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool link_state() override { return _has_link; }
|
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) {
|
protected:
|
||||||
_ep = &ep; }
|
|
||||||
|
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)
|
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)
|
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!");
|
PERR("no net device registered!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _nic->_ndev;
|
return Root::instance->device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -387,18 +502,10 @@ extern "C" int register_netdevice(struct net_device *ndev)
|
|||||||
return -ENODEV;
|
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;
|
already_registered = true;
|
||||||
|
|
||||||
|
Root::instance->device = ndev;
|
||||||
|
|
||||||
ndev->state |= 1UL << __LINK_STATE_START;
|
ndev->state |= 1UL << __LINK_STATE_START;
|
||||||
netif_carrier_off(ndev);
|
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)
|
if (ndev->netdev_ops->ndo_set_rx_mode)
|
||||||
ndev->netdev_ops->ndo_set_rx_mode(ndev);
|
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);
|
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);
|
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;
|
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) {
|
if (ntohs(skb->protocol) == ETH_P_PAE) {
|
||||||
/* XXX call only AF_PACKET hook */
|
/* XXX call only AF_PACKET hook */
|
||||||
for (Proto_hook* ph = proto_hook_list().first(); ph; ph = ph->next()) {
|
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;
|
return NET_RX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_nic && _nic->_session) {
|
if (Root::instance->session)
|
||||||
_nic->rx(skb);
|
Root::instance->session->receive(skb);
|
||||||
}
|
|
||||||
|
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
return NET_RX_SUCCESS;
|
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 **
|
** 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
|
* \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
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
@ -14,101 +15,64 @@
|
|||||||
#ifndef _INCLUDE__NIC__COMPONENT_H_
|
#ifndef _INCLUDE__NIC__COMPONENT_H_
|
||||||
#define _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 <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 {
|
namespace Nic {
|
||||||
|
|
||||||
|
class Communication_buffers;
|
||||||
class Session_component;
|
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,
|
class Nic::Communication_buffers
|
||||||
public Session_rpc_object, public Rx_buffer_alloc,
|
|
||||||
public Driver_notification
|
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
Driver_factory &_driver_factory;
|
Nic::Packet_allocator _rx_packet_alloc;
|
||||||
Driver &_driver;
|
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;
|
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:
|
if (_link_state_sigh.valid())
|
||||||
|
Genode::Signal_transmitter(_link_state_sigh).submit();
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,149 +80,47 @@ class Nic::Session_component : public Genode::Allocator_avl,
|
|||||||
*
|
*
|
||||||
* \param tx_buf_size buffer size for tx channel
|
* \param tx_buf_size buffer size for tx channel
|
||||||
* \param rx_buf_size buffer size for rx 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
|
* \param ep entry point used for packet stream
|
||||||
|
* channels
|
||||||
*/
|
*/
|
||||||
Session_component(Genode::size_t tx_buf_size,
|
Session_component(Genode::size_t const tx_buf_size,
|
||||||
Genode::size_t rx_buf_size,
|
Genode::size_t const rx_buf_size,
|
||||||
Nic::Driver_factory &driver_factory,
|
Genode::Allocator &rx_block_md_alloc,
|
||||||
Genode::Rpc_entrypoint &ep)
|
Genode::Ram_session &ram_session,
|
||||||
|
Server::Entrypoint &ep)
|
||||||
:
|
:
|
||||||
Genode::Allocator_avl(Genode::env()->heap()),
|
Communication_buffers(rx_block_md_alloc, ram_session,
|
||||||
Session_rpc_object(Genode::env()->ram_session()->alloc(tx_buf_size),
|
tx_buf_size, rx_buf_size),
|
||||||
Genode::env()->ram_session()->alloc(rx_buf_size),
|
Session_rpc_object(_tx_ds.cap(),
|
||||||
static_cast<Genode::Range_allocator *>(this), ep),
|
_rx_ds.cap(),
|
||||||
_driver_factory(driver_factory),
|
&_rx_packet_alloc, ep.rpc_ep()),
|
||||||
_driver(*driver_factory.create(*this, *this)),
|
_ep(ep)
|
||||||
_tx_thread(_tx.sink(), _driver)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*/
|
|
||||||
~Session_component()
|
|
||||||
{
|
{
|
||||||
_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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************
|
void link_state_sigh(Genode::Signal_context_capability sigh)
|
||||||
** 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
|
|
||||||
{
|
{
|
||||||
_link_state_sigh = sigh;
|
_link_state_sigh = sigh;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
* Return the current link state
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
Session_component *_create_session(const char *args)
|
virtual bool link_state() = 0;
|
||||||
{
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
Genode::size_t ram_quota =
|
/**
|
||||||
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
* Return the MAC address of the device
|
||||||
Genode::size_t tx_buf_size =
|
*/
|
||||||
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
virtual Mac_address mac_address() = 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)
|
|
||||||
{ }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif /* _INCLUDE__NIC__COMPONENT_H_ */
|
#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/attached_io_mem_dataspace.h>
|
||||||
#include <os/irq_activation.h>
|
#include <os/irq_activation.h>
|
||||||
#include <timer_session/connection.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:
|
private:
|
||||||
|
|
||||||
@ -70,9 +71,7 @@ class Lan9118 : public Nic::Driver
|
|||||||
Genode::Attached_io_mem_dataspace _mmio;
|
Genode::Attached_io_mem_dataspace _mmio;
|
||||||
volatile Genode::uint32_t *_reg_base;
|
volatile Genode::uint32_t *_reg_base;
|
||||||
Timer::Connection _timer;
|
Timer::Connection _timer;
|
||||||
Nic::Rx_buffer_alloc &_rx_buffer_alloc;
|
|
||||||
Nic::Mac_address _mac_addr;
|
Nic::Mac_address _mac_addr;
|
||||||
Nic::Driver_notification &_notify;
|
|
||||||
|
|
||||||
enum { IRQ_STACK_SIZE = 4096 };
|
enum { IRQ_STACK_SIZE = 4096 };
|
||||||
Genode::Irq_activation _irq_activation;
|
Genode::Irq_activation _irq_activation;
|
||||||
@ -189,6 +188,67 @@ class Lan9118 : public Nic::Driver
|
|||||||
return _reg_read(RX_FIFO_INF) & 0xffff;
|
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:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -202,13 +262,14 @@ class Lan9118 : public Nic::Driver
|
|||||||
* \throw Device_not_supported
|
* \throw Device_not_supported
|
||||||
*/
|
*/
|
||||||
Lan9118(Genode::addr_t mmio_base, Genode::size_t mmio_size, int irq,
|
Lan9118(Genode::addr_t mmio_base, Genode::size_t mmio_size, int irq,
|
||||||
Nic::Rx_buffer_alloc &rx_buffer_alloc,
|
Genode::size_t const tx_buf_size,
|
||||||
Nic::Driver_notification ¬ify)
|
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),
|
_mmio(mmio_base, mmio_size),
|
||||||
_reg_base(_mmio.local_addr<Genode::uint32_t>()),
|
_reg_base(_mmio.local_addr<Genode::uint32_t>()),
|
||||||
_rx_buffer_alloc(rx_buffer_alloc),
|
|
||||||
_notify(notify),
|
|
||||||
_irq_activation(irq, *this, IRQ_STACK_SIZE)
|
_irq_activation(irq, *this, IRQ_STACK_SIZE)
|
||||||
{
|
{
|
||||||
unsigned long const id_rev = _reg_read(ID_REV),
|
unsigned long const id_rev = _reg_read(ID_REV),
|
||||||
@ -290,58 +351,21 @@ class Lan9118 : public Nic::Driver
|
|||||||
_mac_csr_write(MAC_CR, 0);
|
_mac_csr_write(MAC_CR, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void link_state_changed() { _notify.link_state_changed(); }
|
/**************************************
|
||||||
|
** Nic::Session_component interface **
|
||||||
|
**************************************/
|
||||||
|
|
||||||
|
Nic::Mac_address mac_address() override
|
||||||
/***************************
|
|
||||||
** Nic::Driver interface **
|
|
||||||
***************************/
|
|
||||||
|
|
||||||
Nic::Mac_address mac_address()
|
|
||||||
{
|
{
|
||||||
return _mac_addr;
|
return _mac_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool link_state()
|
bool link_state() override
|
||||||
{
|
{
|
||||||
/* XXX always return true for now */
|
/* XXX always return true for now */
|
||||||
return true;
|
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 **
|
** Irq_activation interface **
|
||||||
@ -351,7 +375,9 @@ class Lan9118 : public Nic::Driver
|
|||||||
{
|
{
|
||||||
using namespace Genode;
|
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 */
|
/* read packet from NIC, copy to client buffer */
|
||||||
Rx_packet_info packet = _rx_packet_info();
|
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);
|
size_t const size = align_addr(packet.size, 2);
|
||||||
|
|
||||||
/* allocate rx packet buffer */
|
/* 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 */
|
/* calculate number of words to be read from rx fifo */
|
||||||
size_t count = min(size, _rx_data_pending()) >> 2;
|
size_t count = min(size, _rx_data_pending()) >> 2;
|
||||||
@ -369,7 +400,7 @@ class Lan9118 : public Nic::Driver
|
|||||||
for (; count--; )
|
for (; count--; )
|
||||||
*dst++ = _reg_read(RX_DATA_FIFO);
|
*dst++ = _reg_read(RX_DATA_FIFO);
|
||||||
|
|
||||||
_rx_buffer_alloc.submit();
|
_rx.source()->submit_packet(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* acknowledge all pending irqs */
|
/* acknowledge all pending irqs */
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
#include <base/sleep.h>
|
#include <base/sleep.h>
|
||||||
#include <cap_session/connection.h>
|
#include <cap_session/connection.h>
|
||||||
#include <nic/component.h>
|
#include <nic/component.h>
|
||||||
|
#include <os/server.h>
|
||||||
|
#include <root/component.h>
|
||||||
|
|
||||||
/* device definitions */
|
/* device definitions */
|
||||||
#include <lan9118_defs.h>
|
#include <lan9118_defs.h>
|
||||||
@ -25,39 +27,80 @@
|
|||||||
/* driver code */
|
/* driver code */
|
||||||
#include <lan9118.h>
|
#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;
|
||||||
|
|
||||||
/**
|
protected:
|
||||||
* Factory used by 'Nic::Root' at session creation/destruction time
|
|
||||||
*/
|
Lan9118 *_create_session(const char *args)
|
||||||
struct Lan9118_driver_factory : Nic::Driver_factory
|
{
|
||||||
|
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,
|
printf("--- LAN9118 NIC driver started ---\n");
|
||||||
Nic::Driver_notification ¬ify)
|
Genode::env()->parent()->announce(ep.manage(nic_root));
|
||||||
{
|
}
|
||||||
return new (env()->heap())
|
};
|
||||||
Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ, alloc, notify);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy(Nic::Driver *driver)
|
|
||||||
{
|
|
||||||
Genode::destroy(env()->heap(), static_cast<Lan9118 *>(driver));
|
|
||||||
}
|
|
||||||
|
|
||||||
} driver_factory;
|
namespace Server {
|
||||||
|
|
||||||
enum { STACK_SIZE = 4096 };
|
char const *name() { return "nic_ep"; }
|
||||||
static Cap_connection cap;
|
|
||||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_ep");
|
|
||||||
|
|
||||||
static Nic::Root nic_root(&ep, env()->heap(), driver_factory);
|
size_t stack_size() { return 2*1024*sizeof(long); }
|
||||||
env()->parent()->announce(ep.manage(&nic_root));
|
|
||||||
|
|
||||||
Genode::sleep_forever();
|
void construct(Entrypoint &ep)
|
||||||
return 0;
|
{
|
||||||
|
static Main main(ep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
REQUIRES = lan9118
|
REQUIRES = lan9118
|
||||||
TARGET = nic_drv
|
TARGET = nic_drv
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = base
|
LIBS = base server
|
||||||
INC_DIR += $(PRG_DIR)
|
INC_DIR += $(PRG_DIR)
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* \brief NIC driver for Linux TUN/TAP device
|
* \brief NIC driver for Linux TUN/TAP device
|
||||||
* \author Stefan Kalkowski
|
* \author Stefan Kalkowski
|
||||||
* \author Christian Helmuth
|
* \author Christian Helmuth
|
||||||
|
* \author Sebastian Sumpf
|
||||||
* \date 2011-08-08
|
* \date 2011-08-08
|
||||||
*
|
*
|
||||||
* Configuration options are:
|
* Configuration options are:
|
||||||
@ -23,9 +24,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode */
|
/* Genode */
|
||||||
#include <base/sleep.h>
|
#include <base/thread.h>
|
||||||
#include <cap_session/connection.h>
|
#include <nic/root.h>
|
||||||
#include <nic/component.h>
|
|
||||||
#include <nic/xml_node.h>
|
#include <nic/xml_node.h>
|
||||||
#include <os/config.h>
|
#include <os/config.h>
|
||||||
|
|
||||||
@ -37,18 +37,20 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <linux/if_tun.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:
|
private:
|
||||||
|
|
||||||
struct Rx_thread : Genode::Thread<0x2000>
|
struct Rx_signal_thread : Genode::Thread<0x1000>
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
Nic::Driver &driver;
|
Genode::Signal_context_capability sigh;
|
||||||
|
|
||||||
Rx_thread(int fd, Nic::Driver &driver)
|
Rx_signal_thread(int fd, Genode::Signal_context_capability sigh)
|
||||||
: Genode::Thread<0x2000>("rx"), fd(fd), driver(driver) { }
|
: Genode::Thread<0x1000>("rx_signal"), fd(fd), sigh(sigh) { }
|
||||||
|
|
||||||
void entry()
|
void entry()
|
||||||
{
|
{
|
||||||
@ -61,19 +63,15 @@ class Linux_driver : public Nic::Driver
|
|||||||
FD_SET(fd, &rfds);
|
FD_SET(fd, &rfds);
|
||||||
do { ret = select(fd + 1, &rfds, 0, 0, 0); } while (ret < 0);
|
do { ret = select(fd + 1, &rfds, 0, 0, 0); } while (ret < 0);
|
||||||
|
|
||||||
/* inform driver about incoming packet */
|
/* signal incoming packet */
|
||||||
driver.handle_irq(fd);
|
Genode::Signal_transmitter(sigh).submit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Nic::Mac_address _mac_addr;
|
Nic::Mac_address _mac_addr;
|
||||||
Nic::Rx_buffer_alloc &_alloc;
|
int _tap_fd;
|
||||||
Nic::Driver_notification &_notify;
|
Rx_signal_thread _rx_thread;
|
||||||
|
|
||||||
char _packet_buffer[1514]; /* maximum ethernet packet length */
|
|
||||||
int _tap_fd;
|
|
||||||
Rx_thread _rx_thread;
|
|
||||||
|
|
||||||
int _setup_tap_fd()
|
int _setup_tap_fd()
|
||||||
{
|
{
|
||||||
@ -88,6 +86,12 @@ class Linux_driver : public Nic::Driver
|
|||||||
throw Genode::Exception();
|
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));
|
Genode::memset(&ifr, 0, sizeof(ifr));
|
||||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||||
|
|
||||||
@ -113,13 +117,85 @@ class Linux_driver : public Nic::Driver
|
|||||||
return fd;
|
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:
|
public:
|
||||||
|
|
||||||
Linux_driver(Nic::Rx_buffer_alloc &alloc,
|
Linux_session_component(Genode::size_t const tx_buf_size,
|
||||||
Nic::Driver_notification ¬ify)
|
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),
|
Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep),
|
||||||
_tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, *this)
|
_tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, _packet_stream_dispatcher)
|
||||||
{
|
{
|
||||||
/* try using configured MAC address */
|
/* try using configured MAC address */
|
||||||
try {
|
try {
|
||||||
@ -145,93 +221,23 @@ class Linux_driver : public Nic::Driver
|
|||||||
_rx_thread.start();
|
_rx_thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void link_state_changed() { _notify.link_state_changed(); }
|
bool link_state() override { return true; }
|
||||||
|
Nic::Mac_address mac_address() override { return _mac_addr; }
|
||||||
|
|
||||||
/***************************
|
|
||||||
** 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();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
struct Server::Main
|
||||||
* 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 **)
|
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
Entrypoint &ep;
|
||||||
|
Nic::Root<Linux_session_component> nic_root{ ep, *Genode::env()->heap() };
|
||||||
|
|
||||||
printf("--- Linux/tap NIC driver started ---\n");
|
Main(Entrypoint &ep) : ep(ep)
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory used by 'Nic::Root' at session creation/destruction time
|
|
||||||
*/
|
|
||||||
struct Linux_driver_factory : Nic::Driver_factory
|
|
||||||
{
|
{
|
||||||
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
|
Genode::env()->parent()->announce(ep.manage(nic_root));
|
||||||
Nic::Driver_notification ¬ify)
|
}
|
||||||
{
|
};
|
||||||
return new (env()->heap()) Linux_driver(alloc, notify);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
TARGET = nic_drv
|
||||||
REQUIRES = linux
|
REQUIRES = linux
|
||||||
LIBS = lx_hybrid config
|
LIBS = lx_hybrid config server
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
|
@ -15,19 +15,16 @@
|
|||||||
|
|
||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
#include <base/sleep.h>
|
#include <base/sleep.h>
|
||||||
#include <os/attached_ram_dataspace.h>
|
|
||||||
#include <os/server.h>
|
#include <os/server.h>
|
||||||
#include <os/signal_rpc_dispatcher.h>
|
|
||||||
#include <root/component.h>
|
#include <root/component.h>
|
||||||
#include <util/arg_string.h>
|
#include <util/arg_string.h>
|
||||||
#include <util/misc_math.h>
|
#include <util/misc_math.h>
|
||||||
#include <nic_session/rpc_object.h>
|
#include <nic/component.h>
|
||||||
#include <nic_session/client.h>
|
#include <nic/packet_allocator.h>
|
||||||
|
|
||||||
namespace Nic {
|
namespace Nic {
|
||||||
|
|
||||||
class Communication_buffers;
|
class Loopback_component;
|
||||||
class Session_component;
|
|
||||||
class Root;
|
class Root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,36 +32,8 @@ namespace Nic {
|
|||||||
namespace Server { struct Main; }
|
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:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,46 +47,37 @@ class Nic::Session_component : Communication_buffers, public Session_rpc_object
|
|||||||
* \param ep entry point used for packet stream
|
* \param ep entry point used for packet stream
|
||||||
* channels
|
* channels
|
||||||
*/
|
*/
|
||||||
Session_component(Genode::size_t const tx_buf_size,
|
Loopback_component(Genode::size_t const tx_buf_size,
|
||||||
Genode::size_t const rx_buf_size,
|
Genode::size_t const rx_buf_size,
|
||||||
Genode::Allocator &rx_block_md_alloc,
|
Genode::Allocator &rx_block_md_alloc,
|
||||||
Genode::Ram_session &ram_session,
|
Genode::Ram_session &ram_session,
|
||||||
Server::Entrypoint &ep)
|
Server::Entrypoint &ep)
|
||||||
:
|
: Session_component(tx_buf_size, rx_buf_size,
|
||||||
Communication_buffers(rx_block_md_alloc, ram_session,
|
rx_block_md_alloc, ram_session, ep)
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
Mac_address mac_address()
|
Mac_address mac_address() override
|
||||||
{
|
{
|
||||||
Mac_address result = {{1,2,3,4,5,6}};
|
Mac_address result = {{1,2,3,4,5,6}};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool link_state()
|
bool link_state() override
|
||||||
{
|
{
|
||||||
/* XXX always return true, for now */
|
/* XXX always return true, for now */
|
||||||
return true;
|
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;
|
using namespace Genode;
|
||||||
|
|
||||||
|
unsigned const alloc_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE;
|
||||||
|
|
||||||
/* loop unless we cannot make any progress */
|
/* loop unless we cannot make any progress */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
@ -154,35 +114,36 @@ void Nic::Session_component::_handle_packet_stream(unsigned)
|
|||||||
* We are safe to process one packet without blocking.
|
* 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 */
|
/* obtain packet */
|
||||||
Packet_descriptor const packet_from_client = _tx.sink()->get_packet();
|
Packet_descriptor const packet_from_client = _tx.sink()->get_packet();
|
||||||
if (!packet_from_client.valid()) {
|
if (!packet_from_client.valid()) {
|
||||||
PWRN("received invalid packet");
|
PWRN("received invalid packet");
|
||||||
|
_rx.source()->release_packet(packet_to_client);
|
||||||
continue;
|
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),
|
Genode::memcpy(_rx.source()->packet_content(packet_to_client),
|
||||||
_tx.sink()->packet_content(packet_from_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);
|
_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);
|
_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:
|
private:
|
||||||
|
|
||||||
@ -190,7 +151,7 @@ class Nic::Root : public Genode::Root_component<Session_component>
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Session_component *_create_session(const char *args)
|
Loopback_component*_create_session(const char *args)
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
@ -216,7 +177,7 @@ class Nic::Root : public Genode::Root_component<Session_component>
|
|||||||
throw Root::Quota_exceeded();
|
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()->heap(),
|
||||||
*env()->ram_session(),
|
*env()->ram_session(),
|
||||||
_ep);
|
_ep);
|
||||||
@ -226,7 +187,7 @@ class Nic::Root : public Genode::Root_component<Session_component>
|
|||||||
|
|
||||||
Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
|
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)
|
_ep(ep)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
@ -82,14 +82,12 @@ Tuntap_device *tuntap_dev()
|
|||||||
** Implementation of the Nic service **
|
** Implementation of the Nic service **
|
||||||
***************************************/
|
***************************************/
|
||||||
|
|
||||||
class Nic_driver : public Tuntap_device,
|
class Openvpn_component : public Tuntap_device,
|
||||||
public Nic::Driver
|
public Nic::Session_component
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Nic::Mac_address _mac_addr {{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }};
|
Nic::Mac_address _mac_addr {{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }};
|
||||||
Nic::Rx_buffer_alloc &_alloc;
|
|
||||||
Nic::Driver_notification &_notify;
|
|
||||||
|
|
||||||
char const *_packet;
|
char const *_packet;
|
||||||
|
|
||||||
@ -99,12 +97,52 @@ class Nic_driver : public Tuntap_device,
|
|||||||
Genode::Semaphore _startup_lock;
|
Genode::Semaphore _startup_lock;
|
||||||
Genode::Semaphore _tx_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:
|
public:
|
||||||
|
|
||||||
Nic_driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification ¬ify)
|
Openvpn_component(Genode::size_t const tx_buf_size,
|
||||||
:
|
Genode::size_t const rx_buf_size,
|
||||||
_alloc(alloc), _notify(notify), _packet(0)
|
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)) {
|
if (pipe(_pipefd)) {
|
||||||
PERR("could not create pipe");
|
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; }
|
||||||
|
|
||||||
/***************************
|
bool link_state() override
|
||||||
** Nic::Driver interface **
|
|
||||||
***************************/
|
|
||||||
|
|
||||||
Nic::Mac_address mac_address() { return _mac_addr; }
|
|
||||||
|
|
||||||
bool link_state()
|
|
||||||
{
|
{
|
||||||
/* XXX always return true for now */
|
/* XXX always return true for now */
|
||||||
return true;
|
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 **
|
** TUN/TAP interface **
|
||||||
***********************/
|
***********************/
|
||||||
@ -171,10 +186,16 @@ class Nic_driver : public Tuntap_device,
|
|||||||
int write(char const *buf, Genode::size_t len)
|
int write(char const *buf, Genode::size_t len)
|
||||||
{
|
{
|
||||||
PDBGV("buf:0x%p len:%zu", len);
|
PDBGV("buf:0x%p len:%zu", len);
|
||||||
|
_handle_packet_stream();
|
||||||
|
|
||||||
void *buffer = _alloc.alloc(len);
|
if (!_rx.source()->ready_to_submit())
|
||||||
Genode::memcpy(buffer, buf, len);
|
return 0;
|
||||||
_alloc.submit();
|
|
||||||
|
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;
|
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
|
private:
|
||||||
{
|
|
||||||
Nic_driver *drv { 0 };
|
|
||||||
Openvpn_thread *openvpn { 0 };
|
|
||||||
|
|
||||||
Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
|
Server::Entrypoint &_ep;
|
||||||
Nic::Driver_notification ¬ify)
|
Openvpn_thread *_thread = nullptr;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Openvpn_component *_create_session(const char *args)
|
||||||
{
|
{
|
||||||
/* there can be only one */
|
using namespace Genode;
|
||||||
if (!drv) {
|
|
||||||
drv = new (Genode::env()->heap()) Nic_driver(alloc, notify);
|
|
||||||
|
|
||||||
/**
|
size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||||
* Setting the pointer in this manner is quite hackish but it has
|
size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||||
* to be valid before OpenVPN calls open_tun(), which unfortunatly
|
size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||||
* is early.
|
|
||||||
*/
|
|
||||||
_tuntap_dev = drv;
|
|
||||||
|
|
||||||
PDBGV("start OpenVPN main thread");
|
/* deplete ram quota by the memory needed for the session structure */
|
||||||
Openvpn_thread *openvpn = new (Genode::env()->heap()) Openvpn_thread(genode_argc,
|
size_t session_size = max(4096UL, (unsigned long)sizeof(Openvpn_component));
|
||||||
genode_argv);
|
if (ram_quota < session_size)
|
||||||
|
throw Genode::Root::Quota_exceeded();
|
||||||
|
|
||||||
openvpn->start();
|
/*
|
||||||
|
* Check if donated ram quota suffices for both communication
|
||||||
/* wait until OpenVPN configured the TUN/TAP device for the first time */
|
* buffers. Also check both sizes separately to handle a
|
||||||
_tuntap_dev->down();
|
* possible overflow of the sum of both sizes.
|
||||||
|
*/
|
||||||
return drv;
|
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));
|
Genode::destroy(Root::md_alloc(), session);
|
||||||
drv = 0;
|
Genode::destroy(Root::md_alloc(), _thread);
|
||||||
Genode::destroy(Genode::env()->heap(), openvpn);
|
_thread = nullptr;
|
||||||
openvpn = 0;
|
|
||||||
}
|
}
|
||||||
} 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;
|
Server::Entrypoint &ep;
|
||||||
|
::Root nic_root { ep, *Genode::env()->heap() };
|
||||||
|
|
||||||
Main(Server::Entrypoint &ep) : ep(ep)
|
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));
|
Genode::env()->parent()->announce(ep.manage(nic_root));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user