2011-12-22 15:19:25 +00:00
|
|
|
/*
|
|
|
|
* \brief User datagram protocol.
|
|
|
|
* \author Stefan Kalkowski
|
|
|
|
* \date 2010-08-19
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 12:23:52 +00:00
|
|
|
* Copyright (C) 2010-2017 Genode Labs GmbH
|
2011-12-22 15:19:25 +00:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 12:23:52 +00:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2011-12-22 15:19:25 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _UDP_H_
|
|
|
|
#define _UDP_H_
|
|
|
|
|
|
|
|
/* Genode */
|
|
|
|
#include <base/exception.h>
|
|
|
|
#include <base/stdint.h>
|
2016-12-06 13:12:18 +00:00
|
|
|
#include <net/port.h>
|
2011-12-22 15:19:25 +00:00
|
|
|
#include <util/endian.h>
|
|
|
|
#include <net/ethernet.h>
|
|
|
|
#include <net/ipv4.h>
|
|
|
|
|
2015-03-04 20:12:14 +00:00
|
|
|
namespace Net { class Udp_packet; }
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
|
2015-03-04 20:12:14 +00:00
|
|
|
/**
|
|
|
|
* Data layout of this class conforms to an UDP packet (RFC 768)
|
|
|
|
*
|
|
|
|
* UDP-header-format:
|
|
|
|
*
|
|
|
|
* -----------------------------------------------------------------------
|
|
|
|
* | source-port | destination-port | length | checksum |
|
|
|
|
* | 2 bytes | 2 bytes | 2 bytes | 2 bytes |
|
|
|
|
* -----------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
class Net::Udp_packet
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
|
|
|
/***********************
|
|
|
|
** UDP header fields **
|
|
|
|
***********************/
|
|
|
|
|
|
|
|
Genode::uint16_t _src_port;
|
|
|
|
Genode::uint16_t _dst_port;
|
|
|
|
Genode::uint16_t _length;
|
|
|
|
Genode::uint16_t _checksum;
|
|
|
|
unsigned _data[0];
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
2018-01-08 13:11:29 +00:00
|
|
|
struct Bad_data_type : Genode::Exception { };
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T> T *data(Genode::size_t data_size)
|
|
|
|
{
|
|
|
|
if (data_size < sizeof(T)) {
|
|
|
|
throw Bad_data_type();
|
|
|
|
}
|
|
|
|
return (T *)(_data);
|
2015-03-04 20:12:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-09-14 13:10:32 +00:00
|
|
|
/***************
|
|
|
|
** Accessors **
|
|
|
|
***************/
|
2016-05-09 13:47:28 +00:00
|
|
|
|
2018-01-08 13:11:29 +00:00
|
|
|
Port src_port() const { return Port(host_to_big_endian(_src_port)); }
|
|
|
|
Port dst_port() const { return Port(host_to_big_endian(_dst_port)); }
|
|
|
|
Genode::uint16_t length() const { return host_to_big_endian(_length); }
|
|
|
|
Genode::uint16_t checksum() const { return host_to_big_endian(_checksum); }
|
2016-08-25 15:48:06 +00:00
|
|
|
|
2017-09-14 13:10:32 +00:00
|
|
|
void length(Genode::uint16_t v) { _length = host_to_big_endian(v); }
|
|
|
|
void src_port(Port p) { _src_port = host_to_big_endian(p.value); }
|
|
|
|
void dst_port(Port p) { _dst_port = host_to_big_endian(p.value); }
|
2015-03-04 20:12:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
/***************************
|
|
|
|
** Convenience functions **
|
|
|
|
***************************/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* UDP checksum is calculated over the udp datagram + an IPv4
|
|
|
|
* pseudo header.
|
|
|
|
*
|
|
|
|
* IPv4 pseudo header:
|
|
|
|
*
|
|
|
|
* --------------------------------------------------------------
|
|
|
|
* | src-ipaddr | dst-ipaddr | zero-field | prot.-id | udp-length |
|
|
|
|
* | 4 bytes | 4 bytes | 1 byte | 1 byte | 2 bytes |
|
|
|
|
* --------------------------------------------------------------
|
|
|
|
*/
|
2016-08-15 12:42:29 +00:00
|
|
|
void update_checksum(Ipv4_address src,
|
|
|
|
Ipv4_address dst)
|
2015-03-04 20:12:14 +00:00
|
|
|
{
|
|
|
|
/* have to reset the checksum field for calculation */
|
|
|
|
_checksum = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sum up pseudo header
|
|
|
|
*/
|
|
|
|
Genode::uint32_t sum = 0;
|
|
|
|
for (unsigned i = 0; i < Ipv4_packet::ADDR_LEN; i=i+2) {
|
|
|
|
Genode::uint16_t s = src.addr[i] << 8 | src.addr[i + 1];
|
|
|
|
Genode::uint16_t d = dst.addr[i] << 8 | dst.addr[i + 1];
|
|
|
|
sum += s + d;
|
2011-12-22 15:19:25 +00:00
|
|
|
}
|
2017-09-14 13:10:32 +00:00
|
|
|
Genode::uint8_t prot[] = { 0, (Genode::uint8_t)Ipv4_packet::Protocol::UDP };
|
2015-04-29 09:36:54 +00:00
|
|
|
sum += host_to_big_endian(*(Genode::uint16_t*)&prot) + length();
|
2011-12-22 15:19:25 +00:00
|
|
|
|
2015-03-04 20:12:14 +00:00
|
|
|
/*
|
|
|
|
* sum up udp packet itself
|
2011-12-22 15:19:25 +00:00
|
|
|
*/
|
2015-03-04 20:12:14 +00:00
|
|
|
unsigned max = (length() & 1) ? (length() - 1) : length();
|
|
|
|
Genode::uint16_t *udp = (Genode::uint16_t*) this;
|
|
|
|
for (unsigned i = 0; i < max; i=i+2)
|
2015-04-29 09:36:54 +00:00
|
|
|
sum += host_to_big_endian(*udp++);
|
2015-03-04 20:12:14 +00:00
|
|
|
|
|
|
|
/* if udp length is odd, append a zero byte */
|
|
|
|
if (length() & 1) {
|
|
|
|
Genode::uint8_t last[] =
|
|
|
|
{ *((Genode::uint8_t*)this + (length()-1)), 0 };
|
2015-04-29 09:36:54 +00:00
|
|
|
sum += host_to_big_endian(*(Genode::uint16_t*)&last);
|
2011-12-22 15:19:25 +00:00
|
|
|
}
|
2015-03-04 20:12:14 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* keep only the last 16 bits of the 32 bit calculated sum
|
|
|
|
* and add the carries
|
|
|
|
*/
|
|
|
|
while (sum >> 16)
|
|
|
|
sum = (sum & 0xffff) + (sum >> 16);
|
|
|
|
|
|
|
|
/* one's complement of sum */
|
2015-04-29 09:36:54 +00:00
|
|
|
_checksum = host_to_big_endian((Genode::uint16_t) ~sum);
|
2015-03-04 20:12:14 +00:00
|
|
|
}
|
2016-11-02 00:00:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*********
|
|
|
|
** log **
|
|
|
|
*********/
|
|
|
|
|
|
|
|
void print(Genode::Output &output) const;
|
|
|
|
|
2015-03-04 20:12:14 +00:00
|
|
|
} __attribute__((packed));
|
2011-12-22 15:19:25 +00:00
|
|
|
|
|
|
|
#endif /* _UDP_H_ */
|