193 lines
4.4 KiB
C++
193 lines
4.4 KiB
C++
/*
|
|
* \brief Linux emulation code
|
|
* \author Sebastian Sumpf
|
|
* \author Josef Soentgen
|
|
* \author Emery Hemingway
|
|
* \date 2013-08-28
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2013-2017 Genode Labs GmbH
|
|
*
|
|
* This file is distributed under the terms of the GNU General Public License
|
|
* version 2.
|
|
*/
|
|
|
|
/* Genode includes */
|
|
#include <base/log.h>
|
|
#include <nic/packet_allocator.h>
|
|
#include <nic_session/connection.h>
|
|
|
|
/* local includes */
|
|
#include <lx.h>
|
|
#include <nic.h>
|
|
|
|
bool ic_link_state = false;
|
|
|
|
|
|
class Nic_client
|
|
{
|
|
private:
|
|
|
|
enum {
|
|
PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
|
|
BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE,
|
|
};
|
|
|
|
Nic::Packet_allocator _tx_block_alloc;
|
|
Nic::Connection _nic;
|
|
|
|
Genode::Io_signal_handler<Nic_client> _sink_ack;
|
|
Genode::Io_signal_handler<Nic_client> _sink_submit;
|
|
Genode::Io_signal_handler<Nic_client> _source_ack;
|
|
Genode::Io_signal_handler<Nic_client> _link_state_change;
|
|
|
|
void (*_tick)();
|
|
|
|
void _link_state()
|
|
{
|
|
bool const link_state = _nic.link_state();
|
|
ic_link_state = link_state;
|
|
|
|
if (link_state == false || lxip_do_dhcp() == false)
|
|
return;
|
|
|
|
Lx::timer_update_jiffies();
|
|
|
|
/* reconnect dhcp client */
|
|
lxip_configure_dhcp();
|
|
}
|
|
|
|
/**
|
|
* submit queue not empty anymore
|
|
*/
|
|
void _packet_avail()
|
|
{
|
|
Lx::timer_update_jiffies();
|
|
|
|
/* process a batch of only MAX_PACKETS in one run */
|
|
enum { MAX_PACKETS = 20 };
|
|
|
|
int count = 0;
|
|
while (_nic.rx()->packet_avail() &&
|
|
_nic.rx()->ready_to_ack() &&
|
|
count++ < MAX_PACKETS)
|
|
{
|
|
Nic::Packet_descriptor p = _nic.rx()->get_packet();
|
|
try { net_driver_rx(_nic.rx()->packet_content(p), p.size()); }
|
|
catch (Genode::Packet_descriptor::Invalid_packet) {
|
|
Genode::error("received invalid Nic packet"); }
|
|
_nic.rx()->acknowledge_packet(p);
|
|
}
|
|
|
|
/* schedule next batch if there are still packets available */
|
|
if (_nic.rx()->packet_avail())
|
|
Genode::Signal_transmitter(_sink_submit).submit();
|
|
|
|
/* tick the higher layer of the component */
|
|
_tick();
|
|
}
|
|
|
|
/**
|
|
* acknoledgement queue not full anymore
|
|
*/
|
|
void _ready_to_ack()
|
|
{
|
|
_packet_avail();
|
|
}
|
|
|
|
/**
|
|
* acknoledgement queue not empty anymore
|
|
*/
|
|
void _ack_avail()
|
|
{
|
|
while (_nic.tx()->ack_avail()) {
|
|
Nic::Packet_descriptor p = _nic.tx()->get_acked_packet();
|
|
_nic.tx()->release_packet(p);
|
|
}
|
|
}
|
|
|
|
|
|
public:
|
|
|
|
Nic_client(Genode::Env &env,
|
|
Genode::Entrypoint &ep,
|
|
Genode::Allocator &alloc,
|
|
void (*ticker)())
|
|
:
|
|
_tx_block_alloc(&alloc),
|
|
_nic(env, &_tx_block_alloc, BUF_SIZE, BUF_SIZE),
|
|
_sink_ack(ep, *this, &Nic_client::_packet_avail),
|
|
_sink_submit(ep, *this, &Nic_client::_ready_to_ack),
|
|
_source_ack(ep, *this, &Nic_client::_ack_avail),
|
|
_link_state_change(ep, *this, &Nic_client::_link_state),
|
|
_tick(ticker)
|
|
{
|
|
ic_link_state = _nic.link_state();
|
|
|
|
_nic.rx_channel()->sigh_ready_to_ack(_sink_ack);
|
|
_nic.rx_channel()->sigh_packet_avail(_sink_submit);
|
|
_nic.tx_channel()->sigh_ack_avail(_source_ack);
|
|
_nic.link_state_sigh(_link_state_change);
|
|
/* ready_to_submit not handled */
|
|
}
|
|
|
|
Nic::Connection *nic() { return &_nic; }
|
|
};
|
|
|
|
|
|
static Nic_client *_nic_client;
|
|
|
|
|
|
void Lx::nic_client_init(Genode::Env &env,
|
|
Genode::Entrypoint &ep,
|
|
Genode::Allocator &alloc,
|
|
void (*ticker)())
|
|
{
|
|
static Nic_client _inst(env, ep, alloc, ticker);
|
|
_nic_client = &_inst;
|
|
}
|
|
|
|
|
|
/**
|
|
* Call by back-end driver while initializing
|
|
*/
|
|
void net_mac(void* mac, unsigned long size)
|
|
{
|
|
enum { MAC_LEN = 17, ETH_ALEN = 6, };
|
|
|
|
char str[MAC_LEN + 1];
|
|
using namespace Genode;
|
|
|
|
Nic::Mac_address m = _nic_client->nic()->mac_address();
|
|
Genode::memcpy(mac, &m.addr, min(sizeof(m.addr), (size_t)size));
|
|
|
|
unsigned char const *mac_addr = (unsigned char const*)m.addr;
|
|
for (int i = 0; i < ETH_ALEN; i++) {
|
|
Genode::snprintf((char *)&str[i * 3], 3, "%02x", mac_addr[i]);
|
|
if ((i * 3) < MAC_LEN)
|
|
str[(i * 3) + 2] = ':';
|
|
}
|
|
str[MAC_LEN] = 0;
|
|
|
|
Genode::log("Received mac: ", Cstring(str));
|
|
}
|
|
|
|
|
|
/**
|
|
* Call by back-end driver when a packet should be sent
|
|
*/
|
|
int net_tx(void* addr, unsigned long len)
|
|
{
|
|
try {
|
|
Nic::Packet_descriptor packet = _nic_client->nic()->tx()->alloc_packet(len);
|
|
void* content = _nic_client->nic()->tx()->packet_content(packet);
|
|
|
|
Genode::memcpy((char *)content, addr, len);
|
|
_nic_client->nic()->tx()->submit_packet(packet);
|
|
|
|
return 0;
|
|
/* Packet_alloc_failed */
|
|
} catch(...) { return 1; }
|
|
}
|