Merge pull request #2555 from authmillenon/ng_icmpv6/feat/initial
ng_icmpv6: Initial importdev/timer
commit
d1bfa2f2ff
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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/echo.h"
|
||||
#include "net/ng_icmpv6/error.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_ */
|
||||
/**
|
||||
* @}
|
||||
*/
|
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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_echo ICMPv6 echo messages
|
||||
* @ingroup net_ng_icmpv6
|
||||
* @brief ICMPv6 echo request and reply
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief ICMPv6 echo message definitions
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef NG_ICMPV6_ECHO_H_
|
||||
#define NG_ICMPV6_ECHO_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#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 <a href="https://tools.ietf.org/html/rfc4443#section-4.1">
|
||||
* RFC 4443, section 4.1
|
||||
* </a>
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4443#section-4.2">
|
||||
* RFC 4443, section 4.2
|
||||
* </a>
|
||||
*/
|
||||
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 <a href="https://tools.ietf.org/html/rfc4443#section-4.1">
|
||||
* RFC 4443, section 4.1
|
||||
* </a>
|
||||
*
|
||||
* @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 <a href="https://tools.ietf.org/html/rfc4443#section-4.2">
|
||||
* RFC 4443, section 4.2
|
||||
* </a>
|
||||
*
|
||||
* @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_ */
|
||||
/** @} */
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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_error ICMPv6 error messages
|
||||
* @ingroup net_ng_icmpv6
|
||||
* @brief ICMPv6 error message handling and creation
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief ICMPv6 error message definitions
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
#ifndef NG_ICMPV6_ERROR_H_
|
||||
#define NG_ICMPV6_ERROR_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#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 <a href="https://tools.ietf.org/html/rfc4443#section-3.1">
|
||||
* RFC 4443, section 3.1
|
||||
* </a>
|
||||
*/
|
||||
#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 <a href="https://tools.ietf.org/html/rfc4443#section-3.3">
|
||||
* RFC 4443, section 3.3
|
||||
* </a>
|
||||
*/
|
||||
#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 <a href="https://tools.ietf.org/html/rfc4443#section-3.4">
|
||||
* RFC 4443, section 3.4
|
||||
* </a>
|
||||
*/
|
||||
#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 <a href="https://tools.ietf.org/html/rfc4443#section-3.1">
|
||||
* RFC 4443, section 3.1
|
||||
* </a>
|
||||
*/
|
||||
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 <a href="https://tools.ietf.org/html/rfc4443#section-3.2">
|
||||
* RFC 4443, section 3.2
|
||||
* </a>
|
||||
*/
|
||||
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 <a href="https://tools.ietf.org/html/rfc4443#section-3.3">
|
||||
* RFC 4443, section 3.3
|
||||
* </a>
|
||||
*/
|
||||
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 <a href="https://tools.ietf.org/html/rfc4443#section-3.4">
|
||||
* RFC 4443, section 3.3
|
||||
* </a>
|
||||
*/
|
||||
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_ */
|
||||
/** @} */
|
@ -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_ */
|
||||
/** @} */
|
@ -0,0 +1 @@
|
||||
include $(RIOTBASE)/Makefile.base
|
@ -0,0 +1,3 @@
|
||||
MODULE = ng_icmpv6_echo
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @{
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "net/ng_icmpv6/echo.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");
|
||||
ng_icmpv6_echo_req_handle(iface, (ng_ipv6_hdr_t *)ipv6->data,
|
||||
(ng_icmpv6_echo_t *)hdr, icmpv6->size);
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* 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 sys_shell_commands
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
*
|
||||
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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>] <ipv6 addr> [<payload_len>]\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
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
Loading…
Reference in New Issue