From 591ef1826f55cf5f6a07605fcf7ee463b7831828 Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Sat, 7 Mar 2015 20:37:45 +0100 Subject: [PATCH 1/4] 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 61498f9d8ec3..3fe29f8597d9 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 2f3500c967bc..3ec57b53d6f1 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 000000000000..f4921036312f --- /dev/null +++ b/sys/include/net/ng_icmpv6.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + * RFC 4443 + * + * @{ + * + * @file + * @brief Definitions for ICMPv6 + * + * @author Martine Lenders + */ + +#ifndef NG_ICMPV6_H_ +#define NG_ICMPV6_H_ + +#include + +#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 + * RFC 4443, section 2.1 + * + */ +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 000000000000..fddac3d4f6ea --- /dev/null +++ b/sys/include/net/ng_icmpv6/types.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ +#ifndef NG_ICMPV6_TYPES_H_ +#define NG_ICMPV6_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @{ + * @name Error message types + * @see + * IANA, ICMPv6 "type" Numbers + * + */ +#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 + * IANA, ICMPv6 "type" Numbers + * + */ +#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 61d05806e912..b7b423959809 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 000000000000..48422e909a47 --- /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 000000000000..f75e57b5aaeb --- /dev/null +++ b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 + */ + +#include +#include +#include + +#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 b53d5d3b2c25..eb59ae066421 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); From da2ec1b89eeccdbc38a1110507624f96fc8c31ef Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Wed, 1 Apr 2015 17:29:07 +0200 Subject: [PATCH 2/4] ng_icmpv6_error: add preliminary header --- sys/include/net/ng_icmpv6.h | 1 + sys/include/net/ng_icmpv6/error.h | 156 ++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 sys/include/net/ng_icmpv6/error.h diff --git a/sys/include/net/ng_icmpv6.h b/sys/include/net/ng_icmpv6.h index f4921036312f..daec59a27ddc 100644 --- a/sys/include/net/ng_icmpv6.h +++ b/sys/include/net/ng_icmpv6.h @@ -34,6 +34,7 @@ #include "net/ng_nettype.h" #include "net/ng_pkt.h" +#include "net/ng_icmpv6/error.h" #include "net/ng_icmpv6/types.h" #ifdef __cplusplus diff --git a/sys/include/net/ng_icmpv6/error.h b/sys/include/net/ng_icmpv6/error.h new file mode 100644 index 000000000000..dd4f0a271217 --- /dev/null +++ b/sys/include/net/ng_icmpv6/error.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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_error ICMPv6 error messages + * @ingroup net_ng_icmpv6 + * @brief ICMPv6 error message handling and creation + * @{ + * + * @file + * @brief ICMPv6 error message definitions + * + * @author Martine Lenders + */ +#ifndef NG_ICMPV6_ERROR_H_ +#define NG_ICMPV6_ERROR_H_ + +#include + +#include "byteorder.h" +#include "kernel_types.h" +#include "net/ng_icmpv6/types.h" +#include "net/ng_ipv6/hdr.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @{ + * @name Codes for destination unreachable messages + * + * @see + * RFC 4443, section 3.1 + * + */ +#define NG_ICMPV6_ERROR_DEST_UNR_NO_ROUTE (0) /**< no route to destination */ +#define NG_ICMPV6_ERROR_DEST_UNR_PROHIB (1) /**< communictation with + * destination administratively + * prohibited */ +#define NG_ICMPV6_ERROR_DEST_UNR_SCOPE (2) /**< beyond scope of source address */ +#define NG_ICMPV6_ERROR_DEST_UNR_ADDR (3) /**< address unreachable */ +#define NG_ICMPV6_ERROR_DEST_UNR_PORT (4) /**< port unreachable */ +#define NG_ICMPV6_ERROR_DEST_UNR_POLICY (5) /**< source address failed ingress/egress + * policy */ +#define NG_ICMPV6_ERROR_DEST_UNR_REJECT (6) /**< reject route to destination */ +/** + * @} + */ + +/** + * @{ + * @name Codes for time exceeded messages + * + * @see + * RFC 4443, section 3.3 + * + */ +#define NG_ICMPV6_ERROR_TIME_EXC_HL (0) /**< hop limit exceeded in transit */ +#define NG_ICMPV6_ERROR_TIME_EXC_FRAG (1) /**< fragment reassembly time exceeded */ +/** + * @} + */ + +/** + * @{ + * @name Codes for parameter problem messages + * + * @see + * RFC 4443, section 3.4 + * + */ +#define NG_ICMPV6_ERROR_PARAM_PROB_HDR_FIELD (0) /**< errorneous header field + * encountered */ +#define NG_ICMPV6_ERROR_PARAM_PROB_NH (1) /**< unrecognized next header + * field encountered */ +#define NG_ICMPV6_ERROR_PARAM_PROB_OPT (2) /**< unrecognized IPv6 option + * field encountered */ +/** + * @} + */ + +/** + * @brief Destination unreachable message format. + * @extends ng_icmpv6_hdr_t + * + * @see + * RFC 4443, section 3.1 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< message type */ + uint8_t code; /**< message code */ + network_uint16_t csum; /**< checksum */ + network_uint32_t unused; /**< unused field */ +} ng_icmpv6_error_dst_unr_t; + +/** + * @brief Packet too big message format. + * @extends ng_icmpv6_hdr_t + * + * @see + * RFC 4443, section 3.2 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< message type */ + uint8_t code; /**< message code */ + network_uint16_t csum; /**< checksum */ + network_uint32_t mtu; /**< MTU */ +} ng_icmpv6_error_pkt_too_big_t; + +/** + * @brief Time exceeded message format. + * @extends ng_icmpv6_hdr_t + * + * @see + * RFC 4443, section 3.3 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< message type */ + uint8_t code; /**< message code */ + network_uint16_t csum; /**< checksum */ + network_uint32_t unused; /**< unused field */ +} ng_icmpv6_error_time_exc_t; + +/** + * @brief Parameter problem message format. + * @extends ng_icmpv6_hdr_t + * + * @see + * RFC 4443, section 3.3 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< message type */ + uint8_t code; /**< message code */ + network_uint16_t csum; /**< checksum */ + network_uint32_t ptr; /**< pointer */ +} ng_icmpv6_error_param_prob_t; + +/* TODO: implement build and handle functions */ + +#ifdef __cplusplus +} +#endif + +#endif /* NG_ICMPV6_ERROR_H_ */ +/** @} */ From 86133b8404c8d599ebf9bd5f8276f6bd0f5aa6bf Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Wed, 1 Apr 2015 17:35:23 +0200 Subject: [PATCH 3/4] ng_icmpv6_echo: initial import --- Makefile.dep | 5 + sys/Makefile | 3 + sys/include/net/ng_icmpv6.h | 1 + sys/include/net/ng_icmpv6/echo.h | 129 ++++++++++++++++++ sys/net/network_layer/ng_icmpv6/echo/Makefile | 3 + .../ng_icmpv6/echo/ng_icmpv6_echo.c | 119 ++++++++++++++++ sys/net/network_layer/ng_icmpv6/ng_icmpv6.c | 4 +- 7 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 sys/include/net/ng_icmpv6/echo.h create mode 100644 sys/net/network_layer/ng_icmpv6/echo/Makefile create mode 100644 sys/net/network_layer/ng_icmpv6/echo/ng_icmpv6_echo.c diff --git a/Makefile.dep b/Makefile.dep index 3fe29f8597d9..1ba040056832 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -53,6 +53,11 @@ ifneq (,$(filter ng_sixlowpan_ctx,$(USEMODULE))) USEMODULE += vtimer endif +ifneq (,$(filter ng_icmpv6_echo,$(USEMODULE))) + USEMODULE += ng_icmpv6 + USEMODULE += ng_netbase +endif + ifneq (,$(filter ng_icmpv6,$(USEMODULE))) USEMODULE += ng_ipv6 endif diff --git a/sys/Makefile b/sys/Makefile index 3ec57b53d6f1..33569987c6e7 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -65,6 +65,9 @@ endif ifneq (,$(filter ng_icmpv6,$(USEMODULE))) DIRS += net/network_layer/ng_icmpv6 endif +ifneq (,$(filter ng_icmpv6_echo,$(USEMODULE))) + DIRS += net/network_layer/ng_icmpv6/echo +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 index daec59a27ddc..ba590b20decc 100644 --- a/sys/include/net/ng_icmpv6.h +++ b/sys/include/net/ng_icmpv6.h @@ -34,6 +34,7 @@ #include "net/ng_nettype.h" #include "net/ng_pkt.h" +#include "net/ng_icmpv6/echo.h" #include "net/ng_icmpv6/error.h" #include "net/ng_icmpv6/types.h" diff --git a/sys/include/net/ng_icmpv6/echo.h b/sys/include/net/ng_icmpv6/echo.h new file mode 100644 index 000000000000..e7470746a3dc --- /dev/null +++ b/sys/include/net/ng_icmpv6/echo.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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_echo ICMPv6 echo messages + * @ingroup net_ng_icmpv6 + * @brief ICMPv6 echo request and reply + * @{ + * + * @file + * @brief ICMPv6 echo message definitions + * + * @author Martine Lenders + */ +#ifndef NG_ICMPV6_ECHO_H_ +#define NG_ICMPV6_ECHO_H_ + +#include + +#include "byteorder.h" +#include "kernel_types.h" +#include "net/ng_icmpv6/types.h" +#include "net/ng_ipv6/hdr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Echo request and response message format. + * @extends ng_icmpv6_hdr_t + * + * @see + * RFC 4443, section 4.1 + * + * @see + * RFC 4443, section 4.2 + * + */ +typedef struct __attribute__((packed)) { + uint8_t type; /**< message type */ + uint8_t code; /**< message code */ + network_uint16_t csum; /**< checksum */ + network_uint16_t id; /**< identifier */ + network_uint16_t seq; /**< Sequence number */ +} ng_icmpv6_echo_t; + +/** + * @brief Builds an ICMPv6 echo message of type @p type for sending. + * + * @param[in] type Type of the echo message. Expected to be either + * NG_ICMPV6_ECHO_REQ or NG_ICMPV6_ECHO_REP. + * @param[in] id ID for the echo message in host byte-order + * @param[in] seq Sequence number for the echo message in host byte-order + * @param[in] data Payload for the echo message + * @param[in] data_len Length of @p data + * + * @return The echo message on success + * @return NULL, on failure + */ +ng_pktsnip_t *ng_icmpv6_echo_build(uint8_t type, uint16_t id, uint16_t seq, + uint8_t *data, size_t data_len); + +/** + * @brief Builds an ICMPv6 echo request for sending. + * + * @see + * RFC 4443, section 4.1 + * + * + * @param[in] id ID for the echo request in host byte-order + * @param[in] seq Sequence number for the echo request in host byte-order + * @param[in] data Payload for the echo request + * @param[in] data_len Length of @p data + * + * @return The echo request message on success + * @return NULL, on failure + */ +static inline ng_pktsnip_t *ng_icmpv6_echo_req_build(uint16_t id, uint16_t seq, + uint8_t *data, size_t data_len) +{ + return ng_icmpv6_echo_build(NG_ICMPV6_ECHO_REQ, id, seq, data, data_len); +} + +/** + * @brief Builds an ICMPv6 echo reply for sending. + * + * @see + * RFC 4443, section 4.2 + * + * + * @param[in] id ID for the echo reply in host byte-order + * @param[in] seq Sequence number for the echo reply in host byte-order + * @param[in] data Payload for the echo reply + * @param[in] data_len Length of @p data + * + * @return The echo reply message on success + * @return NULL, on failure + */ +static inline ng_pktsnip_t *ng_icmpv6_echo_rep_build(uint16_t id, uint16_t seq, + uint8_t *data, size_t data_len) +{ + return ng_icmpv6_echo_build(NG_ICMPV6_ECHO_REP, id, seq, data, data_len); +} + + +/** + * @brief ICMPv6 echo request handler + * + * @param[in] iface The interface the echo requuest was received on. + * @param[in] ipv6_hdr The IPv6 header of the echo request. + * @param[in] echo The Echo Request message. + * @param[in] len Length of the echo request message (ng_ipv6_hdr_t::len + * of @p ipv6_hdr minus length of extension headers). + */ +void ng_icmpv6_echo_req_handle(kernel_pid_t iface, ng_ipv6_hdr_t *ipv6_hdr, + ng_icmpv6_echo_t *echo, uint16_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* NG_ICMPV6_ECHO_H_ */ +/** @} */ diff --git a/sys/net/network_layer/ng_icmpv6/echo/Makefile b/sys/net/network_layer/ng_icmpv6/echo/Makefile new file mode 100644 index 000000000000..f30fd54da6e7 --- /dev/null +++ b/sys/net/network_layer/ng_icmpv6/echo/Makefile @@ -0,0 +1,3 @@ +MODULE = ng_icmpv6_echo + +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/network_layer/ng_icmpv6/echo/ng_icmpv6_echo.c b/sys/net/network_layer/ng_icmpv6/echo/ng_icmpv6_echo.c new file mode 100644 index 000000000000..24f4701acbae --- /dev/null +++ b/sys/net/network_layer/ng_icmpv6/echo/ng_icmpv6_echo.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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. + */ + +/** + * @{ + * + * @file + */ + +#include "net/ng_netbase.h" + +#include "net/ng_icmpv6.h" +#include "net/ng_icmpv6/echo.h" +#include "utlist.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +ng_pktsnip_t *ng_icmpv6_echo_build(uint8_t type, uint16_t id, uint16_t seq, + uint8_t *data, size_t data_len) +{ + ng_pktsnip_t *pkt; + ng_icmpv6_echo_t *echo; + + if ((pkt = ng_icmpv6_build(type, 0, data_len + sizeof(ng_icmpv6_echo_t))) == NULL) { + return NULL; + } + + DEBUG("icmpv6_echo: Building echo message with type=%" PRIu8 "id=%" PRIu16 + ", seq=%" PRIu16, type, id, seq); + echo = (ng_icmpv6_echo_t *)pkt->data; + echo->id = byteorder_htons(id >> 16); + echo->seq = byteorder_htons(seq); + + if (data != NULL) { + memcpy(echo + 1, data, data_len); +#if defined(MODULE_OD) && ENABLE_DEBUG + DEBUG(", payload:\n"); + od_hex_dump(data, data_len, OD_WIDTH_DEFAULT); +#endif + DEBUG("\n"); + } +#if ENABLE_DEBUG + else { + DEBUG("\n"); + } +#endif + + return pkt; +} + +void ng_icmpv6_echo_req_handle(kernel_pid_t iface, ng_ipv6_hdr_t *ipv6_hdr, + ng_icmpv6_echo_t *echo, uint16_t len) +{ + uint8_t *payload = ((uint8_t *)echo) + sizeof(ng_icmpv6_echo_t); + ng_pktsnip_t *hdr, *pkt; + ng_netreg_entry_t *sendto = NULL; + + if ((echo == NULL) || (len < sizeof(ng_icmpv6_echo_t))) { + DEBUG("icmpv6_echo: echo was NULL or len (%" PRIu16 + ") was < sizeof(ng_icmpv6_echo_t)\n", len); + return; + } + + pkt = _echo_build(NG_ICMPV6_ECHO_REP, byteorder_ntohs(echo->id), + byteorder_ntohs(echo->seq), payload, + len - sizeof(ng_icmpv6_echo_t)); + + if (pkt == NULL) { + DEBUG("icmpv6_echo: no space left in packet buffer\n"); + return; + } + + if (ng_ipv6_addr_is_multicast(&ipv6_hdr->dst)) { + hdr = ng_ipv6_hdr_build(pkt, NULL, 0, (uint8_t *)&ipv6_hdr->src, + sizeof(ng_ipv6_addr_t)); + } + else { + hdr = ng_ipv6_hdr_build(pkt, (uint8_t *)&ipv6_hdr->dst, + sizeof(ng_ipv6_addr_t), (uint8_t *)&ipv6_hdr->src, + sizeof(ng_ipv6_addr_t)); + } + + if (hdr == NULL) { + DEBUG("icmpv6_echo: no space left in packet buffer\n"); + ng_pktbuf_release(pkt); + return; + } + + pkt = hdr; + hdr = ng_netif_hdr_build(NULL, 0, NULL, 0); + + ((ng_netif_hdr_t *)hdr->data)->if_pid = iface; + + LL_PREPEND(pkt, hdr); + + sendto = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL); + + if (sendto == NULL) { + DEBUG("icmpv6_echo: no receivers for IPv6 packets\n"); + ng_pktbuf_release(pkt); + return; + } + + /* ICMPv6 is not interested anymore so `- 1` */ + ng_pktbuf_hold(pkt, ng_netreg_num(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL) - 1); + + while (sendto != NULL) { + ng_netapi_send(sendto->pid, pkt); + sendto = ng_netreg_getnext(sendto); + } +} + +/** @} */ diff --git a/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c index f75e57b5aaeb..fb93c5a44da5 100644 --- a/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c +++ b/sys/net/network_layer/ng_icmpv6/ng_icmpv6.c @@ -28,6 +28,7 @@ #include "utlist.h" #include "net/ng_icmpv6.h" +#include "net/ng_icmpv6/echo.h" #define ENABLE_DEBUG (0) #include "debug.h" @@ -77,7 +78,8 @@ void ng_icmpv6_demux(kernel_pid_t iface, ng_pktsnip_t *pkt) #ifdef MODULE_NG_ICMPV6_ECHO case NG_ICMPV6_ECHO_REQ: DEBUG("icmpv6: handle echo request.\n"); - /* TODO */ + ng_icmpv6_echo_req_handle(iface, (ng_ipv6_hdr_t *)ipv6->data, + (ng_icmpv6_echo_t *)hdr, icmpv6->size); break; #endif From 229f49ad5dddcbcbd63b37605f00137bc2022b1f Mon Sep 17 00:00:00 2001 From: Martine Lenders Date: Wed, 1 Apr 2015 17:40:36 +0200 Subject: [PATCH 4/4] shell: add icmpv6_echo shell handler --- sys/shell/commands/Makefile | 3 + sys/shell/commands/sc_icmpv6_echo.c | 240 ++++++++++++++++++++++++++++ sys/shell/commands/shell_commands.c | 11 ++ 3 files changed, 254 insertions(+) create mode 100644 sys/shell/commands/sc_icmpv6_echo.c diff --git a/sys/shell/commands/Makefile b/sys/shell/commands/Makefile index d2d2dbf6e959..b64d70c46c76 100644 --- a/sys/shell/commands/Makefile +++ b/sys/shell/commands/Makefile @@ -64,6 +64,9 @@ endif ifneq (,$(filter ng_ipv6_nc,$(USEMODULE))) SRC += sc_ipv6_nc.c endif +ifneq (,$(filter ng_icmpv6_echo vtimer,$(USEMODULE))) + SRC += sc_icmpv6_echo.c +endif # TODO # Conditional building not possible at the moment due to diff --git a/sys/shell/commands/sc_icmpv6_echo.c b/sys/shell/commands/sc_icmpv6_echo.c new file mode 100644 index 000000000000..f9fb10257623 --- /dev/null +++ b/sys/shell/commands/sc_icmpv6_echo.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2015 Martine Lenders + * + * 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 sys_shell_commands + * @{ + * + * @file + * + * @author Martine Lenders + */ + +#include +#include + +#ifdef MODULE_NG_ICMPV6 + +#include "byteorder.h" +#include "net/ng_icmpv6.h" +#include "net/ng_ipv6/addr.h" +#include "net/ng_ipv6/hdr.h" +#include "net/ng_netbase.h" +#include "thread.h" +#include "utlist.h" +#include "vtimer.h" + +static uint16_t id = 0x53; +static uint16_t seq = 1; +static char ipv6_str[NG_IPV6_ADDR_MAX_STR_LEN]; + +static void usage(char **argv) +{ + printf("%s [] []\n", argv[0]); +} + +void _set_payload(ng_icmpv6_echo_t *hdr, size_t payload_len) +{ + size_t i = 0; + uint8_t *payload = (uint8_t *)(hdr + 1); + + while (i < payload_len) { + if (seq > 0xff) { + payload[i] = (uint8_t)(seq >> 8); + payload[i + 1] = (uint8_t)(seq & 0xff); + i += 2; + } + else { + payload[i++] = (uint8_t)(seq & 0xff); + } + } + + if (i > payload_len) { + payload[payload_len - 1] = seq >> 8; + } +} + +int _handle_reply(ng_pktsnip_t *pkt, uint64_t time) +{ + ng_pktsnip_t *ipv6, *icmpv6; + ng_ipv6_hdr_t *ipv6_hdr; + ng_icmpv6_echo_t *icmpv6_hdr; + + LL_SEARCH_SCALAR(pkt, ipv6, type, NG_NETTYPE_IPV6); + LL_SEARCH_SCALAR(pkt, icmpv6, type, NG_NETTYPE_ICMPV6); + + if ((ipv6 == NULL) || (icmpv6 == NULL)) { + puts("error: IPv6 header or ICMPv6 header not found in reply"); + return 0; + } + + ipv6_hdr = ipv6->data; + icmpv6_hdr = icmpv6->data; + + if ((byteorder_ntohs(icmpv6_hdr->id) == id) && + (byteorder_ntohs(icmpv6_hdr->seq) == seq)) { + printf("%zu bytes from %s: id=%" PRIu16 " seq=%" PRIu16 " hop limit=%" PRIu8 + "time = %" PRIu64 ".%03" PRIu64 " ms\n", icmpv6->size, + ng_ipv6_addr_to_str(ipv6_str, &(ipv6_hdr->src), sizeof(ipv6_str)), + byteorder_ntohs(icmpv6_hdr->id), byteorder_ntohs(icmpv6_hdr->seq), + ipv6_hdr->hl, time / MS_IN_USEC, time % MS_IN_USEC); + } + else { + puts("error: unexpected parameters"); + return 0; + } + + return 1; +} + +int _icmpv6_ping(int argc, char **argv) +{ + int n = 3, success = 0, count; + size_t payload_len = 4; + char *addr_str; + ng_ipv6_addr_t addr; + ng_netreg_entry_t *ipv6_entry, my_entry = { NULL, NG_ICMPV6_ECHO_REP, + thread_getpid() + }; + timex_t min_rtt = { UINT32_MAX, UINT32_MAX }, max_rtt = { 0, 0 }; + timex_t sum_rtt = { 0, 0 }; + + switch (argc) { + case 1: + usage(argv); + return 1; + + case 2: + addr_str = argv[1]; + break; + + case 3: + n = atoi(argv[1]); + addr_str = argv[2]; + break; + + case 4: + default: + n = atoi(argv[1]); + addr_str = argv[2]; + payload_len = atoi(argv[3]); + break; + } + + if (ng_ipv6_addr_from_str(&addr, addr_str) == NULL) { + usage(argv); + return 1; + } + + if (ng_netreg_register(NG_NETTYPE_ICMPV6, &my_entry) < 0) { + puts("error: network registry is full"); + return 1; + } + + ipv6_entry = ng_netreg_lookup(NG_NETTYPE_IPV6, NG_NETREG_DEMUX_CTX_ALL); + + if (ipv6_entry == NULL) { + puts("error: ipv6 thread missing"); + return 1; + } + + count = n; + + while ((count--) > 0) { + msg_t msg; + ng_pktsnip_t *pkt; + timex_t start, stop, timeout = { 5, 0 }; + + pkt = ng_icmpv6_echo_req_build(id, seq, NULL, payload_len); + + if (pkt == NULL) { + puts("error: packet buffer full"); + return 1; + } + + _set_payload(pkt->data, payload_len); + + pkt = ng_netreg_hdr_build(NG_NETTYPE_IPV6, pkt, NULL, 0, addr.u8, + sizeof(ng_ipv6_addr_t)); + + if (pkt == NULL) { + puts("error: packet buffer full"); + return 1; + } + + vtimer_now(&start); + ng_netapi_send(ipv6_entry->pid, pkt); + + if (vtimer_msg_receive_timeout(&msg, timeout) >= 0) { + switch (msg.type) { + case NG_NETAPI_MSG_TYPE_RCV: + vtimer_now(&stop); + stop = timex_sub(stop, start); + success += _handle_reply((ng_pktsnip_t *)msg.content.ptr, + timex_uint64(stop)); + + if (timex_cmp(stop, max_rtt) > 0) { + max_rtt = stop; + } + + if (timex_cmp(stop, min_rtt) < 1) { + min_rtt = stop; + } + + sum_rtt = timex_add(sum_rtt, stop); + + break; + + default: + /* requeue wrong packets */ + msg_send(&msg, thread_getpid()); + break; + } + } + else { + puts("ping timeout"); + } + + seq++; + } + + seq = 1; + id++; + + ng_netreg_unregister(NG_NETTYPE_ICMPV6, &my_entry); + + printf("--- %s ping statistics ---\n", addr_str); + + if (success > 0) { + printf("%d packets transmitted, %d received, %d%% packet loss, time %" + PRIu64 " ms\n", n, success, (success - n) / n, + timex_uint64(sum_rtt) / MS_IN_USEC); + uint64_t avg_rtt = timex_uint64(sum_rtt) / n; /* get average */ + printf("rtt min/avg/max = " + "%" PRIu64 ".%03" PRIu64 "/" + "%" PRIu64 ".%03" PRIu64 "/" + "%" PRIu64 ".%03" PRIu64 " ms\n", + timex_uint64(min_rtt) / MS_IN_USEC, + timex_uint64(min_rtt) % MS_IN_USEC, + avg_rtt / MS_IN_USEC, avg_rtt % MS_IN_USEC, /* sum is now avg, see above */ + timex_uint64(max_rtt) / MS_IN_USEC, + timex_uint64(max_rtt) % MS_IN_USEC); + } + else { + printf("%d packets transmitted, 0 received, 100%% packet loss\n", n); + return 1; + } + + return 0; +} + +#endif + +/** + * @} + */ diff --git a/sys/shell/commands/shell_commands.c b/sys/shell/commands/shell_commands.c index 87ec5baa6da8..c026933d83d0 100644 --- a/sys/shell/commands/shell_commands.c +++ b/sys/shell/commands/shell_commands.c @@ -145,6 +145,12 @@ extern int _read_sector(int argc, char **argv); extern int _read_bytes(int argc, char **argv); #endif +#ifdef MODULE_NG_ICMPV6_ECHO +#ifdef MODULE_VTIMER +extern int _icmpv6_ping(int argc, char **argv); +#endif +#endif + #ifdef MODULE_RANDOM extern int _mersenne_init(int argc, char **argv); extern int _mersenne_get(int argc, char **argv); @@ -250,6 +256,11 @@ const shell_command_t _shell_command_list[] = { {DISK_GET_SECTOR_COUNT, "Get the sector count of inserted memory card", _get_sectorcount}, {DISK_GET_BLOCK_SIZE, "Get the block size of inserted memory card", _get_blocksize}, #endif +#ifdef MODULE_NG_ICMPV6_ECHO +#ifdef MODULE_VTIMER + { "ping6", "Ping via ICMPv6", _icmpv6_ping }, +#endif +#endif #ifdef MODULE_RANDOM { "mersenne_init", "initializes the PRNG", _mersenne_init }, { "mersenne_get", "returns 32 bit of pseudo randomness", _mersenne_get },