net: use Size_guard for packet-data accessors

Instead of handing over the maximum available size to the packet data
accessors, hand over a size guard that keeps track of the packets
boundaries.

This commit also moves the size-guard utilitiy header of Ping and NIC
Router to the include/net directory making it a part of the net library.
It applies the new approach to all net-lib users in the basic repositories.

Ping looses its configurability regarding the ICMP data size as this would
require an additional method in the size guard which would be used only by
Ping.

The size guard was also re-worked to fit the fact that a packet can
bring a tail as well as a header (Ethernet).

Issue #2788
This commit is contained in:
Martin Stein 2018-04-26 14:53:29 +02:00 committed by Christian Helmuth
parent 2bd163533b
commit 980f3e9c5c
25 changed files with 456 additions and 494 deletions

View File

@ -123,6 +123,11 @@ class Net::Arp_packet
&& _protocol_address_size == Ipv4_packet::ADDR_LEN);
}
Genode::size_t size(Genode::size_t max_size) const
{
return sizeof(Arp_packet) < max_size ? sizeof(Arp_packet) : max_size;
}
/*********
** Log **

View File

@ -333,7 +333,7 @@ class Net::Dhcp_packet
template <typename OPTION>
void append_param_req()
{
_size_guard.add(sizeof(_base[0]));
_size_guard.consume_head(sizeof(_base[0]));
_base[_size] = (Genode::uint8_t)OPTION::CODE;
_size++;
}
@ -351,7 +351,7 @@ class Net::Dhcp_packet
template <typename OPTION, typename... ARGS>
void append_option(ARGS &&... args)
{
_size_guard.add(sizeof(OPTION));
_size_guard.consume_head(sizeof(OPTION));
Genode::construct_at<OPTION>((void *)_base,
static_cast<ARGS &&>(args)...);
_base += sizeof(OPTION);
@ -360,7 +360,7 @@ class Net::Dhcp_packet
template <typename INIT_DATA>
void append_param_req_list(INIT_DATA && init_data)
{
_size_guard.add(sizeof(Parameter_request_list));
_size_guard.consume_head(sizeof(Parameter_request_list));
Parameter_request_list_data
data((Genode::uint8_t *)(_base + sizeof(Parameter_request_list)),
_size_guard);

View File

@ -20,6 +20,7 @@
#include <util/construct_at.h>
#include <util/endian.h>
#include <net/mac_address.h>
#include <net/size_guard.h>
namespace Net
{
@ -70,31 +71,52 @@ class Net::Ethernet_frame
ARP = 0x0806,
};
struct Bad_data_type : Genode::Exception { };
template <typename T> T const &data(Genode::size_t data_size) const
template <typename T>
T const &data(Size_guard &size_guard) const
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
return *(T const *)(_data);
size_guard.consume_head(sizeof(T));
T const &obj = *(T *)(_data);
/* Ethernet may have a tail whose size must be considered */
Genode::size_t const unconsumed = size_guard.unconsumed();
size_guard.consume_tail(unconsumed + sizeof(T) -
obj.size(unconsumed));
return obj;
}
template <typename T> T &data(Genode::size_t data_size)
template <typename T>
T &data(Size_guard &size_guard)
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
return *(T *)(_data);
size_guard.consume_head(sizeof(T));
T &obj = *(T *)(_data);
/* Ethernet may have a tail whose size must be considered */
Genode::size_t const max_obj_sz = size_guard.unconsumed() + sizeof(T);
size_guard.consume_tail(max_obj_sz - obj.size(max_obj_sz));
return obj;
}
template <typename T, typename SIZE_GUARD>
T &construct_at_data(SIZE_GUARD &size_guard)
template <typename T>
T &construct_at_data(Size_guard &size_guard)
{
size_guard.add(sizeof(T));
size_guard.consume_head(sizeof(T));
return *Genode::construct_at<T>(_data);
}
static Ethernet_frame &construct_at(void *base,
Size_guard &size_guard)
{
size_guard.consume_head(sizeof(Ethernet_frame));
return *Genode::construct_at<Ethernet_frame>(base);
}
static Ethernet_frame &cast_from(void *base,
Size_guard &size_guard)
{
size_guard.consume_head(sizeof(Ethernet_frame));
return *(Ethernet_frame *)base;
}
/***************
** Accessors **

View File

@ -41,8 +41,6 @@ class Net::Icmp_packet
public:
struct Bad_data_type : Genode::Exception { };
enum class Type
{
ECHO_REPLY = 0,
@ -73,14 +71,28 @@ class Net::Icmp_packet
Genode::uint16_t query_seq() const { return host_to_big_endian(_rest_of_header_u16[1]); }
Genode::uint32_t rest_of_header() const { return host_to_big_endian(_rest_of_header_u32[0]); }
template <typename T> T &data(Genode::size_t data_size)
template <typename T>
T const &data(Size_guard &size_guard) const
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
size_guard.consume_head(sizeof(T));
return *(T const *)(_data);
}
template <typename T>
T &data(Size_guard &size_guard)
{
size_guard.consume_head(sizeof(T));
return *(T *)(_data);
}
void copy_to_data(void const *base,
Genode::size_t size,
Size_guard &size_guard)
{
size_guard.consume_head(size);
Genode::memcpy(_data, base, size);
}
void type(Type v) { _type = (Genode::uint8_t)v; }
void code(Code v) { _code = (Genode::uint8_t)v; }
void checksum(Genode::uint16_t v) { _checksum = host_to_big_endian(v); }

View File

@ -21,6 +21,7 @@
#include <util/construct_at.h>
#include <util/endian.h>
#include <net/netaddress.h>
#include <net/size_guard.h>
namespace Genode { class Output; }
@ -124,30 +125,24 @@ class Net::Ipv4_packet
UDP = 17,
};
struct Bad_data_type : Genode::Exception { };
template <typename T>
T const &data(Genode::size_t data_size) const
T const &data(Size_guard &size_guard) const
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
size_guard.consume_head(sizeof(T));
return *(T const *)(_data);
}
template <typename T>
T &data(Genode::size_t data_size)
T &data(Size_guard &size_guard)
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
size_guard.consume_head(sizeof(T));
return *(T *)(_data);
}
template <typename T, typename SIZE_GUARD>
T &construct_at_data(SIZE_GUARD &size_guard)
{
size_guard.add(sizeof(T));
size_guard.consume_head(sizeof(T));
return *Genode::construct_at<T>(_data);
}

View File

@ -0,0 +1,66 @@
/*
* \brief Utility to ensure that a size value doesn't exceed a limit
* \author Martin Stein
* \date 2016-08-24
*/
/*
* 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.
*/
#ifndef _NET__SIZE_GUARD_H_
#define _NET__SIZE_GUARD_H_
/* Genode includes */
#include <base/stdint.h>
#include <base/exception.h>
namespace Net { class Size_guard; }
class Net::Size_guard
{
public:
struct Exceeded : Genode::Exception { };
private:
Genode::size_t const _total_size;
Genode::size_t _head_size { 0 };
Genode::size_t _tail_size { 0 };
void _consume(Genode::size_t &s1,
Genode::size_t &s2,
Genode::size_t s1_consume)
{
Genode::size_t const new_s1 = s1 + s1_consume;
if (new_s1 < s1 || new_s1 > _total_size - s2)
throw Exceeded();
s1 = new_s1;
}
public:
Size_guard(Genode::size_t total_size) : _total_size { total_size } { }
void consume_head(Genode::size_t size) { _consume(_head_size, _tail_size, size); }
void consume_tail(Genode::size_t size) { _consume(_tail_size, _head_size, size); }
/***************
** Accessors **
***************/
Genode::size_t unconsumed() const { return _total_size - _head_size - _tail_size; }
Genode::size_t tail_size() const { return _tail_size; }
Genode::size_t head_size() const { return _head_size; }
Genode::size_t total_size() const { return _total_size; }
};
#endif /* _NET__SIZE_GUARD_H_ */

View File

@ -51,28 +51,24 @@ class Net::Udp_packet
public:
struct Bad_data_type : Genode::Exception { };
template <typename T> T const &data(Genode::size_t data_size) const
template <typename T>
T const &data(Size_guard &size_guard) const
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
size_guard.consume_head(sizeof(T));
return *(T const *)(_data);
}
template <typename T> T &data(Genode::size_t data_size)
template <typename T>
T &data(Size_guard &size_guard)
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
size_guard.consume_head(sizeof(T));
return *(T *)(_data);
}
template <typename T, typename SIZE_GUARD>
T &construct_at_data(SIZE_GUARD &size_guard)
{
size_guard.add(sizeof(T));
size_guard.consume_head(sizeof(T));
return *Genode::construct_at<T>(_data);
}

View File

@ -59,7 +59,6 @@ append config {
<resource name="RAM" quantum="8M"/>
<config src_ip="10.0.2.55"
dst_ip="10.0.2.2"
data_size="56"
period_sec="1"
verbose="no"
count="3"/>

View File

@ -121,7 +121,6 @@ append config {
<resource name="RAM" quantum="8M"/>
<config src_ip="10.0.3.2"
dst_ip="10.0.2.2"
data_size="56"
period_sec="1"
verbose="no"/>
<route>
@ -135,7 +134,6 @@ append config {
<resource name="RAM" quantum="8M"/>
<config src_ip="10.0.3.3"
dst_ip="10.0.2.2"
data_size="56"
period_sec="1"
verbose="no"/>
<route>
@ -149,7 +147,6 @@ append config {
<resource name="RAM" quantum="8M"/>
<config src_ip="10.0.5.2"
dst_ip="10.0.2.2"
data_size="56"
period_sec="1"
verbose="no"/>
<route>
@ -163,7 +160,6 @@ append config {
<resource name="RAM" quantum="8M"/>
<config src_ip="10.0.5.3"
dst_ip="10.0.1.2"
data_size="56"
period_sec="1"
verbose="no"/>
<route>

View File

@ -1,8 +1,8 @@
The 'ping' component continuously sends ICMP Echo requests to a given IP host
and waits for the corresponding ICMP Echo replies. For each successfull ICMP
Echo handshake it prints a short statistic. By now, it can be used only with a
static IP configuration. The size of the ICMP data field can be configured. It
gets filled with the letters of the alphabet ('a' to 'z') repeatedly.
static IP configuration. The ICMP data field gets filled with the letters of
the alphabet ('a' to 'z') repeatedly.
Configuration
@ -13,7 +13,6 @@ value for each attribute except 'config.dst_ip' and 'config.src_ip':
! <config src_ip="10.0.0.72"
! dst_ip="10.0.0.24"
! data_size="56"
! period_sec="5"
! verbose="no"
! count="5" />
@ -26,9 +25,6 @@ This is a short description of the tags and attributes:
:config.dst_ip:
Mandatory. IP address of the target host.
:config.data_size:
Optional. Size of the ICMP data field.
:config.period_sec:
Optional. Length of send interval in seconds.

View File

@ -32,7 +32,6 @@
<xs:attribute name="src_ip" type="Ipv4_address" />
<xs:attribute name="period_sec" type="Seconds" />
<xs:attribute name="count" type="xs:positiveInteger" />
<xs:attribute name="data_size" type="xs:nonNegativeInteger" />
</xs:complexType>
</xs:element><!-- config -->

View File

@ -11,9 +11,6 @@
* under the terms of the GNU Affero General Public License version 3.
*/
/* local includes */
#include <size_guard.h>
/* Genode includes */
#include <net/ipv4.h>
#include <net/ethernet.h>
@ -55,13 +52,13 @@ class Main
using Signal_handler = Genode::Signal_handler<Main>;
using Periodic_timeout = Timer::Periodic_timeout<Main>;
enum { IPV4_TIME_TO_LIVE = 64 };
enum { ICMP_ID = 1166 };
enum { DEFAULT_ICMP_DATA_SZ = 56 };
enum { DEFAULT_COUNT = 5 };
enum { DEFAULT_PERIOD_SEC = 5 };
enum { PKT_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE };
enum { BUF_SIZE = Nic::Session::QUEUE_SIZE * PKT_SIZE };
enum { IPV4_TIME_TO_LIVE = 64 };
enum { ICMP_ID = 1166 };
enum { ICMP_DATA_SIZE = 56 };
enum { DEFAULT_COUNT = 5 };
enum { DEFAULT_PERIOD_SEC = 5 };
enum { PKT_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE };
enum { BUF_SIZE = Nic::Session::QUEUE_SIZE * PKT_SIZE };
Env &_env;
Attached_rom_dataspace _config_rom { _env, "config" };
@ -84,29 +81,27 @@ class Main
Mac_address _dst_mac { };
uint16_t _ip_id { 1 };
uint16_t _icmp_seq { 1 };
size_t const _icmp_data_sz { _config.attribute_value("data_size", (size_t)DEFAULT_ICMP_DATA_SZ) };
unsigned long _count { _config.attribute_value("count", (unsigned long)DEFAULT_COUNT) };
void _handle_eth(void *const eth_base,
size_t const eth_size,
Packet_descriptor const &pkt);
void _handle_eth(void *const eth_base,
Size_guard &size_guard);
void _handle_ip(Ethernet_frame &eth,
size_t const eth_size);
Size_guard &size_guard);
void _handle_icmp(Ipv4_packet &ip,
size_t const ip_size);
Size_guard &size_guard);
void _handle_icmp_echo_reply(Ipv4_packet &ip,
Icmp_packet &icmp,
size_t icmp_data_sz);
Size_guard &size_guard);
void _handle_icmp_dst_unreachbl(Ipv4_packet &ip,
Icmp_packet &icmp,
size_t icmp_data_sz);
Size_guard &size_guard);
void _handle_arp(Ethernet_frame &eth,
size_t const eth_size);
Size_guard &size_guard);
void _broadcast_arp_request();
@ -120,10 +115,16 @@ class Main
try {
Packet_descriptor pkt = _source().alloc_packet(pkt_size);
void *pkt_base = _source().packet_content(pkt);
write_to_pkt(pkt_base);
Size_guard size_guard(pkt_size);
write_to_pkt(pkt_base, size_guard);
_source().submit_packet(pkt);
if (_verbose) {
log("snd ", *reinterpret_cast<Ethernet_frame *>(pkt_base)); }
try {
Size_guard size_guard(pkt_size);
log("snd ", Ethernet_frame::cast_from(pkt_base, size_guard));
}
catch (Size_guard::Exceeded) { log("snd ?"); }
}
}
catch (Net::Packet_stream_source::Packet_alloc_failed) {
warning("failed to allocate packet"); }
@ -146,8 +147,7 @@ class Main
public:
struct Invalid_arguments : Exception { };
struct Send_buffer_too_small : Exception { };
struct Invalid_arguments : Exception { };
Main(Env &env);
};
@ -170,12 +170,11 @@ Main::Main(Env &env) : _env(env)
}
void Main::_handle_eth(void *const eth_base,
size_t const eth_size,
Packet_descriptor const &)
void Main::_handle_eth(void *const eth_base,
Size_guard &size_guard)
{
/* print receipt message */
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(eth_base);
Ethernet_frame &eth = Ethernet_frame::cast_from(eth_base, size_guard);
if (_verbose) {
log("rcv ", eth); }
@ -189,19 +188,17 @@ void Main::_handle_eth(void *const eth_base,
}
/* select ETH sub-protocol */
switch (eth.type()) {
case Ethernet_frame::Type::ARP: _handle_arp(eth, eth_size); break;
case Ethernet_frame::Type::IPV4: _handle_ip(eth, eth_size); break;
case Ethernet_frame::Type::ARP: _handle_arp(eth, size_guard); break;
case Ethernet_frame::Type::IPV4: _handle_ip(eth, size_guard); break;
default: ; }
}
void Main::_handle_ip(Ethernet_frame &eth,
size_t const eth_size)
Size_guard &size_guard)
{
/* drop packet if IP does not target us */
size_t const ip_max_size = eth_size - sizeof(Ethernet_frame);
Ipv4_packet &ip = eth.data<Ipv4_packet>(ip_max_size);
size_t const ip_size = ip.size(ip_max_size);
Ipv4_packet &ip = eth.data<Ipv4_packet>(size_guard);
if (ip.dst() != _src_ip &&
ip.dst() != Ipv4_packet::broadcast())
{
@ -217,14 +214,14 @@ void Main::_handle_ip(Ethernet_frame &eth,
}
/* select IP sub-protocol */
switch (ip.protocol()) {
case Ipv4_packet::Protocol::ICMP: _handle_icmp(ip, ip_size);
case Ipv4_packet::Protocol::ICMP: _handle_icmp(ip, size_guard);
default: ; }
}
void Main::_handle_icmp_echo_reply(Ipv4_packet &ip,
Icmp_packet &icmp,
size_t icmp_data_sz)
Size_guard &size_guard)
{
/* check IP source */
if (ip.src() != _dst_ip) {
@ -253,16 +250,16 @@ void Main::_handle_icmp_echo_reply(Ipv4_packet &ip,
return;
}
/* check ICMP data size */
if (icmp_data_sz != _icmp_data_sz) {
if (size_guard.unconsumed() != ICMP_DATA_SIZE) {
if (_verbose) {
log("bad ICMP data size"); }
return;
}
/* check ICMP data */
struct Data { char chr[0]; };
Data &data = icmp.data<Data>(_icmp_data_sz);
Data &data = icmp.data<Data>(size_guard);
char chr = 'a';
for (addr_t chr_id = 0; chr_id < icmp_data_sz; chr_id++) {
for (addr_t chr_id = 0; chr_id < ICMP_DATA_SIZE; chr_id++) {
if (data.chr[chr_id] != chr) {
if (_verbose) {
log("bad ICMP data"); }
@ -276,7 +273,7 @@ void Main::_handle_icmp_echo_reply(Ipv4_packet &ip,
time_us = time_us - time_ms * 1000UL;
/* print success message */
log(icmp_data_sz + sizeof(Icmp_packet), " bytes from ", ip.src(),
log(ICMP_DATA_SIZE + sizeof(Icmp_packet), " bytes from ", ip.src(),
": icmp_seq=", icmp_seq, " ttl=", (unsigned long)IPV4_TIME_TO_LIVE,
" time=", time_ms, ".", time_us ," ms");
@ -290,10 +287,10 @@ void Main::_handle_icmp_echo_reply(Ipv4_packet &ip,
void Main::_handle_icmp_dst_unreachbl(Ipv4_packet &ip,
Icmp_packet &icmp,
size_t icmp_data_sz)
Size_guard &size_guard)
{
/* drop packet if embedded IP checksum is invalid */
Ipv4_packet &embed_ip = icmp.data<Ipv4_packet>(icmp_data_sz);
Ipv4_packet &embed_ip = icmp.data<Ipv4_packet>(size_guard);
if (embed_ip.checksum_error()) {
if (_verbose) {
log("bad IP checksum in payload of ICMP error"); }
@ -306,8 +303,7 @@ void Main::_handle_icmp_dst_unreachbl(Ipv4_packet &ip,
return;
}
/* drop packet if embedded ICMP identifier is invalid */
size_t const embed_icmp_sz = embed_ip.total_length() - sizeof(Ipv4_packet);
Icmp_packet &embed_icmp = embed_ip.data<Icmp_packet>(embed_icmp_sz);
Icmp_packet &embed_icmp = embed_ip.data<Icmp_packet>(size_guard);
if (embed_icmp.query_id() != ICMP_ID) {
if (_verbose) {
log("bad ICMP identifier in payload of ICMP error"); }
@ -324,22 +320,20 @@ void Main::_handle_icmp_dst_unreachbl(Ipv4_packet &ip,
}
void Main::_handle_icmp(Ipv4_packet &ip,
size_t const ip_size)
void Main::_handle_icmp(Ipv4_packet &ip,
Size_guard &size_guard)
{
/* drop packet if ICMP checksum is invalid */
size_t const icmp_sz = ip_size - sizeof(Ipv4_packet);
Icmp_packet &icmp = ip.data<Icmp_packet>(icmp_sz);
size_t const icmp_data_sz = icmp_sz - sizeof(Icmp_packet);
if (icmp.checksum_error(icmp_data_sz)) {
Icmp_packet &icmp = ip.data<Icmp_packet>(size_guard);
if (icmp.checksum_error(size_guard.unconsumed())) {
if (_verbose) {
log("bad ICMP checksum"); }
return;
}
/* select ICMP type */
switch (icmp.type()) {
case Icmp_packet::Type::ECHO_REPLY: _handle_icmp_echo_reply(ip, icmp, icmp_data_sz); break;
case Icmp_packet::Type::DST_UNREACHABLE: _handle_icmp_dst_unreachbl(ip, icmp, icmp_data_sz); break;
case Icmp_packet::Type::ECHO_REPLY: _handle_icmp_echo_reply(ip, icmp, size_guard); break;
case Icmp_packet::Type::DST_UNREACHABLE: _handle_icmp_dst_unreachbl(ip, icmp, size_guard); break;
default:
if (_verbose) {
log("bad ICMP type"); }
@ -349,10 +343,10 @@ void Main::_handle_icmp(Ipv4_packet &ip,
void Main::_handle_arp(Ethernet_frame &eth,
size_t const eth_size)
Size_guard &size_guard)
{
/* check ARP protocol- and hardware address type */
Arp_packet &arp = eth.data<Arp_packet>(eth_size - sizeof(Ethernet_frame));
Arp_packet &arp = eth.data<Arp_packet>(size_guard);
if (!arp.ethernet_ipv4()) {
error("ARP for unknown protocol"); }
@ -386,10 +380,8 @@ void Main::_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);
Size_guard size_guard(pkt.size());
_handle_eth(_sink().packet_content(pkt), size_guard);
if (!_sink().ready_to_ack()) {
error("ack state FULL");
@ -410,19 +402,17 @@ void Main::_ready_to_ack()
void Main::_send_arp_reply(Ethernet_frame &req_eth,
Arp_packet &req_arp)
{
size_t const buf_sz = sizeof(Ethernet_frame) + sizeof(Arp_packet);
_send(buf_sz, [&] (void *pkt_base) {
_send(sizeof(Ethernet_frame) + sizeof(Arp_packet),
[&] (void *pkt_base, Size_guard &size_guard)
{
/* write Ethernet header */
Size_guard<Send_buffer_too_small> size(buf_sz);
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
Ethernet_frame &eth = Ethernet_frame::construct_at(pkt_base, size_guard);
eth.dst(req_eth.src());
eth.src(_src_mac);
eth.type(Ethernet_frame::Type::ARP);
/* write ARP header */
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size);
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size_guard);
arp.hardware_address_type(Arp_packet::ETHERNET);
arp.protocol_address_type(Arp_packet::IPV4);
arp.hardware_address_size(sizeof(Mac_address));
@ -438,19 +428,17 @@ void Main::_send_arp_reply(Ethernet_frame &req_eth,
void Main::_broadcast_arp_request()
{
size_t const buf_sz = sizeof(Ethernet_frame) + sizeof(Arp_packet);
_send(buf_sz, [&] (void *pkt_base) {
_send(sizeof(Ethernet_frame) + sizeof(Arp_packet),
[&] (void *pkt_base, Size_guard &size_guard)
{
/* write Ethernet header */
Size_guard<Send_buffer_too_small> size(buf_sz);
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
Ethernet_frame &eth = Ethernet_frame::construct_at(pkt_base, size_guard);
eth.dst(Mac_address(0xff));
eth.src(_src_mac);
eth.type(Ethernet_frame::Type::ARP);
/* write ARP header */
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size);
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size_guard);
arp.hardware_address_type(Arp_packet::ETHERNET);
arp.protocol_address_type(Arp_packet::IPV4);
arp.hardware_address_size(sizeof(Mac_address));
@ -470,22 +458,19 @@ void Main::_send_ping(Duration)
_broadcast_arp_request();
return;
}
size_t const buf_sz = sizeof(Ethernet_frame) + sizeof(Ipv4_packet) +
sizeof(Icmp_packet) + _icmp_data_sz;
_send(buf_sz, [&] (void *pkt_base) {
_send(sizeof(Ethernet_frame) + sizeof(Ipv4_packet) +
sizeof(Icmp_packet) + ICMP_DATA_SIZE,
[&] (void *pkt_base, Size_guard &size_guard)
{
/* create ETH header */
Size_guard<Send_buffer_too_small> size(buf_sz);
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
Ethernet_frame &eth = Ethernet_frame::construct_at(pkt_base, size_guard);
eth.dst(_dst_mac);
eth.src(_src_mac);
eth.type(Ethernet_frame::Type::IPV4);
/* create IP header */
size_t const ip_off = size.curr();
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size);
size_t const ip_off = size_guard.head_size();
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size_guard);
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.time_to_live(IPV4_TIME_TO_LIVE);
@ -494,24 +479,23 @@ void Main::_send_ping(Duration)
ip.dst(_dst_ip);
/* create ICMP header */
Icmp_packet &icmp = ip.construct_at_data<Icmp_packet>(size);
Icmp_packet &icmp = ip.construct_at_data<Icmp_packet>(size_guard);
icmp.type(Icmp_packet::Type::ECHO_REQUEST);
icmp.code(Icmp_packet::Code::ECHO_REQUEST);
icmp.query_id(ICMP_ID);
icmp.query_seq(_icmp_seq);
/* fill ICMP data with characters from 'a' to 'z' */
size.add(_icmp_data_sz);
struct Data { char chr[0]; };
Data &data = icmp.data<Data>(_icmp_data_sz);
struct Data { char chr[ICMP_DATA_SIZE]; };
Data &data = icmp.data<Data>(size_guard);
char chr = 'a';
for (addr_t chr_id = 0; chr_id < _icmp_data_sz; chr_id++) {
for (addr_t chr_id = 0; chr_id < ICMP_DATA_SIZE; chr_id++) {
data.chr[chr_id] = chr;
chr = chr < 'z' ? chr + 1 : 'a';
}
/* fill in header values that require the packet to be complete */
icmp.update_checksum(_icmp_data_sz);
ip.total_length(size.curr() - ip_off);
icmp.update_checksum(ICMP_DATA_SIZE);
ip.total_length(size_guard.head_size() - ip_off);
ip.update_checksum();
});
_send_time = _timer.curr_time().trunc_to_plain_us();

View File

@ -1,43 +0,0 @@
/*
* \brief Utility to ensure that a size value doesn't exceed a limit
* \author Martin Stein
* \date 2016-08-24
*/
/*
* 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.
*/
#ifndef _SIZE_GUARD_H_
#define _SIZE_GUARD_H_
/* Genode includes */
#include <base/stdint.h>
template <typename EXCEPTION>
class Size_guard
{
private:
Genode::size_t _curr { 0 };
Genode::size_t const _max;
public:
Size_guard(Genode::size_t max) : _max(max) { }
void add(Genode::size_t size)
{
Genode::size_t const new_size = _curr + size;
if (new_size > _max) { throw EXCEPTION(); }
_curr = new_size;
}
Genode::size_t curr() const { return _curr; }
Genode::size_t left() const { return _max - _curr; }
};
#endif /* _SIZE_GUARD_H_ */

View File

@ -22,9 +22,10 @@ using namespace Net;
using namespace Genode;
bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
bool Session_component::handle_arp(Ethernet_frame &eth,
Size_guard &size_guard)
{
Arp_packet &arp = eth->data<Arp_packet>(size - sizeof(Ethernet_frame));
Arp_packet &arp = eth.data<Arp_packet>(size_guard);
if (arp.ethernet_ipv4() &&
arp.opcode() == Arp_packet::REQUEST) {
@ -50,19 +51,16 @@ bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
}
bool Session_component::handle_ip(Ethernet_frame *eth, Genode::size_t size)
bool Session_component::handle_ip(Ethernet_frame &eth,
Size_guard &size_guard)
{
size_t const ip_max_size = size - sizeof(Ethernet_frame);
Ipv4_packet &ip = eth->data<Ipv4_packet>(ip_max_size);
size_t const ip_size = ip.size(ip_max_size);
Ipv4_packet &ip = eth.data<Ipv4_packet>(size_guard);
if (ip.protocol() == Ipv4_packet::Protocol::UDP) {
size_t const udp_size = ip_size - sizeof(Ipv4_packet);
Udp_packet &udp = ip.data<Udp_packet>(udp_size);
Udp_packet &udp = ip.data<Udp_packet>(size_guard);
if (Dhcp_packet::is_dhcp(&udp)) {
size_t const dhcp_size = udp_size - sizeof(Udp_packet);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(dhcp_size);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size_guard);
if (dhcp.op() == Dhcp_packet::REQUEST) {
dhcp.broadcast(true);
@ -75,7 +73,7 @@ bool Session_component::handle_ip(Ethernet_frame *eth, Genode::size_t size)
void Session_component::finalize_packet(Ethernet_frame *eth,
Genode::size_t size)
Genode::size_t size)
{
Mac_address_node *node = vlan().mac_tree.first();
if (node)

View File

@ -163,15 +163,20 @@ class Net::Session_component : private Net::Stream_allocator,
** Packet_handler interface **
******************************/
Packet_stream_sink< ::Nic::Session::Policy> * sink() {
Packet_stream_sink< ::Nic::Session::Policy> * sink() override {
return _tx.sink(); }
Packet_stream_source< ::Nic::Session::Policy> * source() {
Packet_stream_source< ::Nic::Session::Policy> * source() override {
return _rx.source(); }
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
void finalize_packet(Ethernet_frame *eth, Genode::size_t size);
bool handle_arp(Ethernet_frame &eth,
Size_guard &size_guard) override;
bool handle_ip(Ethernet_frame &eth,
Size_guard &size_guard) override;
void finalize_packet(Ethernet_frame *, Genode::size_t) override;
};

View File

@ -24,10 +24,11 @@ using namespace Net;
using namespace Genode;
bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
Arp_packet &arp = eth->data<Arp_packet>(size - sizeof(Ethernet_frame));
bool Net::Nic::handle_arp(Ethernet_frame &eth,
Size_guard &size_guard)
{
/* ignore broken packets */
Arp_packet &arp = eth.data<Arp_packet>(size_guard);
if (!arp.ethernet_ipv4())
return true;
@ -48,16 +49,16 @@ bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
arp.src_mac(mac());
arp.src_ip(arp.dst_ip());
arp.dst_ip(old_src_ip);
eth->dst(arp.dst_mac());
eth.dst(arp.dst_mac());
/* set our MAC as sender */
eth->src(mac());
send(eth, size);
eth.src(mac());
send(&eth, size_guard.total_size());
} else {
/* overwrite destination MAC */
arp.dst_mac(node->component().mac_address().addr);
eth->dst(node->component().mac_address().addr);
node->component().send(eth, size);
eth.dst(node->component().mac_address().addr);
node->component().send(&eth, size_guard.total_size());
}
return false;
}
@ -65,24 +66,19 @@ bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
}
bool Net::Nic::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
size_t const ip_max_size = size - sizeof(Ethernet_frame);
Ipv4_packet &ip = eth->data<Ipv4_packet>(ip_max_size);
size_t const ip_size = ip.size(ip_max_size);
bool Net::Nic::handle_ip(Ethernet_frame &eth,
Size_guard &size_guard)
{
/* is it an UDP packet ? */
Ipv4_packet &ip = eth.data<Ipv4_packet>(size_guard);
if (ip.protocol() == Ipv4_packet::Protocol::UDP)
{
size_t const udp_size = ip_size - sizeof(Ipv4_packet);
Udp_packet &udp = ip.data<Udp_packet>(udp_size);
/* is it a DHCP packet ? */
Udp_packet &udp = ip.data<Udp_packet>(size_guard);
if (Dhcp_packet::is_dhcp(&udp)) {
size_t const dhcp_size = udp_size - sizeof(Udp_packet);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(dhcp_size);
/* check for DHCP ACKs containing new client ips */
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size_guard);
if (dhcp.op() == Dhcp_packet::REPLY) {
try {
@ -108,16 +104,16 @@ bool Net::Nic::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
}
/* is it an unicast message to one of our clients ? */
if (eth->dst() == mac()) {
if (eth.dst() == mac()) {
Ipv4_address_node *node = vlan().ip_tree.first();
if (node) {
node = node->find_by_address(ip.dst());
if (node) {
/* overwrite destination MAC */
eth->dst(node->component().mac_address().addr);
eth.dst(node->component().mac_address().addr);
/* deliver the packet to the client */
node->component().send(eth, size);
node->component().send(&eth, size_guard.total_size());
return false;
}
}

View File

@ -48,15 +48,19 @@ class Net::Nic : public Net::Packet_handler
** Packet_handler interface **
******************************/
Packet_stream_sink< ::Nic::Session::Policy> * sink() {
Packet_stream_sink< ::Nic::Session::Policy> * sink() override {
return _nic.rx(); }
Packet_stream_source< ::Nic::Session::Policy> * source() {
Packet_stream_source< ::Nic::Session::Policy> * source() override {
return _nic.tx(); }
bool handle_arp(Ethernet_frame *eth, Genode::size_t size);
bool handle_ip(Ethernet_frame *eth, Genode::size_t size);
void finalize_packet(Ethernet_frame *, Genode::size_t) {}
bool handle_arp(Ethernet_frame &eth,
Size_guard &size_guard) override;
bool handle_ip(Ethernet_frame &eth,
Size_guard &size_guard) override;
void finalize_packet(Ethernet_frame *, Genode::size_t) override { }
};
#endif /* _SRC__SERVER__NIC_BRIDGE__NIC_H_ */

View File

@ -79,26 +79,22 @@ void Packet_handler::handle_ethernet(void* src, Genode::size_t size)
{
try {
/* parse ethernet frame header */
Ethernet_frame *eth = reinterpret_cast<Ethernet_frame *>(src);
switch (eth->type()) {
Size_guard size_guard(size);
Ethernet_frame &eth = Ethernet_frame::cast_from(src, size_guard);
switch (eth.type()) {
case Ethernet_frame::Type::ARP:
if (!handle_arp(eth, size)) return;
if (!handle_arp(eth, size_guard)) return;
break;
case Ethernet_frame::Type::IPV4:
if(!handle_ip(eth, size)) return;
if (!handle_ip(eth, size_guard)) return;
break;
default:
;
}
broadcast_to_clients(eth, size);
finalize_packet(eth, size);
} catch(Ethernet_frame::Bad_data_type) {
Genode::warning("Invalid Ethernet frame!");
} catch(Ipv4_packet::Bad_data_type) {
Genode::warning("Invalid IPv4 packet!");
} catch(Udp_packet::Bad_data_type) {
Genode::warning("Invalid UDP packet!");
broadcast_to_clients(&eth, size);
finalize_packet(&eth, size);
} catch(Size_guard::Exceeded) {
Genode::warning("Packet size guard exceeded!");
}
}

View File

@ -124,8 +124,8 @@ class Net::Packet_handler
* \param eth ethernet frame containing the ARP packet.
* \param size ethernet frame's size.
*/
virtual bool handle_arp(Ethernet_frame *eth,
Genode::size_t size) = 0;
virtual bool handle_arp(Ethernet_frame &eth,
Size_guard &size_guard) = 0;
/*
* Handle an IP packet
@ -133,8 +133,8 @@ class Net::Packet_handler
* \param eth ethernet frame containing the IP packet.
* \param size ethernet frame's size.
*/
virtual bool handle_ip(Ethernet_frame *eth,
Genode::size_t size) = 0;
virtual bool handle_ip(Ethernet_frame &eth,
Size_guard &size_guard) = 0;
/*
* Finalize handling of ethernet frame.

View File

@ -154,15 +154,16 @@ void Packet_log<Ethernet_frame>::print(Output &output) const
default: ;
}
/* print encapsulated packet */
Size_guard size_guard(~0UL);
switch (_pkt.type()) {
case Ethernet_frame::Type::ARP:
print(output, " ", packet_log(_pkt.data<Arp_packet const>(~0UL), _cfg));
print(output, " ", packet_log(_pkt.data<Arp_packet const>(size_guard), _cfg));
break;
case Ethernet_frame::Type::IPV4:
print(output, " ", packet_log(_pkt.data<Ipv4_packet const>(~0UL), _cfg));
print(output, " ", packet_log(_pkt.data<Ipv4_packet const>(size_guard), _cfg));
break;
default: ;
@ -209,20 +210,21 @@ void Packet_log<Ipv4_packet>::print(Output &output) const
default: ;
}
/* print encapsulated packet */
Size_guard size_guard(~0UL);
switch (_pkt.protocol()) {
case Ipv4_packet::Protocol::TCP:
print(output, " ", packet_log(_pkt.data<Tcp_packet const>(~0UL), _cfg));
print(output, " ", packet_log(_pkt.data<Tcp_packet const>(size_guard), _cfg));
break;
case Ipv4_packet::Protocol::UDP:
print(output, " ", packet_log(_pkt.data<Udp_packet const>(~0UL), _cfg));
print(output, " ", packet_log(_pkt.data<Udp_packet const>(size_guard), _cfg));
break;
case Ipv4_packet::Protocol::ICMP:
print(output, " ", packet_log(_pkt.data<Icmp_packet const>(~0UL), _cfg));
print(output, " ", packet_log(_pkt.data<Icmp_packet const>(size_guard), _cfg));
break;
default: ; }
@ -297,7 +299,8 @@ void Packet_log<Udp_packet>::print(Output &output) const
}
/* print encapsulated packet */
if (Dhcp_packet::is_dhcp(&_pkt)) {
print(output, " ", packet_log(_pkt.data<Dhcp_packet const>(~0UL), _cfg));
Size_guard size_guard(~0UL);
print(output, " ", packet_log(_pkt.data<Dhcp_packet const>(size_guard), _cfg));
}
}

View File

@ -16,7 +16,6 @@
#include <interface.h>
#include <domain.h>
#include <configuration.h>
#include <size_guard.h>
enum { PKT_SIZE = 1024 };
@ -24,7 +23,6 @@ using namespace Genode;
using namespace Net;
using Message_type = Dhcp_packet::Message_type;
using Drop_packet_inform = Net::Interface::Drop_packet_inform;
using Size_guard = Size_guard_tpl<PKT_SIZE, Net::Interface::Send_buffer_too_small>;
using Dhcp_options = Dhcp_packet::Options_aggregator<Size_guard>;
@ -112,39 +110,31 @@ void Dhcp_client::_handle_timeout(Duration)
}
void Dhcp_client::handle_ip(Ethernet_frame &eth, size_t eth_size)
void Dhcp_client::handle_ip(Ethernet_frame &eth,
Size_guard &size_guard)
{
if (eth.dst() != _interface.router_mac() &&
eth.dst() != Mac_address(0xff))
{
throw Drop_packet_inform("DHCP client expects Ethernet targeting the router");
}
size_t const ip_max_size = eth_size - sizeof(Ethernet_frame);
Ipv4_packet &ip = eth.data<Ipv4_packet>(ip_max_size);
size_t const ip_size = ip.size(ip_max_size);
{ throw Drop_packet_inform("DHCP client expects Ethernet targeting the router"); }
Ipv4_packet &ip = eth.data<Ipv4_packet>(size_guard);
if (ip.protocol() != Ipv4_packet::Protocol::UDP) {
throw Drop_packet_inform("DHCP client expects UDP packet");
}
size_t const udp_size = ip_size - sizeof(Ipv4_packet);
Udp_packet &udp = ip.data<Udp_packet>(udp_size);
throw Drop_packet_inform("DHCP client expects UDP packet"); }
Udp_packet &udp = ip.data<Udp_packet>(size_guard);
if (!Dhcp_packet::is_dhcp(&udp)) {
throw Drop_packet_inform("DHCP client expects DHCP packet");
}
size_t const dhcp_size = udp_size - sizeof(Udp_packet);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(dhcp_size);
throw Drop_packet_inform("DHCP client expects DHCP packet"); }
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size_guard);
if (dhcp.op() != Dhcp_packet::REPLY) {
throw Drop_packet_inform("DHCP client expects DHCP reply");
}
throw Drop_packet_inform("DHCP client expects DHCP reply"); }
if (dhcp.client_mac() != _interface.router_mac()) {
throw Drop_packet_inform("DHCP client expects DHCP targeting the router");
}
throw Drop_packet_inform("DHCP client expects DHCP targeting the router"); }
try { _handle_dhcp_reply(dhcp); }
catch (Dhcp_packet::Option_not_found) {
throw Drop_packet_inform("DHCP client misses DHCP option");
}
throw Drop_packet_inform("DHCP client misses DHCP option"); }
}
@ -202,20 +192,18 @@ void Dhcp_client::_send(Message_type msg_type,
Ipv4_address requested_ip)
{
Mac_address client_mac = _interface.router_mac();
_interface.send(PKT_SIZE, [&] (void *pkt_base) {
_interface.send(PKT_SIZE, [&] (void *pkt_base, Size_guard &size_guard) {
/* create ETH header of the request */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
Ethernet_frame &eth = Ethernet_frame::construct_at(pkt_base, size_guard);
eth.dst(Mac_address(0xff));
eth.src(client_mac);
eth.type(Ethernet_frame::Type::IPV4);
/* create IP header of the request */
enum { IPV4_TIME_TO_LIVE = 64 };
size_t const ip_off = size.curr();
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size);
size_t const ip_off = size_guard.head_size();
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size_guard);
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.time_to_live(IPV4_TIME_TO_LIVE);
@ -224,14 +212,14 @@ void Dhcp_client::_send(Message_type msg_type,
ip.dst(Ipv4_address(0xff));
/* create UDP header of the request */
size_t const udp_off = size.curr();
Udp_packet &udp = ip.construct_at_data<Udp_packet>(size);
size_t const udp_off = size_guard.head_size();
Udp_packet &udp = ip.construct_at_data<Udp_packet>(size_guard);
udp.src_port(Port(Dhcp_packet::BOOTPC));
udp.dst_port(Port(Dhcp_packet::BOOTPS));
/* create mandatory DHCP fields of the request */
size_t const dhcp_off = size.curr();
Dhcp_packet &dhcp = udp.construct_at_data<Dhcp_packet>(size);
size_t const dhcp_off = size_guard.head_size();
Dhcp_packet &dhcp = udp.construct_at_data<Dhcp_packet>(size_guard);
dhcp.op(Dhcp_packet::REQUEST);
dhcp.htype(Dhcp_packet::Htype::ETH);
dhcp.hlen(sizeof(Mac_address));
@ -240,7 +228,7 @@ void Dhcp_client::_send(Message_type msg_type,
dhcp.default_magic_cookie();
/* append DHCP option fields to the request */
Dhcp_options dhcp_opts(dhcp, size);
Dhcp_options dhcp_opts(dhcp, size_guard);
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
switch (msg_type) {
case Message_type::DISCOVER:
@ -265,9 +253,9 @@ void Dhcp_client::_send(Message_type msg_type,
dhcp_opts.append_option<Dhcp_packet::Options_end>();
/* fill in header values that need the packet to be complete already */
udp.length(size.curr() - udp_off);
udp.length(size_guard.head_size() - udp_off);
udp.update_checksum(ip.src(), ip.dst());
ip.total_length(size.curr() - ip_off);
ip.total_length(size_guard.head_size() - ip_off);
ip.update_checksum();
});
}

View File

@ -67,7 +67,8 @@ class Net::Dhcp_client
Timer::Connection &timer,
Interface &interface);
void handle_ip(Ethernet_frame &eth, Genode::size_t eth_size);
void handle_ip(Ethernet_frame &eth,
Size_guard &size_guard);
void discover();
};

View File

@ -21,7 +21,6 @@
#include <interface.h>
#include <configuration.h>
#include <l3_protocol.h>
#include <size_guard.h>
using namespace Net;
using Genode::Deallocator;
@ -166,13 +165,13 @@ static void _src_port(L3_protocol const prot,
static void *_prot_base(L3_protocol const prot,
size_t const prot_size,
Size_guard &size_guard,
Ipv4_packet &ip)
{
switch (prot) {
case L3_protocol::TCP: return &ip.data<Tcp_packet>(prot_size);
case L3_protocol::UDP: return &ip.data<Udp_packet>(prot_size);
case L3_protocol::ICMP: return &ip.data<Icmp_packet>(prot_size);
case L3_protocol::TCP: return &ip.data<Tcp_packet>(size_guard);
case L3_protocol::UDP: return &ip.data<Udp_packet>(size_guard);
case L3_protocol::ICMP: return &ip.data<Icmp_packet>(size_guard);
default: throw Interface::Bad_transport_protocol(); }
}
@ -193,23 +192,23 @@ void Interface::_destroy_link(Link &link)
void Interface::_pass_prot(Ethernet_frame &eth,
size_t const eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
L3_protocol const prot,
void *const prot_base,
size_t const prot_size)
{
_update_checksum(prot, prot_base, prot_size, ip.src(), ip.dst(), ip.total_length());
_pass_ip(eth, eth_size, ip);
_pass_ip(eth, size_guard, ip);
}
void Interface::_pass_ip(Ethernet_frame &eth,
size_t const eth_size,
Size_guard &size_guard,
Ipv4_packet &ip)
{
ip.update_checksum();
send(eth, eth_size);
send(eth, size_guard);
}
@ -422,7 +421,7 @@ void Interface::_adapt_eth(Ethernet_frame &eth,
void Interface::_nat_link_and_pass(Ethernet_frame &eth,
size_t const eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
L3_protocol const prot,
void *const prot_base,
@ -446,7 +445,7 @@ void Interface::_nat_link_and_pass(Ethernet_frame &eth,
ip.src(), _src_port(prot, prot_base) };
_new_link(prot, local_id, remote_port_alloc, remote_domain, remote_id);
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface._pass_prot(eth, eth_size, ip, prot, prot_base, prot_size);
interface._pass_prot(eth, size_guard, ip, prot, prot_base, prot_size);
});
}
@ -459,20 +458,17 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
Ipv4_address_prefix const &local_intf)
{
enum { PKT_SIZE = 512 };
using Size_guard = Genode::Size_guard_tpl<PKT_SIZE, Send_buffer_too_small>;
send(PKT_SIZE, [&] (void *pkt_base) {
send(PKT_SIZE, [&] (void *pkt_base, Size_guard &size_guard) {
/* create ETH header of the reply */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
Ethernet_frame &eth = Ethernet_frame::construct_at(pkt_base, size_guard);
eth.dst(client_mac);
eth.src(_router_mac);
eth.type(Ethernet_frame::Type::IPV4);
/* create IP header of the reply */
size_t const ip_off = size.curr();
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size);
size_t const ip_off = size_guard.head_size();
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size_guard);
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.time_to_live(IPV4_TIME_TO_LIVE);
@ -481,13 +477,13 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
ip.dst(client_ip);
/* create UDP header of the reply */
size_t const udp_off = size.curr();
Udp_packet &udp = ip.construct_at_data<Udp_packet>(size);
size_t const udp_off = size_guard.head_size();
Udp_packet &udp = ip.construct_at_data<Udp_packet>(size_guard);
udp.src_port(Port(Dhcp_packet::BOOTPS));
udp.dst_port(Port(Dhcp_packet::BOOTPC));
/* create mandatory DHCP fields of the reply */
Dhcp_packet &dhcp = udp.construct_at_data<Dhcp_packet>(size);
Dhcp_packet &dhcp = udp.construct_at_data<Dhcp_packet>(size_guard);
dhcp.op(Dhcp_packet::REPLY);
dhcp.htype(Dhcp_packet::Htype::ETH);
dhcp.hlen(sizeof(Mac_address));
@ -501,7 +497,7 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
dhcp.default_magic_cookie();
/* append DHCP option fields to the reply */
Dhcp_packet::Options_aggregator<Size_guard> dhcp_opts(dhcp, size);
Dhcp_packet::Options_aggregator<Size_guard> dhcp_opts(dhcp, size_guard);
dhcp_opts.append_option<Dhcp_packet::Message_type_option>(msg_type);
dhcp_opts.append_option<Dhcp_packet::Server_ipv4>(local_intf.address);
dhcp_opts.append_option<Dhcp_packet::Ip_lease_time>(dhcp_srv.ip_lease_time().value / 1000 / 1000);
@ -513,9 +509,9 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
dhcp_opts.append_option<Dhcp_packet::Options_end>();
/* fill in header values that need the packet to be complete already */
udp.length(size.curr() - udp_off);
udp.length(size_guard.head_size() - udp_off);
udp.update_checksum(ip.src(), ip.dst());
ip.total_length(size.curr() - ip_off);
ip.total_length(size_guard.head_size() - ip_off);
ip.update_checksum();
});
}
@ -556,7 +552,7 @@ void Interface::_new_dhcp_allocation(Ethernet_frame &eth,
}
void Interface::_handle_dhcp_request(Ethernet_frame &eth, size_t ,
void Interface::_handle_dhcp_request(Ethernet_frame &eth,
Dhcp_packet &dhcp,
Domain &local_domain)
{
@ -677,13 +673,13 @@ void Interface::_handle_dhcp_request(Ethernet_frame &eth, size_t ,
void Interface::_domain_broadcast(Ethernet_frame &eth,
size_t eth_size,
Size_guard &size_guard,
Domain &local_domain)
{
eth.src(_router_mac);
local_domain.interfaces().for_each([&] (Interface &interface) {
if (&interface != this) {
interface.send(eth, eth_size);
interface.send(eth, size_guard);
}
});
}
@ -699,20 +695,17 @@ void Interface::_send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf
PKT_SIZE = sizeof(Ethernet_frame) + sizeof(Ipv4_packet) +
sizeof(Icmp_packet) + ICMP_MAX_DATA_SIZE,
};
using Size_guard = Genode::Size_guard_tpl<PKT_SIZE, Send_buffer_too_small>;
send(PKT_SIZE, [&] (void *pkt_base) {
send(PKT_SIZE, [&] (void *pkt_base, Size_guard &size_guard) {
/* create ETH header */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
Ethernet_frame &eth = Ethernet_frame::construct_at(pkt_base, size_guard);
eth.dst(req_eth.src());
eth.src(_router_mac);
eth.type(Ethernet_frame::Type::IPV4);
/* create IP header */
size_t const ip_off = size.curr();
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size);
size_t const ip_off = size_guard.head_size();
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size_guard);
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.time_to_live(IPV4_TIME_TO_LIVE);
@ -721,7 +714,7 @@ void Interface::_send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf
ip.dst(req_ip.src());
/* create ICMP header */
Icmp_packet &icmp = ip.construct_at_data<Icmp_packet>(size);
Icmp_packet &icmp = ip.construct_at_data<Icmp_packet>(size_guard);
icmp.type(Icmp_packet::Type::DST_UNREACHABLE);
icmp.code(code);
size_t icmp_data_size = req_ip.total_length();
@ -729,19 +722,18 @@ void Interface::_send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf
icmp_data_size = ICMP_MAX_DATA_SIZE;
}
/* create ICMP data */
size.add(icmp_data_size);
Genode::memcpy(&icmp.data<char>(~0), &req_ip, icmp_data_size);
icmp.copy_to_data(&req_ip, icmp_data_size, size_guard);
/* fill in header values that require the packet to be complete */
icmp.update_checksum(icmp_data_size);
ip.total_length(size.curr() - ip_off);
ip.total_length(size_guard.head_size() - ip_off);
ip.update_checksum();
});
}
void Interface::_handle_icmp_query(Ethernet_frame &eth,
size_t eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
Packet_descriptor const &pkt,
L3_protocol prot,
@ -769,7 +761,7 @@ void Interface::_handle_icmp_query(Ethernet_frame &eth,
_dst_port(prot, prot_base, remote_side.src_port());
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface._pass_prot(eth, eth_size, ip, prot, prot_base, prot_size);
interface._pass_prot(eth, size_guard, ip, prot, prot_base, prot_size);
});
_link_packet(prot, prot_base, link, client);
return;
@ -786,7 +778,7 @@ void Interface::_handle_icmp_query(Ethernet_frame &eth,
Domain &remote_domain = rule.domain();
_adapt_eth(eth, local_id.dst_ip, pkt, remote_domain);
_nat_link_and_pass(eth, eth_size, ip, prot, prot_base, prot_size,
_nat_link_and_pass(eth, size_guard, ip, prot, prot_base, prot_size,
local_id, local_domain, remote_domain);
return;
@ -798,7 +790,7 @@ void Interface::_handle_icmp_query(Ethernet_frame &eth,
void Interface::_handle_icmp_error(Ethernet_frame &eth,
size_t eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
Packet_descriptor const &pkt,
Domain &local_domain,
@ -806,15 +798,13 @@ void Interface::_handle_icmp_error(Ethernet_frame &eth,
size_t icmp_sz)
{
/* drop packet if embedded IP checksum invalid */
size_t const embed_ip_sz = icmp_sz - sizeof(Icmp_packet);
Ipv4_packet &embed_ip = icmp.data<Ipv4_packet>(embed_ip_sz);
Ipv4_packet &embed_ip = icmp.data<Ipv4_packet>(size_guard);
if (embed_ip.checksum_error()) {
throw Drop_packet_inform("bad checksum in IP packet embedded in ICMP error");
}
/* get link identity of the embeddeded transport packet */
L3_protocol const embed_prot = embed_ip.protocol();
size_t const embed_prot_size = embed_ip.total_length() - embed_ip.header_length() * 4;
void *const embed_prot_base = _prot_base(embed_prot, embed_prot_size, embed_ip);
void *const embed_prot_base = _prot_base(embed_prot, size_guard, embed_ip);
Link_side_id const local_id = { embed_ip.dst(), _dst_port(embed_prot, embed_prot_base),
embed_ip.src(), _src_port(embed_prot, embed_prot_base) };
try {
@ -849,7 +839,7 @@ void Interface::_handle_icmp_error(Ethernet_frame &eth,
/* send adapted packet to all interfaces of remote domain */
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface.send(eth, eth_size);
interface.send(eth, size_guard);
});
/* refresh link only if the error is not about an ICMP query */
if (embed_prot != L3_protocol::ICMP) {
@ -862,7 +852,7 @@ void Interface::_handle_icmp_error(Ethernet_frame &eth,
void Interface::_handle_icmp(Ethernet_frame &eth,
size_t eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
Packet_descriptor const &pkt,
L3_protocol prot,
@ -871,30 +861,26 @@ void Interface::_handle_icmp(Ethernet_frame &eth,
Domain &local_domain)
{
/* drop packet if ICMP checksum is invalid */
size_t const icmp_sz = ip.total_length() - sizeof(Ipv4_packet);
Icmp_packet &icmp = ip.data<Icmp_packet>(icmp_sz);
size_t const icmp_data_sz = icmp_sz - sizeof(Icmp_packet);
if (icmp.checksum_error(icmp_data_sz)) {
Icmp_packet &icmp = *reinterpret_cast<Icmp_packet *>(prot_base);
if (icmp.checksum_error(size_guard.unconsumed())) {
throw Drop_packet_inform("bad ICMP checksum");
}
/* select ICMP message type */
switch (icmp.type()) {
case Icmp_packet::Type::ECHO_REPLY:
case Icmp_packet::Type::ECHO_REQUEST: _handle_icmp_query(eth, eth_size, ip, pkt, prot, prot_base, prot_size, local_domain); break;
case Icmp_packet::Type::DST_UNREACHABLE: _handle_icmp_error(eth, eth_size, ip, pkt, local_domain, icmp, icmp_sz); break;
case Icmp_packet::Type::ECHO_REQUEST: _handle_icmp_query(eth, size_guard, ip, pkt, prot, prot_base, prot_size, local_domain); break;
case Icmp_packet::Type::DST_UNREACHABLE: _handle_icmp_error(eth, size_guard, ip, pkt, local_domain, icmp, prot_size); break;
default: Drop_packet_inform("unknown ICMP message type"); }
}
void Interface::_handle_ip(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Packet_descriptor const &pkt,
Domain &local_domain)
{
/* read packet information */
size_t const ip_max_size = eth_size - sizeof(Ethernet_frame);
Ipv4_packet &ip = eth.data<Ipv4_packet>(ip_max_size);
size_t const ip_size = ip.size(ip_max_size);
Ipv4_packet &ip = eth.data<Ipv4_packet>(size_guard);
Ipv4_address_prefix const &local_intf = local_domain.ip_config().interface;
/* try handling subnet-local IP packets */
@ -905,40 +891,38 @@ void Interface::_handle_ip(Ethernet_frame &eth,
* Packet targets IP local to the domain's subnet and doesn't target
* the router. Thus, forward it to all other interfaces of the domain.
*/
_domain_broadcast(eth, eth_size, local_domain);
_domain_broadcast(eth, size_guard, local_domain);
return;
}
/* try to route via transport layer rules */
try {
L3_protocol const prot = ip.protocol();
size_t const prot_size = ip_size - sizeof(Ipv4_packet);
void *const prot_base = _prot_base(prot, prot_size, ip);
size_t const prot_size = size_guard.unconsumed();
void *const prot_base = _prot_base(prot, size_guard, ip);
/* try handling DHCP requests before trying any routing */
if (prot == L3_protocol::UDP) {
Udp_packet &udp = ip.data<Udp_packet>(prot_size);
Udp_packet &udp = *reinterpret_cast<Udp_packet *>(prot_base);
if (Dhcp_packet::is_dhcp(&udp)) {
/* get DHCP packet */
size_t const dhcp_size = prot_size - sizeof(Udp_packet);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(dhcp_size);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size_guard);
if (dhcp.op() == Dhcp_packet::REQUEST) {
try {
_handle_dhcp_request(eth, eth_size, dhcp, local_domain);
_handle_dhcp_request(eth, dhcp, local_domain);
return;
}
catch (Pointer<Dhcp_server>::Invalid) { }
} else {
_dhcp_client.handle_ip(eth, eth_size);
_dhcp_client.handle_ip(eth, size_guard);
return;
}
}
}
else if (prot == L3_protocol::ICMP) {
_handle_icmp(eth, eth_size, ip, pkt, prot, prot_base, prot_size, local_domain);
_handle_icmp(eth, size_guard, ip, pkt, prot, prot_base, prot_size, local_domain);
return;
}
@ -962,7 +946,7 @@ void Interface::_handle_ip(Ethernet_frame &eth,
_dst_port(prot, prot_base, remote_side.src_port());
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface._pass_prot(eth, eth_size, ip, prot, prot_base, prot_size);
interface._pass_prot(eth, size_guard, ip, prot, prot_base, prot_size);
});
_link_packet(prot, prot_base, link, client);
return;
@ -981,7 +965,7 @@ void Interface::_handle_ip(Ethernet_frame &eth,
Domain &remote_domain = rule.domain();
_adapt_eth(eth, rule.to(), pkt, remote_domain);
ip.dst(rule.to());
_nat_link_and_pass(eth, eth_size, ip, prot, prot_base,
_nat_link_and_pass(eth, size_guard, ip, prot, prot_base,
prot_size, local_id, local_domain, remote_domain);
return;
}
@ -1001,7 +985,7 @@ void Interface::_handle_ip(Ethernet_frame &eth,
Domain &remote_domain = permit_rule.domain();
_adapt_eth(eth, local_id.dst_ip, pkt, remote_domain);
_nat_link_and_pass(eth, eth_size, ip, prot, prot_base, prot_size,
_nat_link_and_pass(eth, size_guard, ip, prot, prot_base, prot_size,
local_id, local_domain, remote_domain);
return;
}
@ -1021,7 +1005,7 @@ void Interface::_handle_ip(Ethernet_frame &eth,
Domain &remote_domain = rule.domain();
_adapt_eth(eth, ip.dst(), pkt, remote_domain);
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface._pass_ip(eth, eth_size, ip);
interface._pass_ip(eth, size_guard, ip);
});
return;
@ -1047,19 +1031,16 @@ void Interface::_broadcast_arp_request(Ipv4_address const &src_ip,
ETH_CRC_SZ = sizeof(Genode::uint32_t),
PKT_SIZE = ETH_HDR_SZ + ETH_DAT_SZ + ETH_CRC_SZ,
};
using Size_guard = Genode::Size_guard_tpl<PKT_SIZE, Send_buffer_too_small>;
send(PKT_SIZE, [&] (void *pkt_base) {
send(PKT_SIZE, [&] (void *pkt_base, Size_guard &size_guard) {
/* write Ethernet header */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
Ethernet_frame &eth = Ethernet_frame::construct_at(pkt_base, size_guard);
eth.dst(Mac_address(0xff));
eth.src(_router_mac);
eth.type(Ethernet_frame::Type::ARP);
/* write ARP header */
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size);
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size_guard);
arp.hardware_address_type(Arp_packet::ETHERNET);
arp.protocol_address_type(Arp_packet::IPV4);
arp.hardware_address_size(sizeof(Mac_address));
@ -1074,7 +1055,7 @@ void Interface::_broadcast_arp_request(Ipv4_address const &src_ip,
void Interface::_handle_arp_reply(Ethernet_frame &eth,
size_t const eth_size,
Size_guard &size_guard,
Arp_packet &arp,
Domain &local_domain)
{
@ -1109,13 +1090,13 @@ void Interface::_handle_arp_reply(Ethernet_frame &eth,
* Packet targets IP local to the domain's subnet and doesn't target
* the router. Thus, forward it to all other interfaces of the domain.
*/
_domain_broadcast(eth, eth_size, local_domain);
_domain_broadcast(eth, size_guard, local_domain);
}
}
void Interface::_send_arp_reply(Ethernet_frame &eth,
size_t const eth_size,
Size_guard &size_guard,
Arp_packet &arp)
{
/* interchange source and destination MAC and IP addresses */
@ -1129,12 +1110,12 @@ void Interface::_send_arp_reply(Ethernet_frame &eth,
/* mark packet as reply and send it back to its sender */
arp.opcode(Arp_packet::REPLY);
send(eth, eth_size);
send(eth, size_guard);
}
void Interface::_handle_arp_request(Ethernet_frame &eth,
size_t const eth_size,
Size_guard &size_guard,
Arp_packet &arp,
Domain &local_domain)
{
@ -1151,12 +1132,12 @@ void Interface::_handle_arp_request(Ethernet_frame &eth,
} else if (arp.dst_ip() == local_intf.address) {
/* ARP request for the routers IP at this domain */
_send_arp_reply(eth, eth_size, arp);
_send_arp_reply(eth, size_guard, arp);
} else {
/* forward request to all other interfaces of the domain */
_domain_broadcast(eth, eth_size, local_domain);
_domain_broadcast(eth, size_guard, local_domain);
}
} else {
@ -1170,24 +1151,24 @@ void Interface::_handle_arp_request(Ethernet_frame &eth,
} else {
/* try to act as gateway for the domain as none is configured */
_send_arp_reply(eth, eth_size, arp);
_send_arp_reply(eth, size_guard, arp);
}
}
}
void Interface::_handle_arp(Ethernet_frame &eth,
size_t const eth_size,
Size_guard &size_guard,
Domain &local_domain)
{
/* ignore ARP regarding protocols other than IPv4 via ethernet */
Arp_packet &arp = eth.data<Arp_packet>(eth_size - sizeof(Ethernet_frame));
Arp_packet &arp = eth.data<Arp_packet>(size_guard);
if (!arp.ethernet_ipv4()) {
error("ARP for unknown protocol"); }
switch (arp.opcode()) {
case Arp_packet::REPLY: _handle_arp_reply(eth, eth_size, arp, local_domain); break;
case Arp_packet::REQUEST: _handle_arp_request(eth, eth_size, arp, local_domain); break;
case Arp_packet::REPLY: _handle_arp_reply(eth, size_guard, arp, local_domain); break;
case Arp_packet::REQUEST: _handle_arp_request(eth, size_guard, arp, local_domain); break;
default: error("unknown ARP operation"); }
}
@ -1195,12 +1176,9 @@ void Interface::_handle_arp(Ethernet_frame &eth,
void Interface::_ready_to_submit()
{
while (_sink().packet_avail()) {
Packet_descriptor const pkt = _sink().get_packet();
if (!pkt.size()) {
continue; }
try { _handle_eth(_sink().packet_content(pkt), pkt.size(), pkt); }
Size_guard size_guard(pkt.size());
try { _handle_eth(_sink().packet_content(pkt), size_guard, pkt); }
catch (Packet_postponed) { continue; }
_ack_packet(pkt);
}
@ -1209,7 +1187,8 @@ void Interface::_ready_to_submit()
void Interface::_continue_handle_eth(Packet_descriptor const &pkt)
{
try { _handle_eth(_sink().packet_content(pkt), pkt.size(), pkt); }
Size_guard size_guard(pkt.size());
try { _handle_eth(_sink().packet_content(pkt), size_guard, pkt); }
catch (Packet_postponed) { error("failed twice to handle packet"); }
_ack_packet(pkt);
}
@ -1240,60 +1219,66 @@ void Interface::_destroy_released_dhcp_allocations(Domain &local_domain)
void Interface::_handle_eth(void *const eth_base,
size_t const eth_size,
Size_guard &size_guard,
Packet_descriptor const &pkt)
{
try {
Domain &local_domain = _domain();
local_domain.raise_rx_bytes(size_guard.total_size());
try {
local_domain.raise_rx_bytes(eth_size);
Ethernet_frame &eth = Ethernet_frame::cast_from(eth_base, size_guard);
try {
/* do garbage collection over transport-layer links and DHCP allocations */
_destroy_dissolved_links<Icmp_link>(_dissolved_icmp_links, _alloc);
_destroy_dissolved_links<Udp_link>(_dissolved_udp_links, _alloc);
_destroy_dissolved_links<Tcp_link>(_dissolved_tcp_links, _alloc);
_destroy_released_dhcp_allocations(local_domain);
/* do garbage collection over transport-layer links and DHCP allocations */
_destroy_dissolved_links<Icmp_link>(_dissolved_icmp_links, _alloc);
_destroy_dissolved_links<Udp_link>(_dissolved_udp_links, _alloc);
_destroy_dissolved_links<Tcp_link>(_dissolved_tcp_links, _alloc);
_destroy_released_dhcp_allocations(local_domain);
if (local_domain.verbose_packets()) {
log("[", local_domain, "] rcv ", eth); }
/* inspect and handle ethernet frame */
Ethernet_frame *const eth = reinterpret_cast<Ethernet_frame *>(eth_base);
if (local_domain.verbose_packets()) {
log("[", local_domain, "] rcv ", *eth); }
if (local_domain.ip_config().valid) {
if (local_domain.ip_config().valid) {
switch (eth.type()) {
case Ethernet_frame::Type::ARP: _handle_arp(eth, size_guard, local_domain); break;
case Ethernet_frame::Type::IPV4: _handle_ip(eth, size_guard, pkt, local_domain); break;
default: throw Bad_network_protocol(); }
switch (eth->type()) {
case Ethernet_frame::Type::ARP: _handle_arp(*eth, eth_size, local_domain); break;
case Ethernet_frame::Type::IPV4: _handle_ip(*eth, eth_size, pkt, local_domain); break;
default: throw Bad_network_protocol(); }
} else {
} else {
switch (eth->type()) {
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(*eth, eth_size); break;
default: throw Bad_network_protocol(); }
switch (eth.type()) {
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(eth, size_guard); break;
default: throw Bad_network_protocol(); }
}
}
catch (Drop_packet_warn exception) { warning("[", local_domain, "] drop packet: ", exception.msg); }
catch (Dhcp_server::Alloc_ip_failed) { error ("[", local_domain, "] failed to allocate IP for DHCP client"); }
catch (Port_allocator_guard::Out_of_indices) { error ("[", local_domain, "] no available NAT ports"); }
catch (Domain::No_next_hop) { error ("[", local_domain, "] cannot find next hop"); }
catch (Alloc_dhcp_msg_buffer_failed) { error ("[", local_domain, "] failed to allocate buffer for DHCP reply"); }
catch (Bad_network_protocol) {
if (_config().verbose()) {
log("[", local_domain, "] unknown network layer protocol"); }
}
catch (Drop_packet_inform exception) {
if (_config().verbose()) {
log("[", local_domain, "] drop packet: ", exception.msg); }
}
}
catch (Ethernet_frame::Bad_data_type) { warning("[", local_domain, "] malformed Ethernet frame"); }
catch (Ipv4_packet::Bad_data_type) { warning("[", local_domain, "] malformed IPv4 packet" ); }
catch (Udp_packet::Bad_data_type) { warning("[", local_domain, "] malformed UDP packet" ); }
catch (Drop_packet_warn exception) { warning("[", local_domain, "] drop packet: ", exception.msg); }
catch (Dhcp_server::Alloc_ip_failed) { error ("[", local_domain, "] failed to allocate IP for DHCP client"); }
catch (Send_buffer_too_small) { error ("[", local_domain, "] send buffer buffer too small"); }
catch (Port_allocator_guard::Out_of_indices) { error ("[", local_domain, "] no available NAT ports"); }
catch (Domain::No_next_hop) { error ("[", local_domain, "] cannot find next hop"); }
catch (Alloc_dhcp_msg_buffer_failed) { error ("[", local_domain, "] failed to allocate buffer for DHCP reply"); }
catch (Bad_network_protocol) {
catch (Size_guard::Exceeded) {
if (_config().verbose()) {
log("[", local_domain, "] unknown network layer protocol"); }
}
catch (Drop_packet_inform exception) {
if (_config().verbose()) {
log("[", local_domain, "] drop packet: ", exception.msg); }
log("[", local_domain, "] drop packet: packet size-guard exceeded"); }
}
}
catch (Pointer<Domain>::Invalid) {
if (_config().verbose_packets()) {
log("[?] rcv ", *reinterpret_cast<Ethernet_frame *>(eth_base));
try {
Ethernet_frame &eth = Ethernet_frame::cast_from(eth_base, size_guard);
if (_config().verbose_packets()) {
log("[?] rcv ", eth); }
}
catch (Size_guard::Exceeded) {
if (_config().verbose_packets()) {
log("[?] rcv ?"); }
}
if (_config().verbose()) {
log("[?] drop packet: no domain"); }
@ -1301,10 +1286,11 @@ void Interface::_handle_eth(void *const eth_base,
}
void Interface::send(Ethernet_frame &eth, size_t eth_size)
void Interface::send(Ethernet_frame &eth,
Size_guard &size_guard)
{
send(eth_size, [&] (void *pkt_base) {
Genode::memcpy(pkt_base, (void *)&eth, eth_size);
send(size_guard.total_size(), [&] (void *pkt_base, Size_guard &size_guard) {
Genode::memcpy(pkt_base, (void *)&eth, size_guard.total_size());
});
}
@ -1325,8 +1311,12 @@ void Interface::_send_submit_pkt(Packet_descriptor &pkt,
Domain &local_domain = _domain();
local_domain.raise_tx_bytes(pkt_size);
if (local_domain.verbose_packets()) {
log("[", local_domain, "] snd ",
*reinterpret_cast<Ethernet_frame *>(pkt_base));
try {
Size_guard size_guard(pkt_size);
log("[", local_domain, "] snd ",
Ethernet_frame::cast_from(pkt_base, size_guard));
}
catch (Size_guard::Exceeded) { log("[", local_domain, "] snd ?"); }
}
_source().submit_packet(pkt);
}

View File

@ -133,35 +133,34 @@ class Net::Interface : private Interface_list::Element
L3_protocol const prot) const;
void _handle_arp(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Domain &local_domain);
void _handle_arp_reply(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Arp_packet &arp,
Domain &local_domain);
void _handle_arp_request(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Arp_packet &arp,
Domain &local_domain);
void _send_arp_reply(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Arp_packet &arp);
void _handle_dhcp_request(Ethernet_frame &eth,
Genode::size_t eth_size,
Dhcp_packet &dhcp,
Domain &local_domain);
void _handle_ip(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Packet_descriptor const &pkt,
Domain &local_domain);
void _handle_icmp_query(Ethernet_frame &eth,
Genode::size_t eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
Packet_descriptor const &pkt,
L3_protocol prot,
@ -170,7 +169,7 @@ class Net::Interface : private Interface_list::Element
Domain &local_domain);
void _handle_icmp_error(Ethernet_frame &eth,
Genode::size_t eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
Packet_descriptor const &pkt,
Domain &local_domain,
@ -178,7 +177,7 @@ class Net::Interface : private Interface_list::Element
Genode::size_t icmp_sz);
void _handle_icmp(Ethernet_frame &eth,
Genode::size_t eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
Packet_descriptor const &pkt,
L3_protocol prot,
@ -192,7 +191,7 @@ class Net::Interface : private Interface_list::Element
Domain &remote_domain);
void _nat_link_and_pass(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
L3_protocol const prot,
void *const prot_base,
@ -205,18 +204,18 @@ class Net::Interface : private Interface_list::Element
Ipv4_address const &dst_ip);
void _domain_broadcast(Ethernet_frame &eth,
Genode::size_t eth_size,
Size_guard &size_guard,
Domain &local_domain);
void _pass_prot(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Ipv4_packet &ip,
L3_protocol const prot,
void *const prot_base,
Genode::size_t const prot_size);
void _pass_ip(Ethernet_frame &eth,
Genode::size_t const eth_size,
Size_guard &size_guard,
Ipv4_packet &ip);
void _continue_handle_eth(Packet_descriptor const &pkt);
@ -224,7 +223,7 @@ class Net::Interface : private Interface_list::Element
Ipv4_address const &_router_ip() const;
void _handle_eth(void *const eth_base,
Genode::size_t const eth_size,
Size_guard &size_guard,
Packet_descriptor const &pkt);
void _ack_packet(Packet_descriptor const &pkt);
@ -293,7 +292,6 @@ class Net::Interface : private Interface_list::Element
struct Bad_network_protocol : Genode::Exception { };
struct Packet_postponed : Genode::Exception { };
struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { };
struct Send_buffer_too_small : Genode::Exception { };
struct Drop_packet_inform : Genode::Exception
{
@ -332,7 +330,8 @@ class Net::Interface : private Interface_list::Element
void *pkt_base;
_send_alloc_pkt(pkt, pkt_base, pkt_size);
write_to_pkt(pkt_base);
Size_guard size_guard(pkt_size);
write_to_pkt(pkt_base, size_guard);
_send_submit_pkt(pkt, pkt_base, pkt_size);
}
catch (Packet_stream_source::Packet_alloc_failed) {
@ -340,7 +339,8 @@ class Net::Interface : private Interface_list::Element
}
}
void send(Ethernet_frame &eth, Genode::size_t eth_size);
void send(Ethernet_frame &eth,
Size_guard &size_guard);
Link_list &dissolved_links(L3_protocol const protocol);

View File

@ -1,46 +0,0 @@
/*
* \brief Utility to ensure that a size value doesn't exceed a limit
* \author Martin Stein
* \date 2016-08-24
*/
/*
* 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.
*/
#ifndef _SIZE_GUARD_H_
#define _SIZE_GUARD_H_
/* Genode includes */
#include <base/stdint.h>
namespace Genode {
template <size_t MAX, typename EXCEPTION>
class Size_guard_tpl;
}
template <Genode::size_t MAX, typename EXCEPTION>
class Genode::Size_guard_tpl
{
private:
size_t _curr { 0 };
public:
void add(size_t size)
{
size_t const new_size = _curr + size;
if (new_size > MAX) { throw EXCEPTION(); }
_curr = new_size;
}
size_t curr() const { return _curr; }
size_t left() const { return MAX - _curr; }
};
#endif /* _SIZE_GUARD_H_ */