mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-12-25 22:43:50 +01:00
Merge pull request #8594 from miri64/gnrc_icmpv6_error/enh/use-icmpv6-error
gnrc_icmpv6_error: fix and use where appropriate
This commit is contained in:
commit
3b1a7d0eee
@ -20,6 +20,8 @@ BOARD_INSUFFICIENT_MEMORY := arduino-duemilanove arduino-mega2560 arduino-uno \
|
||||
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
|
||||
USEMODULE += gnrc_netdev_default
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
# Activate ICMPv6 error messages
|
||||
USEMODULE += gnrc_icmpv6_error
|
||||
# Specify the mandatory networking modules for IPv6 and UDP
|
||||
USEMODULE += gnrc_ipv6_router_default
|
||||
USEMODULE += gnrc_udp
|
||||
|
||||
@ -33,133 +33,63 @@
|
||||
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);
|
||||
|
||||
#if defined(MODULE_GNRC_ICMPV6_ERROR) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief Sends an ICMPv6 destination unreachable message for sending.
|
||||
*
|
||||
* @param[in] code The code for the message @see net/icmpv6.h.
|
||||
* @pre @p orig_pkt contains a packet snip of type @ref GNRC_NETTYPE_IPV6
|
||||
*
|
||||
* @param[in] code The [code for the message](@ref net_icmpv6_error_dst_unr_codes).
|
||||
* @param[in] orig_pkt The invoking packet.
|
||||
*/
|
||||
static inline void gnrc_icmpv6_error_dst_unr_send(uint8_t code, gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_icmpv6_error_dst_unr_build(code, orig_pkt);
|
||||
|
||||
if (pkt != NULL) {
|
||||
gnrc_netapi_send(gnrc_ipv6_pid, pkt);
|
||||
}
|
||||
#ifdef MODULE_GNRC_PKTBUF
|
||||
gnrc_pktbuf_release_error(orig_pkt, EHOSTUNREACH);
|
||||
#else
|
||||
(void)orig_pkt;
|
||||
#endif
|
||||
}
|
||||
void gnrc_icmpv6_error_dst_unr_send(uint8_t code, const gnrc_pktsnip_t *orig_pkt);
|
||||
|
||||
/**
|
||||
* @brief Sends an ICMPv6 packet too big message for sending.
|
||||
*
|
||||
* @pre @p orig_pkt contains a packet snip of type @ref GNRC_NETTYPE_IPV6
|
||||
*
|
||||
* @param[in] mtu The maximum transission unit of the next-hop link.
|
||||
* @param[in] orig_pkt The invoking packet.
|
||||
*/
|
||||
static inline void gnrc_icmpv6_error_pkt_too_big_send(uint32_t mtu, gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_icmpv6_error_pkt_too_big_build(mtu, orig_pkt);
|
||||
|
||||
if (pkt != NULL) {
|
||||
gnrc_netapi_send(gnrc_ipv6_pid, pkt);
|
||||
}
|
||||
#ifdef MODULE_GNRC_PKTBUF
|
||||
gnrc_pktbuf_release_error(orig_pkt, EMSGSIZE);
|
||||
#else
|
||||
(void)orig_pkt;
|
||||
#endif
|
||||
}
|
||||
void gnrc_icmpv6_error_pkt_too_big_send(uint32_t mtu,
|
||||
const gnrc_pktsnip_t *orig_pkt);
|
||||
|
||||
/**
|
||||
* @brief Sends an ICMPv6 time exceeded message for sending.
|
||||
*
|
||||
* @param[in] code The code for the message @see net/icmpv6.h.
|
||||
* @pre @p orig_pkt contains a packet snip of type @ref GNRC_NETTYPE_IPV6
|
||||
*
|
||||
* @param[in] code The [code for the message](@ref net_icmpv6_error_time_exc_codes).
|
||||
* @param[in] orig_pkt The invoking packet.
|
||||
*/
|
||||
static inline void gnrc_icmpv6_error_time_exc_send(uint8_t code, gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_icmpv6_error_time_exc_build(code, orig_pkt);
|
||||
|
||||
if (pkt != NULL) {
|
||||
gnrc_netapi_send(gnrc_ipv6_pid, pkt);
|
||||
}
|
||||
#ifdef MODULE_GNRC_PKTBUF
|
||||
gnrc_pktbuf_release_error(orig_pkt, ETIMEDOUT);
|
||||
#else
|
||||
(void)orig_pkt;
|
||||
#endif
|
||||
}
|
||||
void gnrc_icmpv6_error_time_exc_send(uint8_t code,
|
||||
const gnrc_pktsnip_t *orig_pkt);
|
||||
|
||||
/**
|
||||
* @brief Sends an ICMPv6 parameter problem message for sending.
|
||||
*
|
||||
* @param[in] code The code for the message @see net/icmpv6.h.
|
||||
* @pre @p orig_pkt is in receive order.
|
||||
* @pre @p orig_pkt contains a packet snip of type @ref GNRC_NETTYPE_IPV6
|
||||
*
|
||||
*
|
||||
* @param[in] code The [code for the message](@ref net_icmpv6_error_param_prob_codes).
|
||||
* @param[in] ptr Pointer to the errorneous octet in @p orig_pkt.
|
||||
* @param[in] orig_pkt The invoking packet.
|
||||
*/
|
||||
static inline void gnrc_icmpv6_error_param_prob_send(uint8_t code, void *ptr,
|
||||
gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_icmpv6_error_param_prob_build(code, ptr, orig_pkt);
|
||||
|
||||
if (pkt != NULL) {
|
||||
gnrc_netapi_send(gnrc_ipv6_pid, pkt);
|
||||
}
|
||||
#ifdef MODULE_GNRC_PKTBUF
|
||||
gnrc_pktbuf_release_error(orig_pkt, EINVAL);
|
||||
#else
|
||||
(void)orig_pkt;
|
||||
#endif
|
||||
}
|
||||
void gnrc_icmpv6_error_param_prob_send(uint8_t code, void *ptr,
|
||||
const gnrc_pktsnip_t *orig_pkt);
|
||||
#else /* defined(MODULE_GNRC_ICMPV6_ERROR) || defined(DOXYGEN) */
|
||||
/* NOPs to make the usage code more readable */
|
||||
#define gnrc_icmpv6_error_dst_unr_send(code, orig_pkt) \
|
||||
(void)code; (void)orig_pkt
|
||||
#define gnrc_icmpv6_error_pkt_too_big_send(mtu, orig_pkt) \
|
||||
(void)mtu; (void)orig_pkt
|
||||
#define gnrc_icmpv6_error_time_exc_send(code, orig_pkt) \
|
||||
(void)code; (void)orig_pkt
|
||||
#define gnrc_icmpv6_error_param_prob_send(code, ptr, orig_pkt) \
|
||||
(void)code; (void)ptr, (void)orig_pkt
|
||||
#endif /* defined(MODULE_GNRC_ICMPV6_ERROR) || defined(DOXYGEN) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@ -75,6 +75,7 @@ extern "C" {
|
||||
* @{
|
||||
* @name Codes for destination unreachable messages
|
||||
*
|
||||
* @anchor net_icmpv6_error_dst_unr_codes
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4443#section-3.1">
|
||||
* RFC 4443, section 3.1
|
||||
* </a>
|
||||
@ -97,6 +98,7 @@ extern "C" {
|
||||
* @{
|
||||
* @name Codes for time exceeded messages
|
||||
*
|
||||
* @anchor net_icmpv6_error_time_exc_codes
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4443#section-3.3">
|
||||
* RFC 4443, section 3.3
|
||||
* </a>
|
||||
@ -111,6 +113,7 @@ extern "C" {
|
||||
* @{
|
||||
* @name Codes for parameter problem messages
|
||||
*
|
||||
* @anchor net_icmpv6_error_param_prob_codes
|
||||
* @see <a href="https://tools.ietf.org/html/rfc4443#section-3.4">
|
||||
* RFC 4443, section 3.4
|
||||
* </a>
|
||||
|
||||
@ -12,59 +12,145 @@
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "net/ipv6.h"
|
||||
#include "net/gnrc/icmpv6.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/gnrc/pktbuf.h"
|
||||
|
||||
#include "net/ipv6.h"
|
||||
#include "net/gnrc/icmpv6/error.h"
|
||||
#include "net/gnrc/icmpv6.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.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)
|
||||
/**
|
||||
* @brief Get packet fit.
|
||||
*
|
||||
* Get's the minimum size for an ICMPv6 error message packet, based on the
|
||||
* invoking packet's size and the interface the invoking packet came over.
|
||||
*
|
||||
* @param[in] orig_pkt The invoking packet
|
||||
*
|
||||
* @return The supposed size of the ICMPv6 error message.
|
||||
*/
|
||||
static size_t _fit(const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
/* TODO: replace IPV6_MIN_MTU with known path MTU? */
|
||||
return MIN((gnrc_pkt_len(pkt) + ICMPV6_ERROR_SZ), IPV6_MIN_MTU);
|
||||
/* discarding const qualifier is safe here */
|
||||
gnrc_pktsnip_t *netif_hdr = gnrc_pktsnip_search_type(
|
||||
(gnrc_pktsnip_t *)orig_pkt, GNRC_NETTYPE_NETIF
|
||||
);
|
||||
size_t pkt_len = gnrc_pkt_len(orig_pkt) + ICMPV6_ERROR_SZ +
|
||||
sizeof(ipv6_hdr_t);
|
||||
|
||||
if (netif_hdr) {
|
||||
gnrc_netif_hdr_t *data = netif_hdr->data;
|
||||
gnrc_netif_t *netif = gnrc_netif_get_by_pid(data->if_pid);
|
||||
|
||||
pkt_len -= netif_hdr->size;
|
||||
DEBUG("gnrc_icmpv6_error: fitting to MTU of iface %u (%u)\n",
|
||||
netif->pid, netif->ipv6.mtu);
|
||||
return MIN(pkt_len, netif->ipv6.mtu - sizeof(ipv6_hdr_t));
|
||||
}
|
||||
else {
|
||||
/* packet does not have a netif header (most likely because it did not
|
||||
* came from remote) => just assume pkt_len as ideal */
|
||||
DEBUG("gnrc_icmpv6_error: copying whole packet\n");
|
||||
return pkt_len;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool _in_orig_pkt(const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
return (orig_pkt != NULL) && (orig_pkt->type != GNRC_NETTYPE_NETIF);
|
||||
}
|
||||
|
||||
static size_t _copy_rcv_snip(gnrc_pktsnip_t *pkt,
|
||||
const gnrc_pktsnip_t *orig_snip)
|
||||
{
|
||||
/* always skip ICMPv6 error header */
|
||||
size_t offset = ICMPV6_ERROR_SZ;
|
||||
const gnrc_pktsnip_t *ptr = orig_snip;
|
||||
|
||||
while (_in_orig_pkt(ptr->next)) {
|
||||
offset += ptr->next->size;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
if (offset < pkt->size) {
|
||||
uint8_t *data = pkt->data;
|
||||
|
||||
memcpy(data + offset, orig_snip->data,
|
||||
MIN(pkt->size - offset, orig_snip->size));
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
static inline bool _check_send_order(const gnrc_pktsnip_t *pkt)
|
||||
{
|
||||
/* sent packets in IPv6 start either with netif header or
|
||||
* with IPv6 header (but then the NETIF header doesn't follow) */
|
||||
return (pkt->type == GNRC_NETTYPE_NETIF) ||
|
||||
((pkt->type == GNRC_NETTYPE_IPV6) &&
|
||||
((pkt->next == NULL) || (pkt->next->type != GNRC_NETTYPE_NETIF)));
|
||||
}
|
||||
|
||||
/* 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)
|
||||
const 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 */
|
||||
/* 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;
|
||||
ICMPV6_ERROR_SET_VALUE(pkt->data, value);
|
||||
if (_check_send_order(orig_pkt)) {
|
||||
const gnrc_pktsnip_t *ptr = (orig_pkt->type == GNRC_NETTYPE_NETIF)
|
||||
? orig_pkt->next
|
||||
: orig_pkt;
|
||||
size_t offset = ICMPV6_ERROR_SZ;
|
||||
|
||||
while ((ptr != NULL) && (offset < pkt->size)) {
|
||||
uint8_t *data = pkt->data;
|
||||
|
||||
memcpy(data + offset, ptr->data, MIN(pkt->size - offset,
|
||||
ptr->size));
|
||||
offset += ptr->size;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (_in_orig_pkt(orig_pkt)) {
|
||||
_copy_rcv_snip(pkt, orig_pkt);
|
||||
orig_pkt = orig_pkt->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
gnrc_pktsnip_t *gnrc_icmpv6_error_dst_unr_build(uint8_t code, gnrc_pktsnip_t *orig_pkt)
|
||||
static inline gnrc_pktsnip_t *_dst_unr_build(uint8_t code,
|
||||
const 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)
|
||||
static inline gnrc_pktsnip_t *_pkt_too_big_build(uint32_t mtu,
|
||||
const 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)
|
||||
static inline gnrc_pktsnip_t *_time_exc_build(uint8_t code,
|
||||
const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
return _icmpv6_error_build(ICMPV6_TIME_EXC, code, orig_pkt, 0);
|
||||
}
|
||||
@ -74,8 +160,8 @@ 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)
|
||||
static gnrc_pktsnip_t *_param_prob_build(uint8_t code, void *ptr,
|
||||
const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = gnrc_icmpv6_build(NULL, ICMPV6_PARAM_PROB, code,
|
||||
_fit(orig_pkt));
|
||||
@ -83,39 +169,107 @@ gnrc_pktsnip_t *gnrc_icmpv6_error_param_prob_build(uint8_t code, void *ptr,
|
||||
/* 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;
|
||||
icmpv6_error_param_prob_t *hdr = 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);
|
||||
}
|
||||
while (_in_orig_pkt(orig_pkt)) {
|
||||
/* copy as long as it fits into packet; parameter problem can only
|
||||
* come from received packets */
|
||||
size_t offset = _copy_rcv_snip(pkt, orig_pkt);
|
||||
|
||||
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;
|
||||
ptr_offset = (uint32_t)(((uint8_t *)ptr) -
|
||||
((uint8_t *)orig_pkt->data) +
|
||||
(offset - ICMPV6_ERROR_SZ));
|
||||
}
|
||||
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);
|
||||
hdr->ptr = byteorder_htonl(ptr_offset);
|
||||
}
|
||||
|
||||
return pkt;
|
||||
}
|
||||
|
||||
static void _send(gnrc_pktsnip_t *pkt, const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
if (pkt != NULL) {
|
||||
/* discarding const qualifier is safe here */
|
||||
gnrc_pktsnip_t *ipv6 = gnrc_pktsnip_search_type((gnrc_pktsnip_t *)orig_pkt,
|
||||
GNRC_NETTYPE_IPV6);
|
||||
gnrc_pktsnip_t *netif = gnrc_pktsnip_search_type((gnrc_pktsnip_t *)orig_pkt,
|
||||
GNRC_NETTYPE_NETIF);
|
||||
assert(ipv6 != NULL);
|
||||
ipv6_hdr_t *ipv6_hdr = ipv6->data;
|
||||
ipv6 = gnrc_ipv6_hdr_build(pkt, NULL, &ipv6_hdr->src);
|
||||
if (ipv6 == NULL) {
|
||||
DEBUG("gnrc_icmpv6_error: No space in packet buffer left\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
pkt = ipv6;
|
||||
if (netif) {
|
||||
/* copy interface from original netif header to assure packet
|
||||
* goes out where it came from */
|
||||
gnrc_netif_hdr_t *netif_hdr = netif->data;
|
||||
kernel_pid_t netif_pid = netif_hdr->if_pid;
|
||||
|
||||
netif = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
if (netif == NULL) {
|
||||
DEBUG("gnrc_icmpv6_error: No space in packet buffer left\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
netif_hdr = netif->data;
|
||||
netif_hdr->if_pid = netif_pid;
|
||||
LL_PREPEND(pkt, netif);
|
||||
}
|
||||
if (!gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
pkt)) {
|
||||
DEBUG("gnrc_icmpv6_error: No send handler found.\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("gnrc_icmpv6_error: No space in packet buffer left\n");
|
||||
}
|
||||
}
|
||||
|
||||
void gnrc_icmpv6_error_dst_unr_send(uint8_t code, const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = _dst_unr_build(code, orig_pkt);
|
||||
|
||||
DEBUG("gnrc_icmpv6_error: trying to send destination unreachable error\n");
|
||||
_send(pkt, orig_pkt);
|
||||
}
|
||||
|
||||
void gnrc_icmpv6_error_pkt_too_big_send(uint32_t mtu,
|
||||
const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = _pkt_too_big_build(mtu, orig_pkt);
|
||||
|
||||
DEBUG("gnrc_icmpv6_error: trying to send packet too big error\n");
|
||||
_send(pkt, orig_pkt);
|
||||
}
|
||||
|
||||
void gnrc_icmpv6_error_time_exc_send(uint8_t code,
|
||||
const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = _time_exc_build(code, orig_pkt);
|
||||
|
||||
DEBUG("gnrc_icmpv6_error: trying to send time exceeded error\n");
|
||||
_send(pkt, orig_pkt);
|
||||
}
|
||||
|
||||
void gnrc_icmpv6_error_param_prob_send(uint8_t code, void *ptr,
|
||||
const gnrc_pktsnip_t *orig_pkt)
|
||||
{
|
||||
gnrc_pktsnip_t *pkt = _param_prob_build(code, ptr, orig_pkt);
|
||||
|
||||
DEBUG("gnrc_icmpv6_error: trying to send parameter problem error\n");
|
||||
_send(pkt, orig_pkt);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
@ -321,7 +321,8 @@ static void _send_to_iface(gnrc_netif_t *netif, gnrc_pktsnip_t *pkt)
|
||||
((gnrc_netif_hdr_t *)pkt->data)->if_pid = netif->pid;
|
||||
if (gnrc_pkt_len(pkt->next) > netif->ipv6.mtu) {
|
||||
DEBUG("ipv6: packet too big\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
gnrc_icmpv6_error_pkt_too_big_send(netif->ipv6.mtu, pkt);
|
||||
gnrc_pktbuf_release_error(pkt, EMSGSIZE);
|
||||
return;
|
||||
}
|
||||
#ifdef MODULE_NETSTATS_IPV6
|
||||
@ -742,6 +743,7 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
#ifdef MODULE_GNRC_IPV6_WHITELIST
|
||||
if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(pkt->data))->src)) {
|
||||
DEBUG("ipv6: Source address not whitelisted, dropping packet\n");
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PROHIB, pkt);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
@ -749,6 +751,7 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
#ifdef MODULE_GNRC_IPV6_BLACKLIST
|
||||
if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(pkt->data))->src)) {
|
||||
DEBUG("ipv6: Source address blacklisted, dropping packet\n");
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PROHIB, pkt);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
@ -779,6 +782,7 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
else if (!gnrc_ipv6_whitelisted(&((ipv6_hdr_t *)(ipv6->data))->src)) {
|
||||
/* if ipv6 header already marked*/
|
||||
DEBUG("ipv6: Source address not whitelisted, dropping packet\n");
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PROHIB, pkt);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
@ -787,6 +791,7 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
else if (gnrc_ipv6_blacklisted(&((ipv6_hdr_t *)(ipv6->data))->src)) {
|
||||
/* if ipv6 header already marked*/
|
||||
DEBUG("ipv6: Source address blacklisted, dropping packet\n");
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PROHIB, pkt);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
@ -812,7 +817,9 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
DEBUG("ipv6: invalid payload length: %d, actual: %d, dropping packet\n",
|
||||
(int) byteorder_ntohs(hdr->len),
|
||||
(int) (gnrc_pkt_len_upto(pkt, GNRC_NETTYPE_IPV6) - sizeof(ipv6_hdr_t)));
|
||||
gnrc_pktbuf_release(pkt);
|
||||
gnrc_icmpv6_error_param_prob_send(ICMPV6_ERROR_PARAM_PROB_HDR_FIELD,
|
||||
&(hdr->len), pkt);
|
||||
gnrc_pktbuf_release_error(pkt, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -836,6 +843,15 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
if ((ipv6_addr_is_link_local(&(hdr->src))) || (ipv6_addr_is_link_local(&(hdr->dst)))) {
|
||||
DEBUG("ipv6: do not forward packets with link-local source or"
|
||||
" destination address\n");
|
||||
#ifdef MODULE_GNRC_ICMPV6_ERROR
|
||||
if (ipv6_addr_is_link_local(&(hdr->src)) &&
|
||||
!ipv6_addr_is_link_local(&(hdr->dst))) {
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_SCOPE, pkt);
|
||||
}
|
||||
else if (!ipv6_addr_is_multicast(&(hdr->dst))) {
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR, pkt);
|
||||
}
|
||||
#endif
|
||||
gnrc_pktbuf_release(pkt);
|
||||
return;
|
||||
}
|
||||
@ -868,7 +884,8 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
}
|
||||
else {
|
||||
DEBUG("ipv6: hop limit reached 0: drop packet\n");
|
||||
gnrc_pktbuf_release(pkt);
|
||||
gnrc_icmpv6_error_time_exc_send(ICMPV6_ERROR_TIME_EXC_HL, pkt);
|
||||
gnrc_pktbuf_release_error(pkt, ETIMEDOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "net/gnrc/icmpv6/error.h"
|
||||
#include "net/gnrc/ipv6.h"
|
||||
#include "net/gnrc/ipv6/nib/conf.h"
|
||||
#include "net/gnrc/ipv6/nib/nc.h"
|
||||
@ -265,6 +266,8 @@ void _nib_nc_remove(_nib_onl_entry_t *node)
|
||||
(ptr != NULL) && (tmp = (ptr->next), 1);
|
||||
ptr = tmp) {
|
||||
gnrc_pktqueue_t *entry = gnrc_pktqueue_remove(&node->pktqueue, ptr);
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR,
|
||||
entry->pkt);
|
||||
gnrc_pktbuf_release_error(entry->pkt, EHOSTUNREACH);
|
||||
entry->pkt = NULL;
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
|
||||
#include "log.h"
|
||||
#include "net/ipv6/addr.h"
|
||||
#include "net/gnrc/icmpv6/error.h"
|
||||
#include "net/gnrc/nettype.h"
|
||||
#include "net/gnrc/netif/internal.h"
|
||||
#include "net/gnrc/ipv6/nib.h"
|
||||
@ -203,6 +204,8 @@ int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
|
||||
* we also shouldn't release), but if netif is not defined we
|
||||
* should release in any case. */
|
||||
if (netif == NULL) {
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR,
|
||||
pkt);
|
||||
gnrc_pktbuf_release_error(pkt, EHOSTUNREACH);
|
||||
}
|
||||
res = -EHOSTUNREACH;
|
||||
@ -225,6 +228,8 @@ int gnrc_ipv6_nib_get_next_hop_l2addr(const ipv6_addr_t *dst,
|
||||
memcpy(&route.next_hop, dst, sizeof(route.next_hop));
|
||||
}
|
||||
else {
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_NO_ROUTE,
|
||||
pkt);
|
||||
res = -ENETUNREACH;
|
||||
gnrc_pktbuf_release_error(pkt, ENETUNREACH);
|
||||
break;
|
||||
@ -1168,9 +1173,13 @@ static bool _resolve_addr(const ipv6_addr_t *dst, gnrc_netif_t *netif,
|
||||
}
|
||||
}
|
||||
else {
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR,
|
||||
pkt);
|
||||
gnrc_pktbuf_release_error(pkt, EHOSTUNREACH);
|
||||
}
|
||||
#else /* GNRC_IPV6_NIB_CONF_QUEUE_PKT */
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_ADDR,
|
||||
pkt);
|
||||
gnrc_pktbuf_release_error(pkt, EHOSTUNREACH);
|
||||
#endif /* GNRC_IPV6_NIB_CONF_QUEUE_PKT */
|
||||
}
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#include "net/ipv6/hdr.h"
|
||||
#include "net/gnrc/udp.h"
|
||||
#include "net/gnrc.h"
|
||||
#include "net/gnrc/icmpv6/error.h"
|
||||
#include "net/inet_csum.h"
|
||||
|
||||
|
||||
@ -157,6 +158,8 @@ static void _receive(gnrc_pktsnip_t *pkt)
|
||||
/* send payload to receivers */
|
||||
if (!gnrc_netapi_dispatch_receive(GNRC_NETTYPE_UDP, port, pkt)) {
|
||||
DEBUG("udp: unable to forward packet as no one is interested in it\n");
|
||||
/* TODO determine if IPv6 packet, when IPv4 is implemented */
|
||||
gnrc_icmpv6_error_dst_unr_send(ICMPV6_ERROR_DST_UNR_PORT, pkt);
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user