net: safer access to packet data

Replace packet method 'T *data' by the new methods 'T &reinterpret_data'
for parsing or modifying existing sub-protocol packets and 'T
&construct_at_data' for composing a new sub-protocol packet. This has
the advantage that, when composing a new packet, the default constructor
that zero-fills the packet is always called first.

Fixes #2751
This commit is contained in:
Martin Stein 2018-04-09 19:58:08 +02:00 committed by Christian Helmuth
parent 58fcf577ea
commit 373134c4e7
10 changed files with 144 additions and 174 deletions

View File

@ -104,10 +104,6 @@ class Net::Dhcp_packet
_magic_cookie = host_to_big_endian(0x63825363);
}
void zero_fill_sname() { Genode::memset(_sname, 0, sizeof(_sname)); }
void zero_fill_file() { Genode::memset(_file, 0, sizeof(_file)); }
/*******************************
** Utilities for the options **

View File

@ -17,7 +17,7 @@
/* Genode includes */
#include <base/exception.h>
#include <util/string.h>
#include <util/construct_at.h>
#include <util/endian.h>
#include <net/mac_address.h>
@ -72,20 +72,27 @@ class Net::Ethernet_frame
struct Bad_data_type : Genode::Exception { };
template <typename T> T const *data(Genode::size_t data_size) const
template <typename T> T const &data(Genode::size_t data_size) const
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
return (T const *)(_data);
return *(T const *)(_data);
}
template <typename T> T *data(Genode::size_t data_size)
template <typename T> T &data(Genode::size_t data_size)
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
return (T *)(_data);
return *(T *)(_data);
}
template <typename T, typename SIZE_GUARD>
T &construct_at_data(SIZE_GUARD &size_guard)
{
size_guard.add(sizeof(T));
return *Genode::construct_at<T>(_data);
}

View File

@ -18,7 +18,7 @@
#include <base/exception.h>
#include <util/string.h>
#include <util/token.h>
#include <util/construct_at.h>
#include <util/endian.h>
#include <net/netaddress.h>
@ -124,20 +124,29 @@ class Net::Ipv4_packet
struct Bad_data_type : Genode::Exception { };
template <typename T> T const *data(Genode::size_t data_size) const
template <typename T>
T const &data(Genode::size_t data_size) const
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
return (T const *)(_data);
return *(T const *)(_data);
}
template <typename T> T *data(Genode::size_t data_size)
template <typename T>
T &data(Genode::size_t data_size)
{
if (data_size < sizeof(T)) {
throw Bad_data_type();
}
return (T *)(_data);
return *(T *)(_data);
}
template <typename T, typename SIZE_GUARD>
T &construct_at_data(SIZE_GUARD &size_guard)
{
size_guard.add(sizeof(T));
return *Genode::construct_at<T>(_data);
}

View File

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

View File

@ -200,7 +200,7 @@ void Main::_handle_ip(Ethernet_frame &eth,
{
/* 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);
Ipv4_packet &ip = eth.data<Ipv4_packet>(ip_size);
if (ip.dst() != _src_ip &&
ip.dst() != Ipv4_packet::broadcast())
{
@ -306,7 +306,7 @@ void Main::_handle_icmp_dst_unreachbl(Ipv4_packet &ip,
}
/* 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>(embed_icmp_sz);
if (embed_icmp.query_id() != ICMP_ID) {
if (_verbose) {
log("bad ICMP identifier in payload of ICMP error"); }
@ -328,7 +328,7 @@ void Main::_handle_icmp(Ipv4_packet &ip,
{
/* 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);
Icmp_packet &icmp = ip.data<Icmp_packet>(icmp_sz);
size_t const icmp_data_sz = icmp_sz - sizeof(Icmp_packet);
if (icmp.calc_checksum(icmp_data_sz) != icmp.checksum()) {
if (_verbose) {
@ -351,7 +351,7 @@ void Main::_handle_arp(Ethernet_frame &eth,
size_t const eth_size)
{
/* 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>(eth_size - sizeof(Ethernet_frame));
if (!arp.ethernet_ipv4()) {
error("ARP for unknown protocol"); }
@ -409,24 +409,19 @@ void Main::_ready_to_ack()
void Main::_send_arp_reply(Ethernet_frame &req_eth,
Arp_packet &req_arp)
{
enum {
ETH_HDR_SZ = sizeof(Ethernet_frame),
ETH_DAT_SZ = sizeof(Arp_packet) + ETH_HDR_SZ >= Ethernet_frame::MIN_SIZE ?
sizeof(Arp_packet) :
Ethernet_frame::MIN_SIZE - ETH_HDR_SZ,
ETH_CRC_SZ = sizeof(uint32_t),
PKT_SIZE = ETH_HDR_SZ + ETH_DAT_SZ + ETH_CRC_SZ,
};
_send(PKT_SIZE, [&] (void *pkt_base) {
size_t const buf_sz = sizeof(Ethernet_frame) + sizeof(Arp_packet);
_send(buf_sz, [&] (void *pkt_base) {
/* write Ethernet header */
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(pkt_base);
Size_guard<Send_buffer_too_small> size(buf_sz);
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
eth.dst(req_eth.src());
eth.src(_src_mac);
eth.type(Ethernet_frame::Type::ARP);
/* write ARP header */
Arp_packet &arp = *eth.data<Arp_packet>(PKT_SIZE - sizeof(Ethernet_frame));
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size);
arp.hardware_address_type(Arp_packet::ETHERNET);
arp.protocol_address_type(Arp_packet::IPV4);
arp.hardware_address_size(sizeof(Mac_address));
@ -442,24 +437,19 @@ void Main::_send_arp_reply(Ethernet_frame &req_eth,
void Main::_broadcast_arp_request()
{
enum {
ETH_HDR_SZ = sizeof(Ethernet_frame),
ETH_DAT_SZ = sizeof(Arp_packet) + ETH_HDR_SZ >= Ethernet_frame::MIN_SIZE ?
sizeof(Arp_packet) :
Ethernet_frame::MIN_SIZE - ETH_HDR_SZ,
ETH_CRC_SZ = sizeof(uint32_t),
PKT_SIZE = ETH_HDR_SZ + ETH_DAT_SZ + ETH_CRC_SZ,
};
_send(PKT_SIZE, [&] (void *pkt_base) {
size_t const buf_sz = sizeof(Ethernet_frame) + sizeof(Arp_packet);
_send(buf_sz, [&] (void *pkt_base) {
/* write Ethernet header */
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(pkt_base);
Size_guard<Send_buffer_too_small> size(buf_sz);
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
eth.dst(Mac_address(0xff));
eth.src(_src_mac);
eth.type(Ethernet_frame::Type::ARP);
/* write ARP header */
Arp_packet &arp = *eth.data<Arp_packet>(PKT_SIZE - sizeof(Ethernet_frame));
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size);
arp.hardware_address_type(Arp_packet::ETHERNET);
arp.protocol_address_type(Arp_packet::IPV4);
arp.hardware_address_size(sizeof(Mac_address));
@ -487,36 +477,30 @@ void Main::_send_ping(Duration)
/* create ETH header */
Size_guard<Send_buffer_too_small> size(buf_sz);
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(pkt_base);
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
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.data<Ipv4_packet>(size.left());
size.add(sizeof(Ipv4_packet));
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size);
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.diff_service(0);
ip.ecn(0);
ip.identification(0);
ip.flags(0);
ip.fragment_offset(0);
ip.time_to_live(IPV4_TIME_TO_LIVE);
ip.protocol(Ipv4_packet::Protocol::ICMP);
ip.src(_src_ip);
ip.dst(_dst_ip);
/* create ICMP header */
Icmp_packet &icmp = *ip.data<Icmp_packet>(size.left());
size.add(sizeof(Icmp_packet) + _icmp_data_sz);
Icmp_packet &icmp = ip.construct_at_data<Icmp_packet>(size);
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 'w' */
/* 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);
char chr = 'a';

View File

@ -22,9 +22,9 @@ using namespace Net;
bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
{
Arp_packet *arp = eth->data<Arp_packet>(size - sizeof(Ethernet_frame));
if (arp->ethernet_ipv4() &&
arp->opcode() == Arp_packet::REQUEST) {
Arp_packet &arp = eth->data<Arp_packet>(size - sizeof(Ethernet_frame));
if (arp.ethernet_ipv4() &&
arp.opcode() == Arp_packet::REQUEST) {
/*
* 'Gratuitous ARP' broadcast messages are used to announce newly created
@ -34,14 +34,14 @@ bool Session_component::handle_arp(Ethernet_frame *eth, Genode::size_t size)
* The simplest solution to this problem is to just drop those messages,
* since they are not really necessary.
*/
if (arp->src_ip() == arp->dst_ip())
if (arp.src_ip() == arp.dst_ip())
return false;
Ipv4_address_node *node = vlan().ip_tree.first();
if (node)
node = node->find_by_address(arp->dst_ip());
node = node->find_by_address(arp.dst_ip());
if (!node) {
arp->src_mac(_nic.mac());
arp.src_mac(_nic.mac());
}
}
return true;
@ -50,19 +50,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));
Ipv4_packet &ip = eth->data<Ipv4_packet>(size - sizeof(Ethernet_frame));
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));
if (Dhcp_packet::is_dhcp(udp)) {
Dhcp_packet *dhcp = udp->data<Dhcp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet)
- sizeof(Udp_packet));
if (dhcp->op() == Dhcp_packet::REQUEST) {
dhcp->broadcast(true);
udp->update_checksum(ip->src(), ip->dst());
Udp_packet &udp = ip.data<Udp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet));
if (Dhcp_packet::is_dhcp(&udp)) {
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet)
- sizeof(Udp_packet));
if (dhcp.op() == Dhcp_packet::REQUEST) {
dhcp.broadcast(true);
udp.update_checksum(ip.src(), ip.dst());
}
}
}

View File

@ -24,37 +24,37 @@ using namespace Net;
bool Net::Nic::handle_arp(Ethernet_frame *eth, Genode::size_t size) {
Arp_packet *arp = eth->data<Arp_packet>(size - sizeof(Ethernet_frame));
Arp_packet &arp = eth->data<Arp_packet>(size - sizeof(Ethernet_frame));
/* ignore broken packets */
if (!arp->ethernet_ipv4())
if (!arp.ethernet_ipv4())
return true;
/* look whether the IP address is one of our client's */
Ipv4_address_node *node = vlan().ip_tree.first();
if (node)
node = node->find_by_address(arp->dst_ip());
node = node->find_by_address(arp.dst_ip());
if (node) {
if (arp->opcode() == Arp_packet::REQUEST) {
if (arp.opcode() == Arp_packet::REQUEST) {
/*
* The ARP packet gets re-written, we interchange source
* and destination MAC and IP addresses, and set the opcode
* to reply, and then push the packet back to the NIC driver.
*/
Ipv4_address old_src_ip = arp->src_ip();
arp->opcode(Arp_packet::REPLY);
arp->dst_mac(arp->src_mac());
arp->src_mac(mac());
arp->src_ip(arp->dst_ip());
arp->dst_ip(old_src_ip);
eth->dst(arp->dst_mac());
Ipv4_address old_src_ip = arp.src_ip();
arp.opcode(Arp_packet::REPLY);
arp.dst_mac(arp.src_mac());
arp.src_mac(mac());
arp.src_ip(arp.dst_ip());
arp.dst_ip(old_src_ip);
eth->dst(arp.dst_mac());
/* set our MAC as sender */
eth->src(mac());
send(eth, size);
} else {
/* overwrite destination MAC */
arp->dst_mac(node->component().mac_address().addr);
arp.dst_mac(node->component().mac_address().addr);
eth->dst(node->component().mac_address().addr);
node->component().send(eth, size);
}
@ -65,26 +65,26 @@ 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));
Ipv4_packet &ip = eth->data<Ipv4_packet>(size - sizeof(Ethernet_frame));
/* is it an UDP packet ? */
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));
Udp_packet &udp = ip.data<Udp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet));
/* 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));
if (Dhcp_packet::is_dhcp(&udp)) {
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet)
- sizeof(Udp_packet));
/* check for DHCP ACKs containing new client ips */
if (dhcp->op() == Dhcp_packet::REPLY) {
if (dhcp.op() == Dhcp_packet::REPLY) {
try {
Dhcp_packet::Message_type const msg_type =
dhcp->option<Dhcp_packet::Message_type_option>().value();
dhcp.option<Dhcp_packet::Message_type_option>().value();
/*
* Extract the IP address and set it in the client's
@ -94,9 +94,9 @@ bool Net::Nic::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
Mac_address_node *node =
vlan().mac_tree.first();
if (node)
node = node->find_by_address(dhcp->client_mac());
node = node->find_by_address(dhcp.client_mac());
if (node)
node->component().set_ipv4_address(dhcp->yiaddr());
node->component().set_ipv4_address(dhcp.yiaddr());
}
}
catch (Dhcp_packet::Option_not_found) { }
@ -108,7 +108,7 @@ bool Net::Nic::handle_ip(Ethernet_frame *eth, Genode::size_t size) {
if (eth->dst() == mac()) {
Ipv4_address_node *node = vlan().ip_tree.first();
if (node) {
node = node->find_by_address(ip->dst());
node = node->find_by_address(ip.dst());
if (node) {
/* overwrite destination MAC */
eth->dst(node->component().mac_address().addr);

View File

@ -157,12 +157,12 @@ void Packet_log<Ethernet_frame>::print(Output &output) const
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>(~0UL), _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>(~0UL), _cfg));
break;
default: ;
@ -212,17 +212,17 @@ void Packet_log<Ipv4_packet>::print(Output &output) const
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>(~0UL), _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>(~0UL), _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>(~0UL), _cfg));
break;
default: ; }
@ -297,7 +297,7 @@ 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));
print(output, " ", packet_log(_pkt.data<Dhcp_packet const>(~0UL), _cfg));
}
}

View File

@ -119,20 +119,20 @@ 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));
Ipv4_packet &ip = eth.data<Ipv4_packet>(eth_size - sizeof(Ethernet_frame));
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));
Udp_packet &udp = ip.data<Udp_packet>(eth_size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet));
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));
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(eth_size - sizeof(Ethernet_frame)
- sizeof(Ipv4_packet)
- sizeof(Udp_packet));
if (dhcp.op() != Dhcp_packet::REPLY) {
throw Drop_packet_inform("DHCP client expects DHCP reply");
@ -206,7 +206,7 @@ void Dhcp_client::_send(Message_type msg_type,
/* create ETH header of the request */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(pkt_base);
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
eth.dst(Mac_address(0xff));
eth.src(client_mac);
eth.type(Ethernet_frame::Type::IPV4);
@ -214,15 +214,9 @@ void Dhcp_client::_send(Message_type msg_type,
/* create IP header of the request */
enum { IPV4_TIME_TO_LIVE = 64 };
size_t const ip_off = size.curr();
Ipv4_packet &ip = *eth.data<Ipv4_packet>(size.left());
size.add(sizeof(Ipv4_packet));
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size);
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.diff_service(0);
ip.ecn(0);
ip.identification(0);
ip.flags(0);
ip.fragment_offset(0);
ip.time_to_live(IPV4_TIME_TO_LIVE);
ip.protocol(Ipv4_packet::Protocol::UDP);
ip.src(client_ip);
@ -230,29 +224,18 @@ void Dhcp_client::_send(Message_type msg_type,
/* create UDP header of the request */
size_t const udp_off = size.curr();
Udp_packet &udp = *ip.data<Udp_packet>(size.left());
size.add(sizeof(Udp_packet));
Udp_packet &udp = ip.construct_at_data<Udp_packet>(size);
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.data<Dhcp_packet>(size.left());
size.add(sizeof(Dhcp_packet));
Dhcp_packet &dhcp = udp.construct_at_data<Dhcp_packet>(size);
dhcp.op(Dhcp_packet::REQUEST);
dhcp.htype(Dhcp_packet::Htype::ETH);
dhcp.hlen(sizeof(Mac_address));
dhcp.hops(0);
dhcp.xid(0x12345678);
dhcp.secs(0);
dhcp.flags(0);
dhcp.ciaddr(client_ip);
dhcp.yiaddr(Ipv4_address());
dhcp.siaddr(Ipv4_address());
dhcp.giaddr(Ipv4_address());
dhcp.client_mac(client_mac);
dhcp.zero_fill_sname();
dhcp.zero_fill_file();
dhcp.default_magic_cookie();
/* append DHCP option fields to the request */

View File

@ -30,6 +30,7 @@ using Genode::uint32_t;
using Genode::log;
using Genode::error;
using Genode::warning;
using Genode::construct_at;
using Genode::Signal_context_capability;
using Genode::Signal_transmitter;
@ -169,9 +170,9 @@ static void *_prot_base(L3_protocol const prot,
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>(prot_size);
case L3_protocol::UDP: return &ip.data<Udp_packet>(prot_size);
case L3_protocol::ICMP: return &ip.data<Icmp_packet>(prot_size);
default: throw Interface::Bad_transport_protocol(); }
}
@ -464,22 +465,16 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
/* create ETH header of the reply */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(pkt_base);
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
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.data<Ipv4_packet>(size.left());
size.add(sizeof(Ipv4_packet));
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size);
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.diff_service(0);
ip.ecn(0);
ip.identification(0);
ip.flags(0);
ip.fragment_offset(0);
ip.time_to_live(IPV4_TIME_TO_LIVE);
ip.protocol(Ipv4_packet::Protocol::UDP);
ip.src(local_intf.address);
@ -487,28 +482,22 @@ void Interface::_send_dhcp_reply(Dhcp_server const &dhcp_srv,
/* create UDP header of the reply */
size_t const udp_off = size.curr();
Udp_packet &udp = *ip.data<Udp_packet>(size.left());
size.add(sizeof(Udp_packet));
Udp_packet &udp = ip.construct_at_data<Udp_packet>(size);
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.data<Dhcp_packet>(size.left());
size.add(sizeof(Dhcp_packet));
Dhcp_packet &dhcp = udp.construct_at_data<Dhcp_packet>(size);
dhcp.op(Dhcp_packet::REPLY);
dhcp.htype(Dhcp_packet::Htype::ETH);
dhcp.hlen(sizeof(Mac_address));
dhcp.hops(0);
dhcp.xid(xid);
dhcp.secs(0);
dhcp.flags(0);
dhcp.ciaddr(msg_type == Dhcp_packet::Message_type::INFORM ? client_ip : Ipv4_address());
dhcp.yiaddr(msg_type == Dhcp_packet::Message_type::INFORM ? Ipv4_address() : client_ip);
if (msg_type == Dhcp_packet::Message_type::INFORM) {
dhcp.ciaddr(client_ip); }
else {
dhcp.yiaddr(client_ip); }
dhcp.siaddr(local_intf.address);
dhcp.giaddr(Ipv4_address());
dhcp.client_mac(client_mac);
dhcp.zero_fill_sname();
dhcp.zero_fill_file();
dhcp.default_magic_cookie();
/* append DHCP option fields to the reply */
@ -716,37 +705,30 @@ void Interface::_send_icmp_dst_unreachable(Ipv4_address_prefix const &local_intf
/* create ETH header */
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(pkt_base);
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
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.data<Ipv4_packet>(size.left());
size.add(sizeof(Ipv4_packet));
Ipv4_packet &ip = eth.construct_at_data<Ipv4_packet>(size);
ip.header_length(sizeof(Ipv4_packet) / 4);
ip.version(4);
ip.diff_service(0);
ip.ecn(0);
ip.identification(0);
ip.flags(0);
ip.fragment_offset(0);
ip.time_to_live(IPV4_TIME_TO_LIVE);
ip.protocol(Ipv4_packet::Protocol::ICMP);
ip.src(local_intf.address);
ip.dst(req_ip.src());
/* create ICMP header */
Icmp_packet &icmp = *ip.data<Icmp_packet>(size.left());
size.add(sizeof(Icmp_packet));
Icmp_packet &icmp = ip.construct_at_data<Icmp_packet>(size);
icmp.type(Icmp_packet::Type::DST_UNREACHABLE);
icmp.code(code);
icmp.rest_of_header(0);
size_t icmp_data_size = req_ip.total_length();
if (icmp_data_size > ICMP_MAX_DATA_SIZE) {
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);
@ -890,7 +872,7 @@ void Interface::_handle_icmp(Ethernet_frame &eth,
{
/* 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);
Icmp_packet &icmp = ip.data<Icmp_packet>(icmp_sz);
size_t const icmp_data_sz = icmp_sz - sizeof(Icmp_packet);
if (icmp.calc_checksum(icmp_data_sz) != icmp.checksum()) {
throw Drop_packet_inform("bad ICMP checksum");
@ -910,7 +892,7 @@ 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));
Ipv4_packet &ip = eth.data<Ipv4_packet>(eth_size - sizeof(Ethernet_frame));
Ipv4_address_prefix const &local_intf = local_domain.ip_config().interface;
/* try handling subnet-local IP packets */
@ -933,13 +915,13 @@ void Interface::_handle_ip(Ethernet_frame &eth,
/* 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>(eth_size - sizeof(Ipv4_packet));
if (Dhcp_packet::is_dhcp(&udp)) {
/* get DHCP packet */
Dhcp_packet &dhcp = *udp.data<Dhcp_packet>(eth_size - sizeof(Ipv4_packet)
- sizeof(Udp_packet));
Dhcp_packet &dhcp = udp.data<Dhcp_packet>(eth_size - sizeof(Ipv4_packet)
- sizeof(Udp_packet));
if (dhcp.op() == Dhcp_packet::REQUEST) {
try {
@ -1063,16 +1045,19 @@ 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) {
/* write Ethernet header */
Ethernet_frame &eth = *reinterpret_cast<Ethernet_frame *>(pkt_base);
Size_guard size;
size.add(sizeof(Ethernet_frame));
Ethernet_frame &eth = *construct_at<Ethernet_frame>(pkt_base);
eth.dst(Mac_address(0xff));
eth.src(_router_mac);
eth.type(Ethernet_frame::Type::ARP);
/* write ARP header */
Arp_packet &arp = *eth.data<Arp_packet>(PKT_SIZE - sizeof(Ethernet_frame));
Arp_packet &arp = eth.construct_at_data<Arp_packet>(size);
arp.hardware_address_type(Arp_packet::ETHERNET);
arp.protocol_address_type(Arp_packet::IPV4);
arp.hardware_address_size(sizeof(Mac_address));
@ -1194,7 +1179,7 @@ void Interface::_handle_arp(Ethernet_frame &eth,
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>(eth_size - sizeof(Ethernet_frame));
if (!arp.ethernet_ipv4()) {
error("ARP for unknown protocol"); }
@ -1306,8 +1291,7 @@ void Interface::_handle_eth(void *const eth_base,
}
catch (Pointer<Domain>::Invalid) {
if (_config().verbose_packets()) {
Ethernet_frame *const eth = reinterpret_cast<Ethernet_frame *>(eth_base);
log("[?] rcv ", *eth);
log("[?] rcv ", *reinterpret_cast<Ethernet_frame *>(eth_base));
}
if (_config().verbose()) {
log("[?] drop packet: no domain"); }