1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:12:57 +01:00

gnrc_icmpv6_error: initial import

This commit is contained in:
Martine Lenders 2015-06-10 04:02:10 +02:00
parent 54e6163ab3
commit 70c3d29036
6 changed files with 185 additions and 3 deletions

View File

@ -197,6 +197,10 @@ ifneq (,$(filter gnrc_icmpv6_echo,$(USEMODULE)))
USEMODULE += gnrc_icmpv6
endif
ifneq (,$(filter gnrc_icmpv6_error,$(USEMODULE)))
USEMODULE += gnrc_icmpv6
endif
ifneq (,$(filter gnrc_icmpv6,$(USEMODULE)))
USEMODULE += inet_csum
USEMODULE += gnrc_ipv6

View File

@ -16,16 +16,66 @@
* @brief ICMPv6 error message definitions
*
* @author Martine Lenders <mlenders@inf.fu-berlin.de>
*
* @todo implement build and handle functions
*/
#ifndef GNRC_ICMPV6_ERROR_H_
#define GNRC_ICMPV6_ERROR_H_
#include <stdint.h>
#include "net/icmpv6.h"
#include "net/ipv6/hdr.h"
#include "net/gnrc/pkt.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Builds an ICMPv6 destination unreachable message for sending.
*
* @param[in] code The code for the message @see net/icmpv6.h.
* @param[in] orig_pkt The invoking packet.
*
* @return The destination unreachable message on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_icmpv6_error_dst_unr_build(uint8_t code, gnrc_pktsnip_t *orig_pkt);
/**
* @brief Builds an ICMPv6 packet too big message for sending.
*
* @param[in] mtu The maximum transission unit of the next-hop link.
* @param[in] orig_pkt The invoking packet.
*
* @return The packet too big message on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_icmpv6_error_pkt_too_big_build(uint32_t mtu, gnrc_pktsnip_t *orig_pkt);
/**
* @brief Builds an ICMPv6 time exceeded message for sending.
*
* @param[in] code The code for the message @see net/icmpv6.h.
* @param[in] orig_pkt The invoking packet.
*
* @return The time exceeded message on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_icmpv6_error_time_exc_build(uint8_t code, gnrc_pktsnip_t *orig_pkt);
/**
* @brief Builds an ICMPv6 parameter problem message for sending.
*
* @param[in] code The code for the message @see net/icmpv6.h.
* @param[in] ptr Pointer to the errorneous octet in @p orig_pkt.
* @param[in] orig_pkt The invoking packet.
*
* @return The parameter problem message on success.
* @return NULL, on failure.
*/
gnrc_pktsnip_t *gnrc_icmpv6_error_param_prob_build(uint8_t code, void *ptr,
gnrc_pktsnip_t *orig_pkt);
#ifdef __cplusplus
}
#endif

View File

@ -38,7 +38,7 @@ extern "C" {
* IANA, ICMPv6 "type" Numbers
* </a>
*/
#define ICMPV6_DEST_UNR (1) /**< Destination unreachable message */
#define ICMPV6_DST_UNR (1) /**< Destination unreachable message */
#define ICMPV6_PKT_TOO_BIG (2) /**< Packet Too Big message */
#define ICMPV6_TIME_EXC (3) /**< Time Exceeded message */
#define ICMPV6_PARAM_PROB (4) /**< Parameter Problem message */

View File

@ -13,6 +13,9 @@ endif
ifneq (,$(filter gnrc_icmpv6_echo,$(USEMODULE)))
DIRS += network_layer/icmpv6/echo
endif
ifneq (,$(filter gnrc_icmpv6_error,$(USEMODULE)))
DIRS += network_layer/icmpv6/error
endif
ifneq (,$(filter gnrc_ipv6,$(USEMODULE)))
DIRS += network_layer/ipv6
endif

View File

@ -0,0 +1,3 @@
MODULE = gnrc_icmpv6_error
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,122 @@
/*
* 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/gnrc/pktbuf.h"
#include "net/ipv6.h"
#include "net/gnrc/ipv6/netif.h"
#include "net/gnrc/icmpv6/error.h"
#include "net/gnrc/icmpv6.h"
/* all error messages are basically the same size and format */
#define ICMPV6_ERROR_SZ (sizeof(icmpv6_error_dst_unr_t))
#define ICMPV6_ERROR_SET_VALUE(data, value) \
((icmpv6_error_pkt_too_big_t *)(data))->mtu = byteorder_htonl(value)
/* TODO: generalize and centralize (see https://github.com/RIOT-OS/RIOT/pull/3184) */
#define MIN(a, b) ((a) < (b)) ? (a) : (b)
static inline size_t _fit(gnrc_pktsnip_t *pkt)
{
/* TODO: replace IPV6_MIN_MTU with known path MTU? */
return MIN((gnrc_pkt_len(pkt) + ICMPV6_ERROR_SZ), IPV6_MIN_MTU);
}
/* Build a generic error message */
static gnrc_pktsnip_t *_icmpv6_error_build(uint8_t type, uint8_t code,
gnrc_pktsnip_t *orig_pkt, uint32_t value)
{
gnrc_pktsnip_t *pkt = gnrc_icmpv6_build(NULL, type, code, _fit(orig_pkt));
/* copy as much of the originating packet into error message as fits the message's size */
if (pkt != NULL) {
size_t offset = ICMPV6_ERROR_SZ;
uint8_t *data = pkt->data;
ICMPV6_ERROR_SET_VALUE(data, value);
while ((orig_pkt != NULL) && (offset < pkt->size)) {
memcpy(data + offset, orig_pkt->data,
MIN(pkt->size - offset, orig_pkt->size));
offset += MIN(pkt->size - offset, orig_pkt->size);
orig_pkt = orig_pkt->next;
}
}
return pkt;
}
gnrc_pktsnip_t *gnrc_icmpv6_error_dst_unr_build(uint8_t code, gnrc_pktsnip_t *orig_pkt)
{
return _icmpv6_error_build(ICMPV6_DST_UNR, code, orig_pkt, 0);
}
gnrc_pktsnip_t *gnrc_icmpv6_error_pkt_too_big_build(uint32_t mtu, gnrc_pktsnip_t *orig_pkt)
{
return _icmpv6_error_build(ICMPV6_PKT_TOO_BIG, 0, orig_pkt, mtu);
}
gnrc_pktsnip_t *gnrc_icmpv6_error_time_exc_build(uint8_t code, gnrc_pktsnip_t *orig_pkt)
{
return _icmpv6_error_build(ICMPV6_TIME_EXC, code, orig_pkt, 0);
}
static inline bool _in_range(uint8_t *ptr, uint8_t *start, size_t sz)
{
return (ptr >= start) && (ptr < (start + sz));
}
gnrc_pktsnip_t *gnrc_icmpv6_error_param_prob_build(uint8_t code, void *ptr,
gnrc_pktsnip_t *orig_pkt)
{
gnrc_pktsnip_t *pkt = gnrc_icmpv6_build(NULL, ICMPV6_PARAM_PROB, code,
_fit(orig_pkt));
/* copy as much of the originating packet into error message and
* determine relative *ptr* offset */
if (pkt != NULL) {
size_t offset = sizeof(icmpv6_error_param_prob_t);
uint8_t *data = pkt->data;
uint32_t ptr_offset = 0U;
bool found_offset = false;
while (orig_pkt != NULL) {
/* copy as long as it fits into packet */
if (offset < pkt->size) {
memcpy(data + offset, orig_pkt->data,
MIN(pkt->size - offset, orig_pkt->size));
offset += MIN(pkt->size - offset, orig_pkt->size);
}
if (_in_range(ptr, orig_pkt->data, orig_pkt->size)) {
ptr_offset += (uint32_t)(((uint8_t *)ptr) - ((uint8_t *)orig_pkt->data));
found_offset = true;
}
else if (!found_offset) {
ptr_offset += (uint32_t)orig_pkt->size;
}
orig_pkt = orig_pkt->next;
if ((offset < pkt->size) && found_offset) {
break;
}
}
/* set "pointer" field to relative pointer offset */
((icmpv6_error_param_prob_t *)data)->ptr = byteorder_htonl(ptr_offset);
}
return pkt;
}
/** @} */