diff --git a/repos/dde_ipxe/src/drivers/nic/main.cc b/repos/dde_ipxe/src/drivers/nic/main.cc
index e805a1f6d5..6ae85c3ad3 100644
--- a/repos/dde_ipxe/src/drivers/nic/main.cc
+++ b/repos/dde_ipxe/src/drivers/nic/main.cc
@@ -1,6 +1,7 @@
/*
* \brief NIC driver based on iPXE
* \author Christian Helmuth
+ * \author Sebastian Sumpf
* \date 2011-11-17
*/
@@ -17,131 +18,133 @@
#include
#include
#include
+#include
#include
#include
-namespace Ipxe {
+class Ipxe_session_component : public Nic::Session_component
+{
+ public:
- class Driver : public Nic::Driver
- {
- public:
+ static Ipxe_session_component *instance;
- static Driver *instance;
+ private:
- private:
+ Nic::Mac_address _mac_addr;
- Server::Entrypoint &_ep;
+ static void _rx_callback(unsigned if_index,
+ const char *packet,
+ unsigned packet_len)
+ {
+ if (instance)
+ instance->_receive(packet, packet_len);
+ }
- Nic::Mac_address _mac_addr;
- Nic::Rx_buffer_alloc &_alloc;
- Nic::Driver_notification &_notify;
+ static void _link_callback()
+ {
+ if (instance)
+ instance->_link_state_changed();
+ }
- static void _rx_callback(unsigned if_index,
- const char *packet,
- unsigned packet_len)
- {
- instance->rx_handler(packet, packet_len);
+ bool _send()
+ {
+ using namespace Genode;
+
+ if (!_tx.sink()->ready_to_ack())
+ return false;
+
+ if (!_tx.sink()->packet_avail())
+ return false;
+
+ Packet_descriptor packet = _tx.sink()->get_packet();
+ if (!packet.valid()) {
+ PWRN("Invalid tx packet");
+ return true;
}
- static void _link_callback() { instance->link_state_changed(); }
+ if (dde_ipxe_nic_tx(1, _tx.sink()->packet_content(packet), packet.size()))
+ PWRN("Sending packet failed!");
- public:
+ _tx.sink()->acknowledge_packet(packet);
+ return true;
+ }
- Driver(Server::Entrypoint &ep, Nic::Rx_buffer_alloc &alloc,
- Nic::Driver_notification ¬ify)
- : _ep(ep), _alloc(alloc), _notify(notify)
- {
- PINF("--- init callbacks");
- dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback);
+ void _receive(const char *packet, unsigned packet_len)
+ {
+ _handle_packet_stream();
- dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr);
- PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x",
- _mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff,
- _mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff,
- _mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff);
+ if (!_rx.source()->ready_to_submit())
+ return;
+
+ try {
+ Nic::Packet_descriptor p = _rx.source()->alloc_packet(packet_len);
+ Genode::memcpy(_rx.source()->packet_content(p), packet, packet_len);
+ _rx.source()->submit_packet(p);
+ } catch (...) {
+ PDBG("failed to process received packet");
}
+ }
- ~Driver() { dde_ipxe_nic_unregister_callbacks(); }
+ void _handle_packet_stream() override
+ {
+ while (_rx.source()->ack_avail())
+ _rx.source()->release_packet(_rx.source()->get_acked_packet());
- void rx_handler(const char *packet, unsigned packet_len)
- {
- try {
- void *buffer = _alloc.alloc(packet_len);
- Genode::memcpy(buffer, packet, packet_len);
- _alloc.submit();
- } catch (...) {
- PDBG("failed to process received packet");
- }
- }
+ while (_send()) ;
+ }
- void link_state_changed() { _notify.link_state_changed(); }
+ public:
+
+ Ipxe_session_component(Genode::size_t const tx_buf_size,
+ Genode::size_t const rx_buf_size,
+ Genode::Allocator &rx_block_md_alloc,
+ Genode::Ram_session &ram_session,
+ Server::Entrypoint &ep)
+ : Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep)
+ {
+ instance = this;
+
+ PINF("--- init callbacks");
+ dde_ipxe_nic_register_callbacks(_rx_callback, _link_callback);
+
+ dde_ipxe_nic_get_mac_addr(1, _mac_addr.addr);
+ PINF("--- get MAC address %02x:%02x:%02x:%02x:%02x:%02x",
+ _mac_addr.addr[0] & 0xff, _mac_addr.addr[1] & 0xff,
+ _mac_addr.addr[2] & 0xff, _mac_addr.addr[3] & 0xff,
+ _mac_addr.addr[4] & 0xff, _mac_addr.addr[5] & 0xff);
+ }
+
+ ~Ipxe_session_component()
+ {
+ instance = nullptr;
+ dde_ipxe_nic_unregister_callbacks();
+ }
+
+ /**************************************
+ ** Nic::Session_component interface **
+ **************************************/
+
+ Nic::Mac_address mac_address() override { return _mac_addr; }
+
+ bool link_state() override
+ {
+ return dde_ipxe_nic_link_state(1);
+ }
+};
- /***************************
- ** Nic::Driver interface **
- ***************************/
-
- Nic::Mac_address mac_address() override { return _mac_addr; }
-
- bool link_state() override
- {
- return dde_ipxe_nic_link_state(1);
- }
-
- void tx(char const *packet, Genode::size_t size)
- {
- if (dde_ipxe_nic_tx(1, packet, size))
- PWRN("Sending packet failed!");
- }
-
- /******************************
- ** Irq_activation interface **
- ******************************/
-
- void handle_irq(int) { /* not used */ }
- };
-
-} /* namespace Ipxe */
-
-
-Ipxe::Driver * Ipxe::Driver::instance = 0;
+Ipxe_session_component *Ipxe_session_component::instance;
struct Main
{
- Server::Entrypoint &ep;
- Genode::Sliced_heap sliced_heap;
+ Server::Entrypoint &ep;
- struct Factory : public Nic::Driver_factory
- {
- Server::Entrypoint &ep;
+ Nic::Root root {ep, *Genode::env()->heap() };
- Factory(Server::Entrypoint &ep) : ep(ep) { }
-
- Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
- Nic::Driver_notification ¬ify)
- {
- Ipxe::Driver::instance = new (Genode::env()->heap()) Ipxe::Driver(ep, alloc, notify);
- return Ipxe::Driver::instance;
- }
-
- void destroy(Nic::Driver *)
- {
- Genode::destroy(Genode::env()->heap(), Ipxe::Driver::instance);
- Ipxe::Driver::instance = 0;
- }
- } factory;
-
- Nic::Root root;
-
- Main(Server::Entrypoint &ep)
- :
- ep(ep),
- sliced_heap(Genode::env()->ram_session(), Genode::env()->rm_session()),
- factory(ep),
- root(&ep.rpc_ep(), &sliced_heap, factory)
+ Main(Server::Entrypoint &ep) : ep(ep)
{
PINF("--- iPXE NIC driver started ---\n");
diff --git a/repos/dde_ipxe/src/drivers/nic_stat/main.cc b/repos/dde_ipxe/src/drivers/nic_stat/main.cc
deleted file mode 100644
index 059edb1171..0000000000
--- a/repos/dde_ipxe/src/drivers/nic_stat/main.cc
+++ /dev/null
@@ -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
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-/* DDE */
-extern "C" {
-#include
-}
-
-
-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(packet);
- void * buffer = reinterpret_cast(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); }
-}
diff --git a/repos/dde_ipxe/src/drivers/nic_stat/target.mk b/repos/dde_ipxe/src/drivers/nic_stat/target.mk
deleted file mode 100644
index 77251cfb3c..0000000000
--- a/repos/dde_ipxe/src/drivers/nic_stat/target.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-TARGET = nic_drv_stat
-LIBS = base server dde_ipxe_nic net-stat
-SRC_CC = main.cc
diff --git a/repos/dde_linux/src/lib/usb/include/nic/component.h b/repos/dde_linux/src/lib/usb/include/nic/component.h
deleted file mode 100644
index 5fc61f668c..0000000000
--- a/repos/dde_linux/src/lib/usb/include/nic/component.h
+++ /dev/null
@@ -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
-#include
-#include
-#include
-#include
-
-#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
- {
- 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)),
- _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 Root_component;
-
- /**
- * Root component, handling new session requests
- */
- class Root : public Packet_root
- {
- public:
-
- Root(Server::Entrypoint &ep, Allocator *md_alloc,
- Device *device)
- : Packet_root(ep, md_alloc, device) { }
- };
-}
-
-
-#endif /* _NIC__COMPONENT_H_ */
diff --git a/repos/dde_linux/src/lib/usb/include/signal/dispatch.h b/repos/dde_linux/src/lib/usb/include/signal/dispatch.h
deleted file mode 100644
index 5a4fa248bb..0000000000
--- a/repos/dde_linux/src/lib/usb/include/signal/dispatch.h
+++ /dev/null
@@ -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
-class Packet_session_component : public RPC
-{
- private:
-
- Genode::Signal_rpc_member _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
- 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_ */
diff --git a/repos/dde_linux/src/lib/usb/include/usb_nic_component.h b/repos/dde_linux/src/lib/usb/include/usb_nic_component.h
new file mode 100644
index 0000000000..84f3ce1251
--- /dev/null
+++ b/repos/dde_linux/src/lib/usb/include/usb_nic_component.h
@@ -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
+#include
+
+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 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_ */
diff --git a/repos/dde_linux/src/lib/usb/nic/nic.cc b/repos/dde_linux/src/lib/usb/nic/nic.cc
index 0d0bea8d6f..1652ababf2 100644
--- a/repos/dde_linux/src/lib/usb/nic/nic.cc
+++ b/repos/dde_linux/src/lib/usb/nic/nic.cc
@@ -25,7 +25,7 @@
#include
#include
-#include
+#include
#include "signal.h"
@@ -137,7 +137,7 @@ typedef struct sk_buff* (*fixup_t)(struct usbnet *, struct sk_buff *, gfp_t);
/**
* Net_device to session glue code
*/
-class Nic_device : public Nic::Device
+class Nic_device : public Usb_nic::Device
{
public:
@@ -320,7 +320,7 @@ int register_netdev(struct net_device *ndev)
/* XXX: move to 'main' */
if (!announce) {
- static Nic::Root root(_signal->ep(), env()->heap(), nic);
+ static ::Root root(_signal->ep(), *env()->heap(), nic);
announce = true;
@@ -333,10 +333,6 @@ int register_netdev(struct net_device *ndev)
if (ndev->netdev_ops->ndo_set_rx_mode)
ndev->netdev_ops->ndo_set_rx_mode(ndev);
-/*
- if(ndev->netdev_ops->ndo_change_mtu)
- ndev->netdev_ops->ndo_change_mtu(ndev, 4000);
-*/
_nic = nic;
env()->parent()->announce(_signal->ep().rpc_ep().manage(&root));
}
diff --git a/repos/dde_linux/src/lib/wifi/include/nic/component.h b/repos/dde_linux/src/lib/wifi/include/nic/component.h
deleted file mode 100644
index 861b3dc3a0..0000000000
--- a/repos/dde_linux/src/lib/wifi/include/nic/component.h
+++ /dev/null
@@ -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
-#include
-#include
-#include
-
-/* local includes */
-#include
-
-#include
-# include
-#include
-
-
-namespace Nic {
-
- using namespace Genode; /* FIXME */
-
- struct Session_component;
- struct Device;
-
- typedef Genode::Root_component 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
-{
- 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(Server::Entrypoint &ep, Allocator *md_alloc, Device &device)
- : Packet_root(ep, md_alloc, device) { }
-};
-
-#endif /* _NIC__COMPONENT_H_ */
diff --git a/repos/dde_linux/src/lib/wifi/include/nic/dispatch.h b/repos/dde_linux/src/lib/wifi/include/nic/dispatch.h
deleted file mode 100644
index 9c43bf889e..0000000000
--- a/repos/dde_linux/src/lib/wifi/include/nic/dispatch.h
+++ /dev/null
@@ -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
-
-/* local includes */
-#include
-
-
-/**
- * Session components that overrides signal handlers
- */
-template
-class Packet_session_component : public SESSION_RPC_OBJECT
-{
- private:
-
- Genode::Signal_rpc_member _tx_ready_to_ack_dispatcher;
- Genode::Signal_rpc_member _tx_packet_avail_dispatcher;
- Genode::Signal_rpc_member _rx_ack_avail_dispatcher;
- Genode::Signal_rpc_member _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
-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_ */
diff --git a/repos/dde_linux/src/lib/wifi/nic.cc b/repos/dde_linux/src/lib/wifi/nic.cc
index da5ed2f271..27bc5f5f31 100644
--- a/repos/dde_linux/src/lib/wifi/nic.cc
+++ b/repos/dde_linux/src/lib/wifi/nic.cc
@@ -17,17 +17,17 @@
#include
#include
#include
-#include
#include
+#include
+#include
#include
/* local includes */
#include
-#include
#include
-# include
-# include
+#include
+#include
#include
extern bool config_verbose;
@@ -37,22 +37,91 @@ enum {
};
/**
- * Net_device to session glue code
+ * Nic::Session implementation
*/
-class Nic_device : public Nic::Device
+class Wifi_session_component : public Nic::Session_component
{
- public: /* FIXME */
+ private:
- struct net_device *_ndev;
- Nic::Session_component *_session = nullptr;
- bool _has_link = false;
+ net_device *_ndev;
+ bool _has_link = !(_ndev->state & 1UL << __LINK_STATE_NOCARRIER);
+
+ protected:
+
+ bool _send()
+ {
+ using namespace Genode;
+
+ if (!_tx.sink()->ready_to_ack())
+ return false;
+
+ if (!_tx.sink()->packet_avail())
+ return false;
+
+ Packet_descriptor packet = _tx.sink()->get_packet();
+ if (!packet.valid()) {
+ PWRN("Invalid tx packet");
+ return true;
+ }
+
+ struct sk_buff *skb = ::alloc_skb(packet.size() + HEAD_ROOM, GFP_KERNEL);
+ skb_reserve(skb, HEAD_ROOM);
+
+ unsigned char *data = skb_put(skb, packet.size());
+ Genode::memcpy(data, _tx.sink()->packet_content(packet), packet.size());
+
+ _ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
+ _tx.sink()->acknowledge_packet(packet);
+
+ return true;
+ }
+
+ void _handle_packet_stream()
+ {
+ while (_rx.source()->ack_avail())
+ _rx.source()->release_packet(_rx.source()->get_acked_packet());
+
+ while (_send()) ;
+ }
public:
- Nic_device(struct net_device *ndev) : _ndev(ndev) { }
-
- void rx(sk_buff *skb)
+ Wifi_session_component(Genode::size_t const tx_buf_size,
+ Genode::size_t const rx_buf_size,
+ Genode::Allocator &rx_block_md_alloc,
+ Genode::Ram_session &ram_session,
+ Server::Entrypoint &ep, net_device *ndev)
+ : Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep),
+ _ndev(ndev)
{
+ _ndev->lx_nic_device = this;
+ }
+
+ ~Wifi_session_component()
+ {
+ _ndev->lx_nic_device = nullptr;
+ }
+
+ /**
+ * Report link state
+ */
+ void link_state(bool link)
+ {
+ /* only report changes of the link state */
+ if (link == _has_link)
+ return;
+
+ _has_link = link;
+ _link_state_changed();
+ }
+
+ void receive(struct sk_buff *skb)
+ {
+ _handle_packet_stream();
+
+ if (!_rx.source()->ready_to_submit())
+ return;
+
/* get mac header back */
skb_push(skb, ETH_HLEN);
@@ -77,29 +146,24 @@ class Nic_device : public Nic::Device
else
packet_size += skb->len;
- _session->rx((Genode::addr_t)packet, packet_size, (Genode::addr_t)frag, frag_size);
+
+ try {
+ Nic::Packet_descriptor p = _rx.source()->alloc_packet(packet_size + frag_size);
+ void *buffer = _rx.source()->packet_content(p);
+ memcpy(buffer, packet, packet_size);
+ if (frag_size)
+ memcpy((char *)buffer + packet_size, frag, frag_size);
+
+ _rx.source()->submit_packet(p);
+ } catch (...) {
+ PDBG("failed to process received packet");
+ }
}
- /**
- * Report link state
- */
- void link_state(bool link)
- {
- /* only report changes of the link state */
- if (link == _has_link)
- return;
- _has_link = link;
-
- if (_session)
- _session->link_state_changed();
- }
-
- /**********************
- ** Device interface **
- **********************/
-
- void session(Nic::Session_component *s) override { _session = s; }
+ /*****************************
+ ** NIC-component interface **
+ *****************************/
Nic::Mac_address mac_address() override
{
@@ -109,32 +173,83 @@ class Nic_device : public Nic::Device
}
bool link_state() override { return _has_link; }
-
- bool tx(Genode::addr_t virt, Genode::size_t size) override
- {
- struct sk_buff *skb = ::alloc_skb(size + HEAD_ROOM, GFP_KERNEL);
- skb_reserve(skb, HEAD_ROOM);
-
- unsigned char *data = skb_put(skb, size);
- Genode::memcpy(data, (void*)virt, size);
-
- _ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
- return true;
- }
};
-static Nic_device *_nic = 0;
+/**
+ * NIC root implementation
+ */
+class Root : public Genode::Root_component
+{
+ private:
-static Server::Entrypoint *_ep;
+ Server::Entrypoint &_ep;
-void Lx::nic_init(Server::Entrypoint &ep) {
- _ep = &ep; }
+ protected:
+
+ Wifi_session_component *_create_session(const char *args)
+ {
+ using namespace Genode;
+
+ size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
+ size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
+ size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
+
+ /* deplete ram quota by the memory needed for the session structure */
+ size_t session_size = max(4096UL, (unsigned long)sizeof(Wifi_session_component));
+ if (ram_quota < session_size)
+ throw Genode::Root::Quota_exceeded();
+
+ /*
+ * Check if donated ram quota suffices for both communication
+ * buffers. Also check both sizes separately to handle a
+ * possible overflow of the sum of both sizes.
+ */
+ if (tx_buf_size > ram_quota - session_size
+ || rx_buf_size > ram_quota - session_size
+ || tx_buf_size + rx_buf_size > ram_quota - session_size) {
+ PERR("insufficient 'ram_quota', got %zd, need %zd",
+ ram_quota, tx_buf_size + rx_buf_size + session_size);
+ throw Genode::Root::Quota_exceeded();
+ }
+
+ session = new (md_alloc())
+ Wifi_session_component(tx_buf_size, rx_buf_size,
+ *env()->heap(),
+ *env()->ram_session(),
+ _ep, device);
+ return session;
+ }
+
+ public:
+
+ net_device *device = nullptr;
+ Wifi_session_component *session = nullptr;
+ static Root *instance;
+
+ Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
+ : Genode::Root_component(&ep.rpc_ep(), &md_alloc),
+ _ep(ep)
+ { }
+
+ void announce() { Genode::env()->parent()->announce(_ep.rpc_ep().manage(this)); }
+};
+
+
+Root *Root::instance;
+
+
+void Lx::nic_init(Server::Entrypoint &ep)
+{
+ static Root root(ep, *Genode::env()->heap());
+ Root::instance = &root;
+}
void Lx::get_mac_address(unsigned char *addr)
{
- Genode::memcpy(addr, _nic->_ndev->perm_addr, ETH_ALEN);
+ memcpy(addr, Root::instance->device->perm_addr, ETH_ALEN);
}
@@ -319,12 +434,12 @@ extern "C" void __dev_remove_pack(struct packet_type *pt)
extern "C" struct net_device *__dev_get_by_index(struct net *net, int ifindex)
{
- if (!_nic || !_nic->_ndev) {
+ if (!Root::instance->device) {
PERR("no net device registered!");
return 0;
}
- return _nic->_ndev;
+ return Root::instance->device;
}
@@ -387,18 +502,10 @@ extern "C" int register_netdevice(struct net_device *ndev)
return -ENODEV;
}
- static Nic_device nic_device(ndev);
- static Nic::Root nic_root(*_ep, Genode::env()->heap(), nic_device);
-
- /*
- * XXX This is just a starting point for removing all the static stuff from
- * this file...
- */
- ndev->lx_nic_device = (void *)&nic_device;
- _nic = &nic_device;
-
already_registered = true;
+ Root::instance->device = ndev;
+
ndev->state |= 1UL << __LINK_STATE_START;
netif_carrier_off(ndev);
@@ -424,7 +531,7 @@ extern "C" int register_netdevice(struct net_device *ndev)
if (ndev->netdev_ops->ndo_set_rx_mode)
ndev->netdev_ops->ndo_set_rx_mode(ndev);
- Genode::env()->parent()->announce(_ep->rpc_ep().manage(&nic_root));
+ Root::instance->announce();
list_add_tail_rcu(&ndev->dev_list, &init_net.dev_base_head);
@@ -451,9 +558,10 @@ extern "C" void netif_carrier_on(struct net_device *dev)
{
dev->state &= ~(1UL << __LINK_STATE_NOCARRIER);
- Nic_device *nic = (Nic_device *)dev->lx_nic_device;
+ Wifi_session_component *session = (Wifi_session_component *)dev->lx_nic_device;
- nic->link_state(true);
+ if (session)
+ session->link_state(true);
}
@@ -464,9 +572,10 @@ extern "C" void netif_carrier_off(struct net_device *dev)
dev->state |= 1UL << __LINK_STATE_NOCARRIER;
- Nic_device *nic = (Nic_device *)dev->lx_nic_device;
+ Wifi_session_component *session = (Wifi_session_component *)dev->lx_nic_device;
- nic->link_state(false);
+ if (session)
+ session->link_state(false);
}
@@ -481,14 +590,13 @@ extern "C" int netif_receive_skb(struct sk_buff *skb)
if (ntohs(skb->protocol) == ETH_P_PAE) {
/* XXX call only AF_PACKET hook */
for (Proto_hook* ph = proto_hook_list().first(); ph; ph = ph->next()) {
- ph->pt.func(skb, _nic->_ndev, &ph->pt, _nic->_ndev);
+ ph->pt.func(skb, Root::instance->device, &ph->pt, Root::instance->device);
}
return NET_RX_SUCCESS;
}
- if (_nic && _nic->_session) {
- _nic->rx(skb);
- }
+ if (Root::instance->session)
+ Root::instance->session->receive(skb);
dev_kfree_skb(skb);
return NET_RX_SUCCESS;
@@ -567,12 +675,6 @@ extern "C" struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name
}
-/**********************
- ** linux/inerrupt.h **
- **********************/
-
-
-
/*************************
** linux/etherdevice.h **
*************************/
diff --git a/repos/os/include/nic/component.h b/repos/os/include/nic/component.h
index d679985aa8..e8ae0f2e05 100644
--- a/repos/os/include/nic/component.h
+++ b/repos/os/include/nic/component.h
@@ -1,11 +1,12 @@
/*
- * \brief Glue between device-specific NIC driver code and Genode
+ * \brief Server::Entrypoint based NIC session component
* \author Norman Feske
- * \date 2011-05-21
+ * \author Sebastian Sumpf
+ * \date 2015-06-22
*/
/*
- * Copyright (C) 2011-2013 Genode Labs GmbH
+ * Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
@@ -14,101 +15,64 @@
#ifndef _INCLUDE__NIC__COMPONENT_H_
#define _INCLUDE__NIC__COMPONENT_H_
-#include
+#include
+#include
+#include
#include
-#include
-#include
-#include
-#include
-#include
-
-enum { VERBOSE_RX = false };
namespace Nic {
+ class Communication_buffers;
class Session_component;
-
- /**
- * Shortcut for single-client NIC root component
- */
- typedef Genode::Root_component
- Root_component;
-
- class Root;
}
-class Nic::Session_component : public Genode::Allocator_avl,
- public Session_rpc_object, public Rx_buffer_alloc,
- public Driver_notification
+class Nic::Communication_buffers
{
- private:
+ protected:
- Driver_factory &_driver_factory;
- Driver &_driver;
+ Nic::Packet_allocator _rx_packet_alloc;
+ Genode::Attached_ram_dataspace _tx_ds, _rx_ds;
+ Communication_buffers(Genode::Allocator &rx_block_md_alloc,
+ Genode::Ram_session &ram_session,
+ Genode::size_t tx_size, Genode::size_t rx_size)
+ :
+ _rx_packet_alloc(&rx_block_md_alloc),
+ _tx_ds(&ram_session, tx_size),
+ _rx_ds(&ram_session, rx_size)
+ { }
+};
+
+
+class Nic::Session_component : Communication_buffers, public Session_rpc_object
+{
+ protected:
+
+ Server::Entrypoint &_ep;
Genode::Signal_context_capability _link_state_sigh;
- /* rx packet descriptor */
- Genode::Packet_descriptor _curr_rx_packet;
- enum { TX_STACK_SIZE = 8*1024 };
- class Tx_thread : public Genode::Thread
+ /**
+ * Signal link-state change to client
+ */
+ void _link_state_changed()
{
- private:
-
- Tx::Sink *_tx_sink;
- Driver &_driver;
-
- public:
-
- Tx_thread(Tx::Sink *tx_sink, Driver &driver)
- :
- Genode::Thread("tx"),
- _tx_sink(tx_sink), _driver(driver)
- {
- start();
- }
-
- void entry()
- {
- using namespace Genode;
-
- while (true) {
-
- /* block for packet from client */
- Packet_descriptor packet = _tx_sink->get_packet();
- if (!packet.valid()) {
- PWRN("received invalid packet");
- continue;
- }
-
- _driver.tx(_tx_sink->packet_content(packet),
- packet.size());
-
- /* acknowledge packet to the client */
- if (!_tx_sink->ready_to_ack())
- PDBG("need to wait until ready-for-ack");
- _tx_sink->acknowledge_packet(packet);
- }
- }
- } _tx_thread;
-
- void dump()
- {
- using namespace Genode;
-
- if (!VERBOSE_RX) return;
-
- char *buf = (char *)_rx.source()->packet_content(_curr_rx_packet);
- size_t size = _curr_rx_packet.size();
-
- printf("rx packet:");
- for (unsigned i = 0; i < size; i++)
- printf("%02x,", buf[i]);
- printf("\n");
+ if (_link_state_sigh.valid())
+ Genode::Signal_transmitter(_link_state_sigh).submit();
}
+ /**
+ * Sub-classes must implement this function, it is called upon all
+ * packet-stream signals.
+ */
+ virtual void _handle_packet_stream() = 0;
+
+ void _dispatch(unsigned) { _handle_packet_stream(); }
+
+ Genode::Signal_rpc_member _packet_stream_dispatcher {
+ _ep, *this, &Session_component::_dispatch };
+
public:
/**
@@ -116,149 +80,47 @@ class Nic::Session_component : public Genode::Allocator_avl,
*
* \param tx_buf_size buffer size for tx channel
* \param rx_buf_size buffer size for rx channel
- * \param rx_block_alloc rx block allocator
+ * \param rx_block_md_alloc backing store of the meta data of the
+ * rx block allocator
+ * \param ram_session RAM session to allocate tx and rx buffers
* \param ep entry point used for packet stream
+ * channels
*/
- Session_component(Genode::size_t tx_buf_size,
- Genode::size_t rx_buf_size,
- Nic::Driver_factory &driver_factory,
- Genode::Rpc_entrypoint &ep)
+ Session_component(Genode::size_t const tx_buf_size,
+ Genode::size_t const rx_buf_size,
+ Genode::Allocator &rx_block_md_alloc,
+ Genode::Ram_session &ram_session,
+ Server::Entrypoint &ep)
:
- Genode::Allocator_avl(Genode::env()->heap()),
- Session_rpc_object(Genode::env()->ram_session()->alloc(tx_buf_size),
- Genode::env()->ram_session()->alloc(rx_buf_size),
- static_cast(this), ep),
- _driver_factory(driver_factory),
- _driver(*driver_factory.create(*this, *this)),
- _tx_thread(_tx.sink(), _driver)
- { }
-
- /**
- * Destructor
- */
- ~Session_component()
+ Communication_buffers(rx_block_md_alloc, ram_session,
+ tx_buf_size, rx_buf_size),
+ Session_rpc_object(_tx_ds.cap(),
+ _rx_ds.cap(),
+ &_rx_packet_alloc, ep.rpc_ep()),
+ _ep(ep)
{
- _driver_factory.destroy(&_driver);
+ /* install data-flow signal handlers for both packet streams */
+ _tx.sigh_ready_to_ack(_packet_stream_dispatcher);
+ _tx.sigh_packet_avail(_packet_stream_dispatcher);
+ _rx.sigh_ready_to_submit(_packet_stream_dispatcher);
+ _rx.sigh_ack_avail(_packet_stream_dispatcher);
}
- /***********************************
- ** Driver-notification interface **
- ***********************************/
-
- void link_state_changed() override
- {
- if (_link_state_sigh.valid())
- Genode::Signal_transmitter(_link_state_sigh).submit();
- }
-
- /*******************************
- ** Rx_buffer_alloc interface **
- *******************************/
-
- void *alloc(Genode::size_t size) override
- {
- /* assign rx packet descriptor */
- _curr_rx_packet = _rx.source()->alloc_packet(size);
-
- return _rx.source()->packet_content(_curr_rx_packet);
- }
-
- void submit() override
- {
- /* check for acknowledgements from the client */
- while (_rx.source()->ack_avail()) {
- Genode::Packet_descriptor packet = _rx.source()->get_acked_packet();
-
- /* free packet buffer */
- _rx.source()->release_packet(packet);
- }
-
- dump();
-
- _rx.source()->submit_packet(_curr_rx_packet);
-
- /* invalidate rx packet descriptor */
- _curr_rx_packet = Packet_descriptor();
- }
-
-
- /****************************
- ** Nic::Session interface **
- ****************************/
-
- Mac_address mac_address() { return _driver.mac_address(); }
- bool link_state() { return _driver.link_state(); }
- Tx::Sink* tx_sink() { return _tx.sink(); }
- Rx::Source* rx_source() { return _rx.source(); }
-
- void link_state_sigh(Genode::Signal_context_capability sigh) override
+ void link_state_sigh(Genode::Signal_context_capability sigh)
{
_link_state_sigh = sigh;
}
-};
-
-/*
- * Root component, handling new session requests.
- */
-class Nic::Root : public Root_component
-{
- private:
-
- Driver_factory &_driver_factory;
- Genode::Rpc_entrypoint &_ep;
-
- protected:
-
- /*
- * Always returns the singleton nic-session component.
+ /**
+ * Return the current link state
*/
- Session_component *_create_session(const char *args)
- {
- using namespace Genode;
+ virtual bool link_state() = 0;
- Genode::size_t ram_quota =
- Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
- Genode::size_t tx_buf_size =
- Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
- Genode::size_t rx_buf_size =
- Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
-
- /* delete ram quota by the memory needed for the session */
- Genode::size_t session_size = max((Genode::size_t)4096, sizeof(Session_component)
- + sizeof(Allocator_avl));
- if (ram_quota < session_size)
- throw Root::Quota_exceeded();
-
- /*
- * Check if donated ram quota suffices for both
- * communication buffers. Also check both sizes separately
- * to handle a possible overflow of the sum of both sizes.
- */
- if (tx_buf_size > ram_quota - session_size
- || rx_buf_size > ram_quota - session_size
- || tx_buf_size + rx_buf_size > ram_quota - session_size) {
- PERR("insufficient 'ram_quota', got %zd, need %zd",
- ram_quota, tx_buf_size + rx_buf_size + session_size);
- throw Root::Quota_exceeded();
- }
-
- return new (md_alloc()) Session_component(tx_buf_size,
- rx_buf_size,
- _driver_factory,
- _ep);
- }
-
- public:
-
- Root(Genode::Rpc_entrypoint *session_ep,
- Genode::Allocator *md_alloc,
- Nic::Driver_factory &driver_factory)
- :
- Root_component(session_ep, md_alloc),
- _driver_factory(driver_factory),
- _ep(*session_ep)
- { }
+ /**
+ * Return the MAC address of the device
+ */
+ virtual Mac_address mac_address() = 0;
};
+
#endif /* _INCLUDE__NIC__COMPONENT_H_ */
diff --git a/repos/os/include/nic/driver.h b/repos/os/include/nic/driver.h
deleted file mode 100644
index cdebf968aa..0000000000
--- a/repos/os/include/nic/driver.h
+++ /dev/null
@@ -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 /* for 'Genode::Irq_handler' type */
-#include /* 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_ */
diff --git a/repos/os/include/nic/root.h b/repos/os/include/nic/root.h
new file mode 100644
index 0000000000..7417170872
--- /dev/null
+++ b/repos/os/include/nic/root.h
@@ -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
+#include
+
+namespace Nic {
+
+ template class Root;
+};
+
+
+template
+class Nic::Root : public Genode::Root_component
+{
+ 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(&ep.rpc_ep(), &md_alloc),
+ _ep(ep)
+ { }
+};
+
+#endif /* _INCLUDE__NIC__ROOT_H_ */
diff --git a/repos/os/src/drivers/nic/lan9118/lan9118.h b/repos/os/src/drivers/nic/lan9118/lan9118.h
index 40abc3cc2f..92ac1f9f16 100644
--- a/repos/os/src/drivers/nic/lan9118/lan9118.h
+++ b/repos/os/src/drivers/nic/lan9118/lan9118.h
@@ -19,9 +19,10 @@
#include
#include
#include
-#include
+#include
-class Lan9118 : public Nic::Driver
+class Lan9118 : public Nic::Session_component,
+ public Genode::Irq_handler
{
private:
@@ -70,9 +71,7 @@ class Lan9118 : public Nic::Driver
Genode::Attached_io_mem_dataspace _mmio;
volatile Genode::uint32_t *_reg_base;
Timer::Connection _timer;
- Nic::Rx_buffer_alloc &_rx_buffer_alloc;
Nic::Mac_address _mac_addr;
- Nic::Driver_notification &_notify;
enum { IRQ_STACK_SIZE = 4096 };
Genode::Irq_activation _irq_activation;
@@ -189,6 +188,67 @@ class Lan9118 : public Nic::Driver
return _reg_read(RX_FIFO_INF) & 0xffff;
}
+ protected:
+
+ bool _send()
+ {
+ if (!_tx.sink()->ready_to_ack())
+ return false;
+
+ if (!_tx.sink()->packet_avail())
+ return false;
+
+ Genode::Packet_descriptor packet = _tx.sink()->get_packet();
+ if (!packet.valid()) {
+ PWRN("Invalid tx packet");
+ return true;
+ }
+
+ /* limit size to 11 bits, the maximum supported by lan9118 */
+ enum { MAX_PACKET_SIZE_LOG2 = 11 };
+ Genode::size_t const max_size = (1 << MAX_PACKET_SIZE_LOG2) - 1;
+ if (packet.size() > max_size) {
+ PERR("packet size %zd too large, limit is %zd", packet.size(), max_size);
+ return true;
+ }
+
+ enum { FIRST_SEG = (1 << 13),
+ LAST_SEG = (1 << 12) };
+
+ Genode::uint32_t const cmd_a = packet.size() | FIRST_SEG | LAST_SEG,
+ cmd_b = packet.size();
+
+ unsigned count = Genode::align_addr(packet.size(), 2) >> 2;
+ Genode::uint32_t *src = (Genode::uint32_t *)_tx.sink()->packet_content(packet);
+
+ /* check space left in tx data fifo */
+ Genode::size_t const fifo_avail = _reg_read(TX_FIFO_INF) & 0xffff;
+ if (fifo_avail < count*4 + sizeof(cmd_a) + sizeof(cmd_b)) {
+ PERR("tx fifo overrun, ignore packet");
+ _tx.sink()->acknowledge_packet(packet);
+ return false;
+ }
+
+ _reg_write(TX_DATA_FIFO, cmd_a);
+ _reg_write(TX_DATA_FIFO, cmd_b);
+
+ /* supply payload to transmit fifo */
+ for (; count--; src++)
+ _reg_write(TX_DATA_FIFO, *src);
+
+ _tx.sink()->acknowledge_packet(packet);
+ return true;
+ }
+
+ void _handle_packet_stream() override
+ {
+ while (_rx.source()->ack_avail())
+ _rx.source()->release_packet(_rx.source()->get_acked_packet());
+
+ while (_send()) ;
+ }
+
+
public:
/**
@@ -202,13 +262,14 @@ class Lan9118 : public Nic::Driver
* \throw Device_not_supported
*/
Lan9118(Genode::addr_t mmio_base, Genode::size_t mmio_size, int irq,
- Nic::Rx_buffer_alloc &rx_buffer_alloc,
- Nic::Driver_notification ¬ify)
- :
+ Genode::size_t const tx_buf_size,
+ Genode::size_t const rx_buf_size,
+ Genode::Allocator &rx_block_md_alloc,
+ Genode::Ram_session &ram_session,
+ Server::Entrypoint &ep)
+ : Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep),
_mmio(mmio_base, mmio_size),
_reg_base(_mmio.local_addr()),
- _rx_buffer_alloc(rx_buffer_alloc),
- _notify(notify),
_irq_activation(irq, *this, IRQ_STACK_SIZE)
{
unsigned long const id_rev = _reg_read(ID_REV),
@@ -290,58 +351,21 @@ class Lan9118 : public Nic::Driver
_mac_csr_write(MAC_CR, 0);
}
- void link_state_changed() { _notify.link_state_changed(); }
+ /**************************************
+ ** Nic::Session_component interface **
+ **************************************/
-
- /***************************
- ** Nic::Driver interface **
- ***************************/
-
- Nic::Mac_address mac_address()
+ Nic::Mac_address mac_address() override
{
return _mac_addr;
}
- bool link_state()
+ bool link_state() override
{
/* XXX always return true for now */
return true;
}
- void tx(char const *packet, Genode::size_t size)
- {
- /* limit size to 11 bits, the maximum supported by lan9118 */
- enum { MAX_PACKET_SIZE_LOG2 = 11 };
- Genode::size_t const max_size = (1 << MAX_PACKET_SIZE_LOG2) - 1;
- if (size > max_size) {
- PERR("packet size %zd too large, limit is %zd", size, max_size);
- return;
- }
-
- enum { FIRST_SEG = (1 << 13),
- LAST_SEG = (1 << 12) };
-
- Genode::uint32_t const cmd_a = size | FIRST_SEG | LAST_SEG,
- cmd_b = size;
-
- unsigned count = Genode::align_addr(size, 2) >> 2;
- Genode::uint32_t *src = (Genode::uint32_t *)packet;
-
- /* check space left in tx data fifo */
- Genode::size_t const fifo_avail = _reg_read(TX_FIFO_INF) & 0xffff;
- if (fifo_avail < count*4 + sizeof(cmd_a) + sizeof(cmd_b)) {
- PERR("tx fifo overrun, ignore packet");
- return;
- }
-
- _reg_write(TX_DATA_FIFO, cmd_a);
- _reg_write(TX_DATA_FIFO, cmd_b);
-
- /* supply payload to transmit fifo */
- for (; count--; src++)
- _reg_write(TX_DATA_FIFO, *src);
- }
-
/******************************
** Irq_activation interface **
@@ -351,7 +375,9 @@ class Lan9118 : public Nic::Driver
{
using namespace Genode;
- while (_rx_packet_avail()) {
+ _handle_packet_stream();
+
+ while (_rx_packet_avail() && _rx.source()->ready_to_submit()) {
/* read packet from NIC, copy to client buffer */
Rx_packet_info packet = _rx_packet_info();
@@ -360,7 +386,12 @@ class Lan9118 : public Nic::Driver
size_t const size = align_addr(packet.size, 2);
/* allocate rx packet buffer */
- uint32_t *dst = (uint32_t *)_rx_buffer_alloc.alloc(size);
+ Nic::Packet_descriptor p;
+ try {
+ p = _rx.source()->alloc_packet(size);
+ } catch (Session::Rx::Source::Packet_alloc_failed) { return; }
+
+ uint32_t *dst = (uint32_t *)_rx.source()->packet_content(p);
/* calculate number of words to be read from rx fifo */
size_t count = min(size, _rx_data_pending()) >> 2;
@@ -369,7 +400,7 @@ class Lan9118 : public Nic::Driver
for (; count--; )
*dst++ = _reg_read(RX_DATA_FIFO);
- _rx_buffer_alloc.submit();
+ _rx.source()->submit_packet(p);
}
/* acknowledge all pending irqs */
diff --git a/repos/os/src/drivers/nic/lan9118/main.cc b/repos/os/src/drivers/nic/lan9118/main.cc
index 1caa92c701..2099cbb081 100644
--- a/repos/os/src/drivers/nic/lan9118/main.cc
+++ b/repos/os/src/drivers/nic/lan9118/main.cc
@@ -18,6 +18,8 @@
#include
#include
#include
+#include
+#include
/* device definitions */
#include
@@ -25,39 +27,80 @@
/* driver code */
#include
+namespace Server { struct Main; }
-int main(int, char **)
+class Root : public Genode::Root_component
{
- using namespace Genode;
+ private:
- printf("--- LAN9118 NIC driver started ---\n");
+ Server::Entrypoint &_ep;
- /**
- * Factory used by 'Nic::Root' at session creation/destruction time
- */
- struct Lan9118_driver_factory : Nic::Driver_factory
+ protected:
+
+ Lan9118 *_create_session(const char *args)
+ {
+ using namespace Genode;
+
+ size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
+ size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
+ size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
+
+ /* deplete ram quota by the memory needed for the session structure */
+ size_t session_size = max(4096UL, (unsigned long)sizeof(Lan9118));
+ if (ram_quota < session_size)
+ throw Genode::Root::Quota_exceeded();
+
+ /*
+ * Check if donated ram quota suffices for both communication
+ * buffers. Also check both sizes separately to handle a
+ * possible overflow of the sum of both sizes.
+ */
+ if (tx_buf_size > ram_quota - session_size
+ || rx_buf_size > ram_quota - session_size
+ || tx_buf_size + rx_buf_size > ram_quota - session_size) {
+ PERR("insufficient 'ram_quota', got %zd, need %zd",
+ ram_quota, tx_buf_size + rx_buf_size + session_size);
+ throw Genode::Root::Quota_exceeded();
+ }
+
+ return new (Root::md_alloc())
+ Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ,
+ tx_buf_size, rx_buf_size,
+ *env()->heap(),
+ *env()->ram_session(),
+ _ep);
+ }
+
+ public:
+
+ Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
+ : Genode::Root_component(&ep.rpc_ep(), &md_alloc),
+ _ep(ep)
+ { }
+};
+
+struct Server::Main
+{
+ Entrypoint &ep;
+ ::Root nic_root{ ep, *Genode::env()->heap() };
+
+ Main(Entrypoint &ep) : ep(ep)
{
- Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
- Nic::Driver_notification ¬ify)
- {
- return new (env()->heap())
- Lan9118(LAN9118_PHYS, LAN9118_SIZE, LAN9118_IRQ, alloc, notify);
- }
+ printf("--- LAN9118 NIC driver started ---\n");
+ Genode::env()->parent()->announce(ep.manage(nic_root));
+ }
+};
- void destroy(Nic::Driver *driver)
- {
- Genode::destroy(env()->heap(), static_cast(driver));
- }
- } driver_factory;
+namespace Server {
- enum { STACK_SIZE = 4096 };
- static Cap_connection cap;
- static Rpc_entrypoint ep(&cap, STACK_SIZE, "nic_ep");
+ char const *name() { return "nic_ep"; }
- static Nic::Root nic_root(&ep, env()->heap(), driver_factory);
- env()->parent()->announce(ep.manage(&nic_root));
+ size_t stack_size() { return 2*1024*sizeof(long); }
- Genode::sleep_forever();
- return 0;
+ void construct(Entrypoint &ep)
+ {
+ static Main main(ep);
+ }
}
+
diff --git a/repos/os/src/drivers/nic/lan9118/target.mk b/repos/os/src/drivers/nic/lan9118/target.mk
index 5e8635fe9c..34d51e6eab 100644
--- a/repos/os/src/drivers/nic/lan9118/target.mk
+++ b/repos/os/src/drivers/nic/lan9118/target.mk
@@ -1,5 +1,5 @@
REQUIRES = lan9118
TARGET = nic_drv
SRC_CC = main.cc
-LIBS = base
+LIBS = base server
INC_DIR += $(PRG_DIR)
diff --git a/repos/os/src/drivers/nic/linux/main.cc b/repos/os/src/drivers/nic/linux/main.cc
index b7213de2f6..1111c0b48d 100644
--- a/repos/os/src/drivers/nic/linux/main.cc
+++ b/repos/os/src/drivers/nic/linux/main.cc
@@ -2,6 +2,7 @@
* \brief NIC driver for Linux TUN/TAP device
* \author Stefan Kalkowski
* \author Christian Helmuth
+ * \author Sebastian Sumpf
* \date 2011-08-08
*
* Configuration options are:
@@ -23,9 +24,8 @@
*/
/* Genode */
-#include
-#include
-#include
+#include
+#include
#include
#include
@@ -37,18 +37,20 @@
#include
#include
+namespace Server { struct Main; }
-class Linux_driver : public Nic::Driver
+
+class Linux_session_component : public Nic::Session_component
{
private:
- struct Rx_thread : Genode::Thread<0x2000>
+ struct Rx_signal_thread : Genode::Thread<0x1000>
{
- int fd;
- Nic::Driver &driver;
+ int fd;
+ Genode::Signal_context_capability sigh;
- Rx_thread(int fd, Nic::Driver &driver)
- : Genode::Thread<0x2000>("rx"), fd(fd), driver(driver) { }
+ Rx_signal_thread(int fd, Genode::Signal_context_capability sigh)
+ : Genode::Thread<0x1000>("rx_signal"), fd(fd), sigh(sigh) { }
void entry()
{
@@ -61,19 +63,15 @@ class Linux_driver : public Nic::Driver
FD_SET(fd, &rfds);
do { ret = select(fd + 1, &rfds, 0, 0, 0); } while (ret < 0);
- /* inform driver about incoming packet */
- driver.handle_irq(fd);
+ /* signal incoming packet */
+ Genode::Signal_transmitter(sigh).submit();
}
}
};
- Nic::Mac_address _mac_addr;
- Nic::Rx_buffer_alloc &_alloc;
- Nic::Driver_notification &_notify;
-
- char _packet_buffer[1514]; /* maximum ethernet packet length */
- int _tap_fd;
- Rx_thread _rx_thread;
+ Nic::Mac_address _mac_addr;
+ int _tap_fd;
+ Rx_signal_thread _rx_thread;
int _setup_tap_fd()
{
@@ -88,6 +86,12 @@ class Linux_driver : public Nic::Driver
throw Genode::Exception();
}
+ /* set fd to non-blocking */
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
+ PERR("could not set /dev/net/tun to non-blocking");
+ throw Genode::Exception();
+ }
+
Genode::memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
@@ -113,13 +117,85 @@ class Linux_driver : public Nic::Driver
return fd;
}
+ bool _send()
+ {
+ using namespace Genode;
+
+ if (!_tx.sink()->ready_to_ack())
+ return false;
+
+ if (!_tx.sink()->packet_avail())
+ return false;
+
+ Packet_descriptor packet = _tx.sink()->get_packet();
+ if (!packet.valid()) {
+ PWRN("Invalid tx packet");
+ return true;
+ }
+
+ int ret;
+
+ /* non-blocking-write packet to TAP */
+ do {
+ ret = write(_tap_fd, _tx.sink()->packet_content(packet), packet.size());
+ /* drop packet if write would block */
+ if (ret < 0 && errno == EAGAIN)
+ continue;
+
+ if (ret < 0) PERR("write: errno=%d", errno);
+ } while (ret < 0);
+
+ _tx.sink()->acknowledge_packet(packet);
+
+ return true;
+ }
+
+ bool _receive()
+ {
+ unsigned const max_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE;
+
+ if (!_rx.source()->ready_to_submit())
+ return false;
+
+ Nic::Packet_descriptor p;
+ try {
+ p = _rx.source()->alloc_packet(max_size);
+ } catch (Session::Rx::Source::Packet_alloc_failed) { return false; }
+
+ int size = read(_tap_fd, _rx.source()->packet_content(p), max_size);
+ if (size <= 0) {
+ _rx.source()->release_packet(p);
+ return false;
+ }
+
+ /* adjust packet size */
+ Nic::Packet_descriptor p_adjust(p.offset(), size);
+ _rx.source()->submit_packet(p_adjust);
+
+ return true;
+ }
+
+ protected:
+
+ void _handle_packet_stream() override
+ {
+ while (_rx.source()->ack_avail())
+ _rx.source()->release_packet(_rx.source()->get_acked_packet());
+
+ while (_send()) ;
+ while (_receive()) ;
+ }
+
public:
- Linux_driver(Nic::Rx_buffer_alloc &alloc,
- Nic::Driver_notification ¬ify)
+ Linux_session_component(Genode::size_t const tx_buf_size,
+ Genode::size_t const rx_buf_size,
+ Genode::Allocator &rx_block_md_alloc,
+ Genode::Ram_session &ram_session,
+ Server::Entrypoint &ep)
:
- _alloc(alloc), _notify(notify),
- _tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, *this)
+ Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep),
+ _tap_fd(_setup_tap_fd()), _rx_thread(_tap_fd, _packet_stream_dispatcher)
{
/* try using configured MAC address */
try {
@@ -145,93 +221,23 @@ class Linux_driver : public Nic::Driver
_rx_thread.start();
}
- void link_state_changed() { _notify.link_state_changed(); }
-
-
- /***************************
- ** Nic::Driver interface **
- ***************************/
-
- Nic::Mac_address mac_address() { return _mac_addr; }
-
- bool link_state()
- {
- /* XXX return always true for now */
- return true;
- }
-
- void tx(char const *packet, Genode::size_t size)
- {
- int ret;
-
- /* blocking-write packet to TAP */
- do {
- ret = write(_tap_fd, packet, size);
- if (ret < 0) PERR("write: errno=%d", errno);
- } while (ret < 0);
- }
-
-
- /******************************
- ** Irq_activation interface **
- ******************************/
-
- void handle_irq(int)
- {
- int ret;
-
- /* blocking read incoming packet */
- do {
- ret = read(_tap_fd, _packet_buffer, sizeof(_packet_buffer));
- if (ret < 0) PERR("read: errno=%d", errno);
- } while (ret < 0);
-
- void *buffer = _alloc.alloc(ret);
- Genode::memcpy(buffer, _packet_buffer, ret);
- _alloc.submit();
- }
+ bool link_state() override { return true; }
+ Nic::Mac_address mac_address() override { return _mac_addr; }
};
-/*
- * Manually initialize the 'lx_environ' pointer, needed because 'nic_drv' is not
- * using the normal Genode startup code.
- */
-extern char **environ;
-char **lx_environ = environ;
-
-
-int main(int, char **)
+struct Server::Main
{
- using namespace Genode;
+ Entrypoint &ep;
+ Nic::Root nic_root{ ep, *Genode::env()->heap() };
- printf("--- Linux/tap NIC driver started ---\n");
-
- /**
- * Factory used by 'Nic::Root' at session creation/destruction time
- */
- struct Linux_driver_factory : Nic::Driver_factory
+ Main(Entrypoint &ep) : ep(ep)
{
- Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
- Nic::Driver_notification ¬ify)
- {
- return new (env()->heap()) Linux_driver(alloc, notify);
- }
+ Genode::env()->parent()->announce(ep.manage(nic_root));
+ }
+};
- void destroy(Nic::Driver *driver)
- {
- Genode::destroy(env()->heap(), static_cast(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); }
diff --git a/repos/os/src/drivers/nic/linux/target.mk b/repos/os/src/drivers/nic/linux/target.mk
index 953ce5e00b..d76d0fc993 100644
--- a/repos/os/src/drivers/nic/linux/target.mk
+++ b/repos/os/src/drivers/nic/linux/target.mk
@@ -1,4 +1,4 @@
TARGET = nic_drv
REQUIRES = linux
-LIBS = lx_hybrid config
+LIBS = lx_hybrid config server
SRC_CC = main.cc
diff --git a/repos/os/src/server/nic_loopback/main.cc b/repos/os/src/server/nic_loopback/main.cc
index 14616d7778..0e1a377947 100644
--- a/repos/os/src/server/nic_loopback/main.cc
+++ b/repos/os/src/server/nic_loopback/main.cc
@@ -15,19 +15,16 @@
#include
#include
-#include
#include
-#include
#include
#include
#include
-#include
-#include
+#include
+#include
namespace Nic {
- class Communication_buffers;
- class Session_component;
+ class Loopback_component;
class Root;
}
@@ -35,36 +32,8 @@ namespace Nic {
namespace Server { struct Main; }
-class Nic::Communication_buffers
+class Nic::Loopback_component : public Nic::Session_component
{
- protected:
-
- Genode::Allocator_avl _rx_packet_alloc;
-
- Genode::Attached_ram_dataspace _tx_ds, _rx_ds;
-
- Communication_buffers(Genode::Allocator &rx_block_md_alloc,
- Genode::Ram_session &ram_session,
- Genode::size_t tx_size, Genode::size_t rx_size)
- :
- _rx_packet_alloc(&rx_block_md_alloc),
- _tx_ds(&ram_session, tx_size),
- _rx_ds(&ram_session, rx_size)
- { }
-};
-
-
-class Nic::Session_component : Communication_buffers, public Session_rpc_object
-{
- private:
-
- Server::Entrypoint &_ep;
-
- void _handle_packet_stream(unsigned);
-
- Genode::Signal_rpc_member _packet_stream_dispatcher {
- _ep, *this, &Session_component::_handle_packet_stream };
-
public:
/**
@@ -78,46 +47,37 @@ class Nic::Session_component : Communication_buffers, public Session_rpc_object
* \param ep entry point used for packet stream
* channels
*/
- Session_component(Genode::size_t const tx_buf_size,
- Genode::size_t const rx_buf_size,
- Genode::Allocator &rx_block_md_alloc,
- Genode::Ram_session &ram_session,
- Server::Entrypoint &ep)
- :
- Communication_buffers(rx_block_md_alloc, ram_session,
- tx_buf_size, rx_buf_size),
- Session_rpc_object(this->_tx_ds.cap(),
- this->_rx_ds.cap(),
- &this->_rx_packet_alloc, ep.rpc_ep()),
- _ep(ep)
- {
- /* install data-flow signal handlers for both packet streams */
- _tx.sigh_ready_to_ack(_packet_stream_dispatcher);
- _tx.sigh_packet_avail(_packet_stream_dispatcher);
- _rx.sigh_ready_to_submit(_packet_stream_dispatcher);
- _rx.sigh_ack_avail(_packet_stream_dispatcher);
- }
+ Loopback_component(Genode::size_t const tx_buf_size,
+ Genode::size_t const rx_buf_size,
+ Genode::Allocator &rx_block_md_alloc,
+ Genode::Ram_session &ram_session,
+ Server::Entrypoint &ep)
+ : Session_component(tx_buf_size, rx_buf_size,
+ rx_block_md_alloc, ram_session, ep)
+ { }
- Mac_address mac_address()
+ Mac_address mac_address() override
{
Mac_address result = {{1,2,3,4,5,6}};
return result;
}
- bool link_state()
+ bool link_state() override
{
/* XXX always return true, for now */
return true;
}
- void link_state_sigh(Genode::Signal_context_capability sigh) { }
+ void _handle_packet_stream() override;
};
-void Nic::Session_component::_handle_packet_stream(unsigned)
+void Nic::Loopback_component::_handle_packet_stream()
{
using namespace Genode;
+ unsigned const alloc_size = Nic::Packet_allocator::DEFAULT_PACKET_SIZE;
+
/* loop unless we cannot make any progress */
for (;;) {
@@ -154,35 +114,36 @@ void Nic::Session_component::_handle_packet_stream(unsigned)
* We are safe to process one packet without blocking.
*/
+
+ Packet_descriptor packet_to_client;
+ try {
+ packet_to_client = _rx.source()->alloc_packet(alloc_size);
+ } catch (Session::Rx::Source::Packet_alloc_failed) {
+ continue;
+ }
+
/* obtain packet */
Packet_descriptor const packet_from_client = _tx.sink()->get_packet();
if (!packet_from_client.valid()) {
PWRN("received invalid packet");
+ _rx.source()->release_packet(packet_to_client);
continue;
}
- try {
- size_t const packet_size = packet_from_client.size();
-
- Packet_descriptor const packet_to_client =
- _rx.source()->alloc_packet(packet_size);
-
Genode::memcpy(_rx.source()->packet_content(packet_to_client),
_tx.sink()->packet_content(packet_from_client),
- packet_size);
+ packet_from_client.size());
+ packet_to_client = Packet_descriptor(packet_to_client.offset(), packet_from_client.size());
_rx.source()->submit_packet(packet_to_client);
- } catch (Session::Rx::Source::Packet_alloc_failed) {
- PWRN("transmit packet allocation failed, drop packet");
- }
_tx.sink()->acknowledge_packet(packet_from_client);
}
}
-class Nic::Root : public Genode::Root_component
+class Nic::Root : public Genode::Root_component
{
private:
@@ -190,7 +151,7 @@ class Nic::Root : public Genode::Root_component
protected:
- Session_component *_create_session(const char *args)
+ Loopback_component*_create_session(const char *args)
{
using namespace Genode;
@@ -216,7 +177,7 @@ class Nic::Root : public Genode::Root_component
throw Root::Quota_exceeded();
}
- return new (md_alloc()) Session_component(tx_buf_size, rx_buf_size,
+ return new (md_alloc()) Loopback_component(tx_buf_size, rx_buf_size,
*env()->heap(),
*env()->ram_session(),
_ep);
@@ -226,7 +187,7 @@ class Nic::Root : public Genode::Root_component
Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
:
- Genode::Root_component(&ep.rpc_ep(), &md_alloc),
+ Genode::Root_component(&ep.rpc_ep(), &md_alloc),
_ep(ep)
{ }
};
diff --git a/repos/ports/src/app/openvpn/main.cc b/repos/ports/src/app/openvpn/main.cc
index 2b14aca824..c7852918a0 100644
--- a/repos/ports/src/app/openvpn/main.cc
+++ b/repos/ports/src/app/openvpn/main.cc
@@ -82,14 +82,12 @@ Tuntap_device *tuntap_dev()
** Implementation of the Nic service **
***************************************/
-class Nic_driver : public Tuntap_device,
- public Nic::Driver
+class Openvpn_component : public Tuntap_device,
+ public Nic::Session_component
{
private:
Nic::Mac_address _mac_addr {{ 0x02, 0x00, 0x00, 0x00, 0x00, 0x01 }};
- Nic::Rx_buffer_alloc &_alloc;
- Nic::Driver_notification &_notify;
char const *_packet;
@@ -99,12 +97,52 @@ class Nic_driver : public Tuntap_device,
Genode::Semaphore _startup_lock;
Genode::Semaphore _tx_lock;
+ protected:
+
+ bool _send()
+ {
+ using namespace Genode;
+
+ if (!_tx.sink()->ready_to_ack())
+ return false;
+
+ if (!_tx.sink()->packet_avail())
+ return false;
+
+ Packet_descriptor packet = _tx.sink()->get_packet();
+ if (!packet.valid()) {
+ PWRN("Invalid tx packet");
+ return true;
+ }
+
+ _packet = _tx.sink()->packet_content(packet);
+
+ /* notify openvpn */
+ ::write(_pipefd[WRITE], "1", 1);
+
+ /* block while openvpn handles the packet */
+ _tx_lock.down();
+ _tx.sink()->acknowledge_packet(packet);
+
+ return true;
+ }
+
+ void _handle_packet_stream() override
+ {
+ while (_rx.source()->ack_avail())
+ _rx.source()->release_packet(_rx.source()->get_acked_packet());
+
+ while (_send()) ;
+ }
public:
- Nic_driver(Nic::Rx_buffer_alloc &alloc, Nic::Driver_notification ¬ify)
- :
- _alloc(alloc), _notify(notify), _packet(0)
+ Openvpn_component(Genode::size_t const tx_buf_size,
+ Genode::size_t const rx_buf_size,
+ Genode::Allocator &rx_block_md_alloc,
+ Genode::Ram_session &ram_session,
+ Server::Entrypoint &ep)
+ : Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, ram_session, ep)
{
if (pipe(_pipefd)) {
PERR("could not create pipe");
@@ -112,41 +150,18 @@ class Nic_driver : public Tuntap_device,
}
}
- ~Nic_driver() { PDBG("should probably be implemented"); }
+ /**************************************
+ ** Nic::Session_component interface **
+ **************************************/
- void link_state_changed() { _notify.link_state_changed(); }
+ Nic::Mac_address mac_address() override { return _mac_addr; }
- /***************************
- ** Nic::Driver interface **
- ***************************/
-
- Nic::Mac_address mac_address() { return _mac_addr; }
-
- bool link_state()
+ bool link_state() override
{
/* XXX always return true for now */
return true;
}
- void tx(char const *packet, Genode::size_t size)
- {
- PDBGV("packet:0x%p size:%zu", packet, size);
-
- _packet = packet;
-
- /* notify openvpn */
- ::write(_pipefd[WRITE], "1", 1);
-
- /* block while openvpn handles the packet */
- _tx_lock.down();
- }
-
- /******************************
- ** Irq_activation interface **
- ******************************/
-
- void handle_irq(int) { }
-
/***********************
** TUN/TAP interface **
***********************/
@@ -171,10 +186,16 @@ class Nic_driver : public Tuntap_device,
int write(char const *buf, Genode::size_t len)
{
PDBGV("buf:0x%p len:%zu", len);
+ _handle_packet_stream();
- void *buffer = _alloc.alloc(len);
- Genode::memcpy(buffer, buf, len);
- _alloc.submit();
+ if (!_rx.source()->ready_to_submit())
+ return 0;
+
+ try {
+ Genode::Packet_descriptor packet = _rx.source()->alloc_packet(len);
+ Genode::memcpy(_rx.source()->packet_content(packet), buf, len);
+ _rx.source()->submit_packet(packet);
+ } catch (...) { return 0; }
return len;
}
@@ -185,57 +206,86 @@ class Nic_driver : public Tuntap_device,
};
-struct Main
+class Root : public Genode::Root_component
{
- struct Nic_driver_factory : Nic::Driver_factory
- {
- Nic_driver *drv { 0 };
- Openvpn_thread *openvpn { 0 };
+ private:
- Nic::Driver *create(Nic::Rx_buffer_alloc &alloc,
- Nic::Driver_notification ¬ify)
+ Server::Entrypoint &_ep;
+ Openvpn_thread *_thread = nullptr;
+
+ protected:
+
+ Openvpn_component *_create_session(const char *args)
{
- /* there can be only one */
- if (!drv) {
- drv = new (Genode::env()->heap()) Nic_driver(alloc, notify);
+ using namespace Genode;
- /**
- * Setting the pointer in this manner is quite hackish but it has
- * to be valid before OpenVPN calls open_tun(), which unfortunatly
- * is early.
- */
- _tuntap_dev = drv;
+ size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
+ size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
+ size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
- PDBGV("start OpenVPN main thread");
- Openvpn_thread *openvpn = new (Genode::env()->heap()) Openvpn_thread(genode_argc,
- genode_argv);
+ /* deplete ram quota by the memory needed for the session structure */
+ size_t session_size = max(4096UL, (unsigned long)sizeof(Openvpn_component));
+ if (ram_quota < session_size)
+ throw Genode::Root::Quota_exceeded();
- openvpn->start();
-
- /* wait until OpenVPN configured the TUN/TAP device for the first time */
- _tuntap_dev->down();
-
- return drv;
+ /*
+ * Check if donated ram quota suffices for both communication
+ * buffers. Also check both sizes separately to handle a
+ * possible overflow of the sum of both sizes.
+ */
+ if (tx_buf_size > ram_quota - session_size
+ || rx_buf_size > ram_quota - session_size
+ || tx_buf_size + rx_buf_size > ram_quota - session_size) {
+ PERR("insufficient 'ram_quota', got %zd, need %zd",
+ ram_quota, tx_buf_size + rx_buf_size + session_size);
+ throw Genode::Root::Quota_exceeded();
}
- return 0;
+ Openvpn_component *component = new (Root::md_alloc())
+ Openvpn_component(tx_buf_size, rx_buf_size,
+ *env()->heap(),
+ *env()->ram_session(),
+ _ep);
+ /**
+ * Setting the pointer in this manner is quite hackish but it has
+ * to be valid before OpenVPN calls open_tun(), which unfortunatly
+ * is early.
+ */
+ _tuntap_dev = component;
+
+ PDBGV("start OpenVPN main thread");
+ _thread = new (Genode::env()->heap()) Openvpn_thread(genode_argc, genode_argv);
+ _thread->start();
+
+ /* wait until OpenVPN configured the TUN/TAP device for the first time */
+ _tuntap_dev->down();
+
+ return component;
}
- void destroy(Nic::Driver *driver)
+ void _destroy_session(Openvpn_component *session)
{
- Genode::destroy(Genode::env()->heap(), static_cast(driver));
- drv = 0;
- Genode::destroy(Genode::env()->heap(), openvpn);
- openvpn = 0;
+ Genode::destroy(Root::md_alloc(), session);
+ Genode::destroy(Root::md_alloc(), _thread);
+ _thread = nullptr;
}
- } driver_factory;
+ public:
+
+ Root(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
+ : Genode::Root_component(&ep.rpc_ep(), &md_alloc),
+ _ep(ep)
+ { }
+};
+
+
+struct Main
+{
Server::Entrypoint &ep;
+ ::Root nic_root { ep, *Genode::env()->heap() };
Main(Server::Entrypoint &ep) : ep(ep)
{
- static Nic::Root nic_root(&ep.rpc_ep(), Genode::env()->heap(), driver_factory);
-
Genode::env()->parent()->announce(ep.manage(nic_root));
}
};