From 591ef1826f55cf5f6a07605fcf7ee463b7831828 Mon Sep 17 00:00:00 2001 From: Martine Lenders <mlenders@inf.fu-berlin.de> Date: Sat, 7 Mar 2015 20:37:45 +0100 Subject: [PATCH] ng_icmpv6: Initial import --- Makefile.dep | 5 + sys/Makefile | 3 + sys/include/net/ng_icmpv6.h | 101 ++++++++++++ sys/include/net/ng_icmpv6/types.h | 70 ++++++++ sys/net/crosslayer/ng_netreg/ng_netreg.c | 1 + sys/net/network_layer/ng_icmpv6/Makefile | 1 + sys/net/network_layer/ng_icmpv6/ng_icmpv6.c | 172 ++++++++++++++++++++ sys/net/network_layer/ng_ipv6/ng_ipv6.c | 11 +- 8 files changed, 362 insertions(+), 2 deletions(-) create mode 100644 sys/include/net/ng_icmpv6.h create mode 100644 sys/include/net/ng_icmpv6/types.h create mode 100644 sys/net/network_layer/ng_icmpv6/Makefile create mode 100644 sys/net/network_layer/ng_icmpv6/ng_icmpv6.c diff --git a/Makefile.dep b/Makefile.dep index 61498f9d8e..3fe29f8597 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -53,6 +53,10 @@ ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE))) USEMODULE += vtimer endif +ifneq (,$(filter ng_icmpv6,$(USEMODULE))) + USEMODULE += ng_ipv6 +endif + ifneq (,$(filter ng_ipv6_hdr,$(USEMODULE))) USEMODULE += ng_inet_csum USEMODULE += ng_pktbuf @@ -63,6 +67,7 @@ ifneq (,$(filter ng_ipv6_router,$(USEMODULE))) endif ifneq (,$(filter ng_ipv6,$(USEMODULE))) + USEMODULE += ng_icmpv6 USEMODULE += ng_inet_csum USEMODULE += ng_ipv6_addr USEMODULE += ng_ipv6_hdr diff --git a/sys/Makefile b/sys/Makefile index 2f3500c967..3ec57b53d6 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -62,6 +62,9 @@ endif ifneq (,$(filter oneway_malloc,$(USEMODULE))) DIRS += oneway-malloc endif +ifneq (,$(filter ng_icmpv6,$(USEMODULE))) + DIRS += net/network_layer/ng_icmpv6 +endif ifneq (,$(filter ng_ipv6,$(USEMODULE))) DIRS += net/network_layer/ng_ipv6 endif diff --git a/sys/include/net/ng_icmpv6.h b/sys/include/net/ng_icmpv6.h new file mode 100644 index 0000000000..f492103631 --- /dev/null +++ b/sys/include/net/ng_icmpv6.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for + * more details. + */ + +/** + * @defgroup net_ng_icmpv6 Internet Control Message Protocol for IPv6 + * @ingroup net_ng_ipv6 + * @brief Basic implementation of ICMPv6 + * + * @see <a href="https://tools.ietf.org/html/rfc4443"> + * RFC 4443 + * </a> + * @{ + * + * @file + * @brief Definitions for ICMPv6 + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ + +#ifndef NG_ICMPV6_H_ +#define NG_ICMPV6_H_ + +#include <inttypes.h> + +#include "byteorder.h" +#include "kernel_types.h" +#include "net/ng_ipv6/hdr.h" +#include "net/ng_nettype.h" +#include "net/ng_nettype.h" +#include "net/ng_pkt.h" + +#include "net/ng_icmpv6/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief General ICMPv6 message format. + * + * @see <a href="https://tools.ietf.org/html/rfc4443#section-2.1"> + * RFC 4443, section 2.1 + * </a> + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< message type */ + uint8_t code; /**< message code */ + network_uint16_t csum; /**< checksum */ +} ng_icmpv6_hdr_t; + +/** + * @brief Demultiplexes a received ICMPv6 packet according to its type field. + * + * @param[in] iface The receiving interface + * @param[in] pkt The packet to demultiplex. + */ +void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt); + +/** + * @brief Builds an ICMPv6 message for sending. + * + * @param[in] type Type for the ICMPv6 message. + * @param[in] code Code for the ICMPv6 message. + * @param[in] size Size of the ICMPv6 message (needs do be > + * `sizeof(ng_icmpv6_hdr_t)`). + * + * @return The ICMPv6 message on success + * @return NULL, on failure + */ +ng_pktsnip_t *ng_icmpv6_build(uint8_t type, uint8_t code, size_t size); + +/* TODO: build error messages */ + +/** + * @brief Calculates the checksum for an ICMPv6 packet. + * + * @param[in] hdr The header the checksum should be calculated + * for. + * @param[in] pseudo_hdr The header the pseudo header shall be generated + * from. NULL if none is needed. + * + * @return 0, on success. + * @return -EINVAL, if ng_pktsnip_t::type of @p pkt was not NG_NETTYPE_ICMPV6 + * @return -ENOENT, if ng_pktsnip_t::type of @p pseudo_hdr was not + * NG_NETTYPE_IPV6 + */ +int ng_icmpv6_calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_ICMPV6_H_ */ +/** + * @} + */ diff --git a/sys/include/net/ng_icmpv6/types.h b/sys/include/net/ng_icmpv6/types.h new file mode 100644 index 0000000000..fddac3d4f6 --- /dev/null +++ b/sys/include/net/ng_icmpv6/types.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_ng_icmpv6_types ICMPv6 message type definitions + * @ingroup net_ng_icmpv6 + * @brief Type numbers for the corresponding field in ICMPv6 messages. + * @{ + * + * @file + * @brief Macro definitions for ICMPv6 type fields + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ +#ifndef NG_ICMPV6_TYPES_H_ +#define NG_ICMPV6_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @{ + * @name Error message types + * @see <a href="http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2"> + * IANA, ICMPv6 "type" Numbers + * </a> + */ +#define NG_ICMPV6_DEST_UNR (1) /**< Destination unreachable message */ +#define NG_ICMPV6_PKT_TOO_BIG (2) /**< Packet Too Big message */ +#define NG_ICMPV6_TIME_EXC (3) /**< Time Exceeded message */ +#define NG_ICMPV6_PARAM_PROB (4) /**< Parameter Problem message */ +#define NG_ICMPV6_ERR_EXP1 (100) /**< message type for private experimentation */ +#define NG_ICMPV6_ERR_EXP2 (101) /**< message type for private experimentation */ +/** + * @} + */ + +/** + * @{ + * @name Informational message types + * @see <a href="http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-2"> + * IANA, ICMPv6 "type" Numbers + * </a> + */ +#define NG_ICMPV6_ECHO_REQ (128) /**< Echo request message (ping) */ +#define NG_ICMPV6_ECHO_REP (129) /**< Echo reply message (pong) */ +#define NG_ICMPV6_RTR_SOL (133) /**< NDP router solicitation message */ +#define NG_ICMPV6_RTR_ADV (134) /**< NDP router advertisement message */ +#define NG_ICMPV6_NBR_SOL (135) /**< NDP neighbor solicitation message */ +#define NG_ICMPV6_NBR_ADV (136) /**< NDP neighbor advertisement message */ +#define NG_ICMPV6_REDIRECT (137) /**< NDP redirect message */ +#define NG_ICMPV6_RPL_CTRL (155) /**< RPL control message */ +#define NG_ICMPV6_INF_EXP1 (200) /**< message type for private experimentation */ +#define NG_ICMPV6_INF_EXP2 (201) /**< message type for private experimentation */ +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* NG_ICMPV6_TYPES_H_ */ +/** @} */ diff --git a/sys/net/crosslayer/ng_netreg/ng_netreg.c b/sys/net/crosslayer/ng_netreg/ng_netreg.c index 61d05806e9..b7b4239598 100644 --- a/sys/net/crosslayer/ng_netreg/ng_netreg.c +++ b/sys/net/crosslayer/ng_netreg/ng_netreg.c @@ -20,6 +20,7 @@ #include "net/ng_netreg.h" #include "net/ng_nettype.h" #include "net/ng_pkt.h" +#include "net/ng_icmpv6.h" #include "net/ng_ipv6.h" #define _INVALID_TYPE(type) (((type) < NG_NETTYPE_UNDEF) || ((type) >= NG_NETTYPE_NUMOF)) diff --git a/sys/net/network_layer/ng_icmpv6/Makefile b/sys/net/network_layer/ng_icmpv6/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/net/network_layer/ng_icmpv6/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c new file mode 100644 index 0000000000..f75e57b5aa --- /dev/null +++ b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2015 Martine Lenders <mlenders@inf.fu-berlin.de> + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for + * more details. + */ + +/** + * @ingroup net_ng_icmpv6 + * @{ + * + * @file + * + * @author Martine Lenders <mlenders@inf.fu-berlin.de> + */ + +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> + +#include "byteorder.h" +#include "kernel_types.h" +#include "net/ng_netbase.h" +#include "net/ng_protnum.h" +#include "net/ng_ipv6/hdr.h" +#include "od.h" +#include "utlist.h" + +#include "net/ng_icmpv6.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static inline uint16_t _calc_csum(ng_pktsnip_t *hdr, + ng_pktsnip_t *pseudo_hdr, + ng_pktsnip_t *payload) +{ + uint16_t csum = 0; + uint16_t len = (uint16_t)hdr->size; + + while (payload && (payload != hdr)) { + csum = ng_inet_csum(csum, payload->data, payload->size); + len += (uint16_t)payload->size; + payload = payload->next; + } + + csum = ng_inet_csum(csum, hdr->data, hdr->size); + csum = ng_ipv6_hdr_inet_csum(csum, pseudo_hdr->data, NG_PROTNUM_ICMPV6, + len); + + return ~csum; +} + +void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt) +{ + ng_pktsnip_t *icmpv6, *ipv6; + ng_icmpv6_hdr_t *hdr; + ng_netreg_entry_t *sendto; + + LL_SEARCH_SCALAR(pkt, icmpv6, type, NG_NETTYPE_ICMPV6); + + /* there can be extension headers between IPv6 and ICMPv6 header so we have + * to search it */ + LL_SEARCH_SCALAR(icmpv6, ipv6, type, NG_NETTYPE_IPV6); + + hdr = (ng_icmpv6_hdr_t *)icmpv6->data; + + if (_calc_csum(icmpv6, ipv6, pkt)) { + DEBUG("icmpv6: wrong checksum.\n"); + /* don't release: IPv6 does this */ + return; + } + + switch (hdr->type) { + /* TODO: handle ICMPv6 errors */ +#ifdef MODULE_NG_ICMPV6_ECHO + case NG_ICMPV6_ECHO_REQ: + DEBUG("icmpv6: handle echo request.\n"); + /* TODO */ + break; +#endif + +#ifdef MODULE_NG_NDP + case NG_ICMPV6_RTR_SOL: + case NG_ICMPV6_RTR_ADV: + case NG_ICMPV6_NBR_SOL: + case NG_ICMPV6_NBR_ADV: + case NG_ICMPV6_REDIRECT: + DEBUG("icmpv6: neighbor discovery message received\n"); + /* TODO */ + break; +#endif + +#ifdef MODULE_NG_RPL + case NG_ICMPV6_RPL_CTRL: + DEBUG("icmpv6: RPL control message received\n"); + /* TODO */ + break; +#endif + + default: + DEBUG("icmpv6: unknown type field %" PRIu8 "\n", hdr->type); + break; + } + + /* ICMPv6-all will be send in ng_ipv6.c so only dispatch of subtypes is + * needed */ + + sendto = ng_netreg_lookup(NG_NETTYPE_ICMPV6, hdr->type); + + if (sendto == NULL) { + DEBUG("icmpv6: no receivers for ICMPv6 type %" PRIu8 "\n", hdr->type); + /* don't release: IPv6 does this */ + return; + } + + /* ICMPv6 is not interested anymore so `- 1` */ + ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_ICMPV6, hdr->type) - 1); + + while (sendto != NULL) { + ng_netapi_receive(sendto->pid, pkt); + sendto = ng_netreg_getnext(sendto); + } +} + +ng_pktsnip_t *ng_icmpv6_build(uint8_t type, uint8_t code, size_t size) +{ + ng_pktsnip_t *pkt; + ng_icmpv6_hdr_t *icmpv6; + + pkt = ng_pktbuf_add(NULL, NULL, size, NG_NETTYPE_ICMPV6); + + if (pkt == NULL) { + DEBUG("icmpv6_echo: no space left in packet buffer\n"); + return NULL; + } + + DEBUG("icmpv6: Building ICMPv6 message with type=%" PRIu8 ", code=%" PRIu8 "\n", + type, code); + icmpv6 = (ng_icmpv6_hdr_t *)pkt->data; + icmpv6->type = type; + icmpv6->code = code; + + return pkt; +} + +int ng_icmpv6_calc_csum(ng_pktsnip_t *hdr, ng_pktsnip_t *pseudo_hdr) +{ + uint32_t csum = 0; + + if (hdr == NULL) { + return -EFAULT; + } + if (hdr->type != NG_NETTYPE_ICMPV6) { + return -EBADMSG; + } + + csum = _calc_csum(hdr, pseudo_hdr, hdr->next); + + if (csum == 0) { + return -ENOENT; + } + + ((ng_icmpv6_hdr_t *)hdr->data)->csum = byteorder_htons(csum); + + return 0; +} + +/** + * @} + */ diff --git a/sys/net/network_layer/ng_ipv6/ng_ipv6.c b/sys/net/network_layer/ng_ipv6/ng_ipv6.c index b53d5d3b2c..eb59ae0664 100644 --- a/sys/net/network_layer/ng_ipv6/ng_ipv6.c +++ b/sys/net/network_layer/ng_ipv6/ng_ipv6.c @@ -18,6 +18,7 @@ #include "byteorder.h" #include "cpu-conf.h" #include "kernel_types.h" +#include "net/ng_icmpv6.h" #include "net/ng_netbase.h" #include "net/ng_protnum.h" #include "thread.h" @@ -68,8 +69,14 @@ void ng_ipv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt, uint8_t nh) pkt->type = ng_nettype_from_protnum(nh); - /* TODO: add ICMPv6 and extension header handling */ - (void)iface; /* will be used by that */ + switch (nh) { + case NG_PROTNUM_ICMPV6: + ng_icmpv6_demux(iface, pkt); + break; + /* TODO: add extension header handling */ + default: + break; + } receiver_num = ng_netreg_num(pkt->type, NG_NETREG_DEMUX_CTX_ALL) + ng_netreg_num(NG_NETTYPE_IPV6, nh); -- GitLab