Instead of having a method validate_size in each packet class, check sizes in the data accessor of the surrounding packet class. This packet accessor is the one that casts the data pointer to the desired data type so it is sensible that it also checks whether the desired type would exceed the available RAM before doing the cast. This also fits nicely the fact that for the top-level packet-class of a packet, the size must not be checked (which was previously done). Issue #465
107 lines
3.0 KiB
C++
107 lines
3.0 KiB
C++
/*
|
|
* \brief A net interface in form of a signal-driven NIC-packet handler
|
|
* \author Martin Stein
|
|
* \date 2017-03-08
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2016-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
/* local includes */
|
|
#include <interface.h>
|
|
|
|
/* Genode includes */
|
|
#include <net/ethernet.h>
|
|
#include <packet_log.h>
|
|
|
|
using namespace Net;
|
|
using namespace Genode;
|
|
|
|
|
|
void Net::Interface::_handle_eth(void *const eth_base,
|
|
size_t const eth_size,
|
|
Packet_descriptor const &)
|
|
{
|
|
try {
|
|
Ethernet_frame ð = *reinterpret_cast<Ethernet_frame *>(eth_base);
|
|
Interface &remote = _remote.deref();
|
|
Packet_log_config log_cfg;
|
|
|
|
if (_log_time) {
|
|
Genode::Duration const new_time = _timer.curr_time();
|
|
unsigned long const new_time_ms = new_time.trunc_to_plain_us().value / 1000;
|
|
unsigned long const old_time_ms = _curr_time.trunc_to_plain_us().value / 1000;
|
|
|
|
log("\033[33m(", remote._label, " <- ", _label, ")\033[0m ",
|
|
packet_log(eth, log_cfg), " \033[33mtime ", new_time_ms,
|
|
" ms (Δ ", new_time_ms - old_time_ms, " ms)\033[0m");
|
|
|
|
_curr_time = new_time;
|
|
} else {
|
|
log("\033[33m(", remote._label, " <- ", _label, ")\033[0m ", packet_log(eth, log_cfg));
|
|
}
|
|
remote._send(eth, eth_size);
|
|
}
|
|
catch (Pointer<Interface>::Invalid) {
|
|
error("no remote interface set"); }
|
|
}
|
|
|
|
|
|
void Net::Interface::_send(Ethernet_frame ð, Genode::size_t const size)
|
|
{
|
|
try {
|
|
Packet_descriptor const pkt = _source().alloc_packet(size);
|
|
char *content = _source().packet_content(pkt);
|
|
Genode::memcpy((void *)content, (void *)ð, size);
|
|
_source().submit_packet(pkt);
|
|
}
|
|
catch (Packet_stream_source::Packet_alloc_failed) {
|
|
error("Failed to allocate packet"); }
|
|
}
|
|
|
|
|
|
void Net::Interface::_ready_to_submit()
|
|
{
|
|
while (_sink().packet_avail()) {
|
|
|
|
Packet_descriptor const pkt = _sink().get_packet();
|
|
if (!pkt.size()) {
|
|
continue; }
|
|
|
|
_handle_eth(_sink().packet_content(pkt), pkt.size(), pkt);
|
|
|
|
if (!_sink().ready_to_ack()) {
|
|
error("ack state FULL");
|
|
return;
|
|
}
|
|
_sink().acknowledge_packet(pkt);
|
|
}
|
|
}
|
|
|
|
|
|
void Net::Interface::_ready_to_ack()
|
|
{
|
|
while (_source().ack_avail()) {
|
|
_source().release_packet(_source().get_acked_packet()); }
|
|
}
|
|
|
|
|
|
Net::Interface::Interface(Entrypoint &ep,
|
|
Interface_label label,
|
|
Timer::Connection &timer,
|
|
Duration &curr_time,
|
|
bool log_time,
|
|
Allocator &alloc)
|
|
:
|
|
_sink_ack (ep, *this, &Interface::_ack_avail),
|
|
_sink_submit (ep, *this, &Interface::_ready_to_submit),
|
|
_source_ack (ep, *this, &Interface::_ready_to_ack),
|
|
_source_submit(ep, *this, &Interface::_packet_avail),
|
|
_alloc(alloc), _label(label), _timer(timer), _curr_time(curr_time),
|
|
_log_time(log_time)
|
|
{ }
|