diff --git a/repos/os/include/net/icmp.h b/repos/os/include/net/icmp.h new file mode 100644 index 0000000000..f9402684b5 --- /dev/null +++ b/repos/os/include/net/icmp.h @@ -0,0 +1,95 @@ +/* + * \brief Internet Control Message Protocol + * \author Martin Stein + * \date 2018-03-23 + */ + +/* + * Copyright (C) 2018 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__ICMP_H_ +#define _NET__ICMP_H_ + +/* Genode includes */ +#include +#include + +namespace Genode { class Output; } + +namespace Net { class Icmp_packet; } + + +class Net::Icmp_packet +{ + private: + + Genode::uint8_t _type; + Genode::uint8_t _code; + Genode::uint16_t _checksum; + union { + Genode::uint32_t _rest_of_header_u32[1]; + Genode::uint16_t _rest_of_header_u16[2]; + Genode::uint8_t _rest_of_header_u8[4]; + }; + Genode::uint8_t _data[0]; + + public: + + struct Bad_data_type : Genode::Exception { }; + + enum class Type + { + ECHO_REPLY = 0, + DST_UNREACHABLE = 3, + ECHO_REQUEST = 8, + }; + + enum class Code + { + DST_NET_UNREACHABLE = 0, + ECHO_REQUEST = 0, + ECHO_REPLY = 0, + }; + + Genode::uint16_t calc_checksum(Genode::size_t data_sz) const; + + + /*************** + ** Accessors ** + ***************/ + + Type type() const { return (Type)_type; } + Code code() const { return (Code)_code; } + Genode::uint16_t checksum() const { return host_to_big_endian(_checksum); } + Genode::uint16_t query_id() const { return host_to_big_endian(_rest_of_header_u16[0]); } + 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 T &data(Genode::size_t data_size) + { + if (data_size < sizeof(T)) { + throw Bad_data_type(); + } + return *(T *)(_data); + } + + 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); } + void rest_of_header(Genode::uint32_t v) { _rest_of_header_u32[0] = host_to_big_endian(v); } + void query_id(Genode::uint16_t v) { _rest_of_header_u16[0] = host_to_big_endian(v); } + void query_seq(Genode::uint16_t v) { _rest_of_header_u16[1] = host_to_big_endian(v); } + + + /********* + ** log ** + *********/ + + void print(Genode::Output &output) const; +}; + +#endif /* _NET__ICMP_H_ */ diff --git a/repos/os/include/net/ipv4.h b/repos/os/include/net/ipv4.h index c5fc6b0fde..4028b5ed06 100644 --- a/repos/os/include/net/ipv4.h +++ b/repos/os/include/net/ipv4.h @@ -117,8 +117,9 @@ class Net::Ipv4_packet enum class Protocol : Genode::uint8_t { - TCP = 6, - UDP = 17, + ICMP = 1, + TCP = 6, + UDP = 17, }; struct Bad_data_type : Genode::Exception { }; diff --git a/repos/os/lib/mk/net.mk b/repos/os/lib/mk/net.mk index 9f603d004b..a1a71c387c 100644 --- a/repos/os/lib/mk/net.mk +++ b/repos/os/lib/mk/net.mk @@ -1,3 +1,4 @@ -SRC_CC = ethernet.cc ipv4.cc dhcp.cc arp.cc udp.cc tcp.cc mac_address.cc +SRC_CC += ethernet.cc ipv4.cc dhcp.cc arp.cc udp.cc tcp.cc mac_address.cc +SRC_CC += icmp.cc vpath %.cc $(REP_DIR)/src/lib/net diff --git a/repos/os/src/lib/net/icmp.cc b/repos/os/src/lib/net/icmp.cc new file mode 100644 index 0000000000..2134723fd7 --- /dev/null +++ b/repos/os/src/lib/net/icmp.cc @@ -0,0 +1,54 @@ +/* + * \brief Internet Control Message Protocol + * \author Martin Stein + * \date 2018-03-23 + */ + +/* + * Copyright (C) 2018 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. + */ + +/* Genode includes */ +#include +#include + +using namespace Net; +using namespace Genode; + + +void Net::Icmp_packet::print(Output &output) const +{ + Genode::print(output, "\033[32mICMP\033[0m ", (unsigned)type(), " ", + (unsigned)code()); +} + + +uint16_t Icmp_packet::calc_checksum(size_t data_sz) const +{ + /* do not sum-up checksum itself */ + register long sum = _type + _code; + addr_t addr = (addr_t)&_rest_of_header_u32; + size_t count = sizeof(Icmp_packet) + data_sz - sizeof(_type) - + sizeof(_code) - sizeof(_checksum); + + /* sum-up rest of header and data */ + while (count > 1) { + sum += *(uint16_t *)addr; + addr += sizeof(uint16_t); + count -= sizeof(uint16_t); + } + /* add left-over byte, if any */ + if (count) { + sum += *(uint8_t *)addr; + } + /* fold 32-bit sum to 16 bits */ + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + /* write to header */ + uint16_t sum16 = ~sum; + return host_to_big_endian(sum16); +} diff --git a/repos/os/src/lib/net/ipv4.cc b/repos/os/src/lib/net/ipv4.cc index a8060e75e2..3717b41ed9 100644 --- a/repos/os/src/lib/net/ipv4.cc +++ b/repos/os/src/lib/net/ipv4.cc @@ -16,6 +16,7 @@ #include #include +#include #include using namespace Genode; @@ -32,6 +33,9 @@ void Net::Ipv4_packet::print(Genode::Output &output) const case Protocol::UDP: Genode::print(output, *reinterpret_cast(_data)); break; + case Protocol::ICMP: + Genode::print(output, *reinterpret_cast(_data)); + break; default: ; } }