net: consider tail of Ethernet frame

The Ethernet payload may be followed by padding of variable length and
the FCS (Frame Check Sequence). Thus, we should consider the value
"Ethernet-frame size minus Ethernet-header size" to be only the maximum
size of the encapsulated IP packet. But until now, we considered it to
be also the actual size of the encapsulated IP packet. This commit fixes
the problem for all affected components of the Genode base-repository.

Fixes #2775
This commit is contained in:
Martin Stein 2018-04-18 19:38:43 +02:00 committed by Christian Helmuth
parent 841d583678
commit 11a297b557
7 changed files with 47 additions and 27 deletions

View File

@ -151,6 +151,8 @@ class Net::Ipv4_packet
return *Genode::construct_at<T>(_data);
}
Genode::size_t size(Genode::size_t max_size) const;
/***************
** Accessors **

View File

@ -199,8 +199,9 @@ void Main::_handle_ip(Ethernet_frame &eth,
size_t const eth_size)
{
/* drop packet if IP does not target us */
size_t const ip_size = eth_size - sizeof(Ethernet_frame);
Ipv4_packet &ip = eth.data<Ipv4_packet>(ip_size);
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);
if (ip.dst() != _src_ip &&
ip.dst() != Ipv4_packet::broadcast())
{

View File

@ -146,3 +146,10 @@ bool Ipv4_packet::checksum_error() const
{
return internet_checksum((uint16_t *)this, sizeof(Ipv4_packet));
}
size_t Ipv4_packet::size(size_t max_size) const
{
size_t const stated_size = total_length();
return stated_size < max_size ? stated_size : max_size;
}

View File

@ -19,6 +19,8 @@
#include <component.h>
using namespace Net;
using namespace Genode;
bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
{
@ -50,17 +52,19 @@ bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
bool Session_component::handle_ip(Ethernet_frame *eth, Genode::size_t size)
{
Ipv4_packet &ip = eth->data<Ipv4_packet>(size - sizeof(Ethernet_frame));
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);
if (ip.protocol() == Ipv4_packet::Protocol::UDP) {
if (ip.protocol() == Ipv4_packet::Protocol::UDP)
{
Udp_packet &udp = ip.data<Udp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet));
size_t const udp_size = ip_size - sizeof(Ipv4_packet);
Udp_packet &udp = ip.data<Udp_packet>(udp_size);
if (Dhcp_packet::is_dhcp(&udp)) {
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet)
- sizeof(Udp_packet));
size_t const dhcp_size = udp_size - sizeof(Udp_packet);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(dhcp_size);
if (dhcp.op() == Dhcp_packet::REQUEST) {
dhcp.broadcast(true);
udp.update_checksum(ip.src(), ip.dst());
}

View File

@ -21,6 +21,7 @@
#include <component.h>
using namespace Net;
using namespace Genode;
bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
@ -65,19 +66,21 @@ bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
bool Net::Nic::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
Ipv4_packet &ip = eth->data<Ipv4_packet>(size - sizeof(Ethernet_frame));
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);
/* is it an UDP packet ? */
if (ip.protocol() == Ipv4_packet::Protocol::UDP)
{
Udp_packet &udp = ip.data<Udp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet));
size_t const udp_size = ip_size - sizeof(Ipv4_packet);
Udp_packet &udp = ip.data<Udp_packet>(udp_size);
/* is it a DHCP packet ? */
if (Dhcp_packet::is_dhcp(&udp)) {
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet)
- sizeof(Udp_packet));
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 */
if (dhcp.op() == Dhcp_packet::REPLY) {

View File

@ -119,20 +119,21 @@ void Dhcp_client::handle_ip(Ethernet_frame &eth, size_t eth_size)
{
throw Drop_packet_inform("DHCP client expects Ethernet targeting the router");
}
Ipv4_packet &ip = eth.data<Ipv4_packet>(eth_size - sizeof(Ethernet_frame));
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);
if (ip.protocol() != Ipv4_packet::Protocol::UDP) {
throw Drop_packet_inform("DHCP client expects UDP packet");
}
Udp_packet &udp = ip.data<Udp_packet>(eth_size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet));
size_t const udp_size = ip_size - sizeof(Ipv4_packet);
Udp_packet &udp = ip.data<Udp_packet>(udp_size);
if (!Dhcp_packet::is_dhcp(&udp)) {
throw Drop_packet_inform("DHCP client expects DHCP packet");
}
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(eth_size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet)
- sizeof(Udp_packet));
size_t const dhcp_size = udp_size - sizeof(Udp_packet);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(dhcp_size);
if (dhcp.op() != Dhcp_packet::REPLY) {
throw Drop_packet_inform("DHCP client expects DHCP reply");

View File

@ -892,7 +892,9 @@ void Interface::_handle_ip(Ethernet_frame &eth,
Domain &local_domain)
{
/* read packet information */
Ipv4_packet &ip = eth.data<Ipv4_packet>(eth_size - sizeof(Ethernet_frame));
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_address_prefix const &local_intf = local_domain.ip_config().interface;
/* try handling subnet-local IP packets */
@ -910,18 +912,18 @@ void Interface::_handle_ip(Ethernet_frame &eth,
/* try to route via transport layer rules */
try {
L3_protocol const prot = ip.protocol();
size_t const prot_size = ip.total_length() - ip.header_length() * 4;
size_t const prot_size = ip_size - sizeof(Ipv4_packet);
void *const prot_base = _prot_base(prot, prot_size, ip);
/* try handling DHCP requests before trying any routing */
if (prot == L3_protocol::UDP) {
Udp_packet &udp = ip.data<Udp_packet>(eth_size - sizeof(Ipv4_packet));
Udp_packet &udp = ip.data<Udp_packet>(prot_size);
if (Dhcp_packet::is_dhcp(&udp)) {
/* get DHCP packet */
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(eth_size - sizeof(Ipv4_packet)
- sizeof(Udp_packet));
size_t const dhcp_size = prot_size - sizeof(Udp_packet);
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(dhcp_size);
if (dhcp.op() == Dhcp_packet::REQUEST) {
try {