genode/repos/dde_linux/src/lib/lxip/nic_handler.cc

148 lines
3.2 KiB
C++

#include <base/printf.h>
#include <nic/packet_allocator.h>
#include <nic_session/connection.h>
#include <env.h>
#include <nic.h>
#include <packet_handler.h>
enum {
MAC_LEN = 17,
ETH_ALEN = 6,
};
namespace Net {
class Nic;
}
class Net::Nic : public Net::Packet_handler
{
private:
enum {
PACKET_SIZE = ::Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
BUF_SIZE = ::Nic::Session::QUEUE_SIZE * PACKET_SIZE,
};
::Nic::Packet_allocator _tx_block_alloc;
::Nic::Connection _nic;
public:
Nic()
: _tx_block_alloc(Genode::env()->heap()),
_nic(&_tx_block_alloc, BUF_SIZE, BUF_SIZE)
{
_nic.rx_channel()->sigh_ready_to_ack(_sink_ack);
_nic.rx_channel()->sigh_packet_avail(_sink_submit);
_nic.tx_channel()->sigh_ack_avail(_source_ack);
_nic.tx_channel()->sigh_ready_to_submit(_source_submit);
}
/******************************
** Packet_handler interface **
******************************/
Packet_stream_sink< ::Nic::Session::Policy> * sink() {
return _nic.rx(); }
Packet_stream_source< ::Nic::Session::Policy> * source() {
return _nic.tx(); }
static Nic *nic()
{
static Nic _net_nic;
return &_net_nic;
}
static ::Nic::Connection *n()
{
return &nic()->_nic;
}
};
Net::Packet_handler::Packet_handler()
: _sink_ack(*Net::Env::receiver(), *this, &Packet_handler::_ready_to_ack),
_sink_submit(*Net::Env::receiver(), *this, &Packet_handler::_packet_avail),
_source_ack(*Net::Env::receiver(), *this, &Packet_handler::_ack_avail),
_source_submit(*Net::Env::receiver(), *this, &Packet_handler::_ready_to_submit)
{ }
void Net::Packet_handler::_ack_avail(unsigned)
{
while (source()->ack_avail())
source()->release_packet(source()->get_acked_packet());
}
void Net::Packet_handler::_ready_to_ack(unsigned num)
{
_packet_avail(num);
}
void Net::Packet_handler::_packet_avail(unsigned)
{
using namespace Net;
enum { MAX_PACKETS = 20 };
int count = 0;
while(Nic::n()->rx()->packet_avail() &&
Nic::n()->rx()->ready_to_ack() &&
count++ < MAX_PACKETS)
{
Packet_descriptor p = Nic::n()->rx()->get_packet();
net_driver_rx(Net::Nic::n()->rx()->packet_content(p), p.size());
Nic::n()->rx()->acknowledge_packet(p);
}
if (Nic::n()->rx()->packet_avail())
Genode::Signal_transmitter(_sink_submit).submit();
}
static void snprint_mac(unsigned char *buf, unsigned char *mac)
{
for (int i = 0; i < ETH_ALEN; i++) {
Genode::snprintf((char *)&buf[i * 3], 3, "%02x", mac[i]);
if ((i * 3) < MAC_LEN)
buf[(i * 3) + 2] = ':';
}
buf[MAC_LEN] = 0;
}
void net_mac(void* mac, unsigned long size)
{
unsigned char str[MAC_LEN + 1];
using namespace Genode;
Nic::Mac_address m = Net::Nic::n()->mac_address();
Genode::memcpy(mac, &m.addr, min(sizeof(m.addr), (size_t)size));
snprint_mac(str, (unsigned char *)m.addr);
PINF("Received mac: %s", str);
}
int net_tx(void* addr, unsigned long len)
{
try {
Packet_descriptor packet = Net::Nic::n()->tx()->alloc_packet(len);
void* content = Net::Nic::n()->tx()->packet_content(packet);
Genode::memcpy((char *)content, addr, len);
Net::Nic::n()->tx()->submit_packet(packet);
return 0;
/* 'Packet_alloc_failed' */
} catch(...) {
return 1;
}
}