net: icmp: Introduce new API to send ICMP messages
Allow user to send ICMP Echo Request message a.k.a pings. The same ICMP API and framework is used for network stack internal needs in later commits. One benefit for this new API is that it allows sending Echo Requests to offlined network devices. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
This commit is contained in:
parent
c631bc7757
commit
31a25da8c2
174
include/zephyr/net/icmp.h
Normal file
174
include/zephyr/net/icmp.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/** @file icmp.h
|
||||
*
|
||||
* @defgroup icmp Send and receive IPv4 or IPv6 ICMP Echo Request messages.
|
||||
* @ingroup networking
|
||||
* @{
|
||||
* @brief ICMP sending and receiving.
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_NET_ICMP_H_
|
||||
#define ZEPHYR_INCLUDE_NET_ICMP_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/types.h>
|
||||
#include <zephyr/net/net_ip.h>
|
||||
#include <zephyr/net/net_if.h>
|
||||
#include <zephyr/net/net_pkt.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define NET_ICMPV4_ECHO_REQUEST 8
|
||||
#define NET_ICMPV4_ECHO_REPLY 0
|
||||
#define NET_ICMPV6_ECHO_REQUEST 128
|
||||
#define NET_ICMPV6_ECHO_REPLY 129
|
||||
|
||||
struct net_icmp_ctx;
|
||||
struct net_icmp_ip_hdr;
|
||||
|
||||
/**
|
||||
* @typedef net_icmp_handler_t
|
||||
* @brief Handler function that is called when ICMP response is received.
|
||||
*
|
||||
* @param ctx ICMP context to use.
|
||||
* @param pkt Received ICMP response network packet.
|
||||
* @param ip_hdr IP header of the packet.
|
||||
* @param icmp_hdr ICMP header of the packet.
|
||||
* @param user_data A valid pointer to user data or NULL
|
||||
*/
|
||||
typedef int (*net_icmp_handler_t)(struct net_icmp_ctx *ctx,
|
||||
struct net_pkt *pkt,
|
||||
struct net_icmp_ip_hdr *ip_hdr,
|
||||
struct net_icmp_hdr *icmp_hdr,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @brief ICMP context structure.
|
||||
*/
|
||||
struct net_icmp_ctx {
|
||||
/** List node */
|
||||
sys_snode_t node;
|
||||
|
||||
/** ICMP response handler */
|
||||
net_icmp_handler_t handler;
|
||||
|
||||
/** Network interface where the ICMP request was sent */
|
||||
struct net_if *iface;
|
||||
|
||||
/** Opaque user supplied data */
|
||||
void *user_data;
|
||||
|
||||
/** ICMP type of the response we are waiting */
|
||||
uint8_t type;
|
||||
|
||||
/** ICMP code of the response type we are waiting */
|
||||
uint8_t code;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Struct presents either IPv4 or IPv6 header in ICMP response message.
|
||||
*/
|
||||
struct net_icmp_ip_hdr {
|
||||
union {
|
||||
/** IPv4 header in response message. */
|
||||
struct net_ipv4_hdr *ipv4;
|
||||
|
||||
/** IPv6 header in response message. */
|
||||
struct net_ipv6_hdr *ipv6;
|
||||
};
|
||||
|
||||
/** Is the header IPv4 or IPv6 one. Value of either AF_INET or AF_INET6 */
|
||||
sa_family_t family;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Struct presents parameters that are needed when sending
|
||||
* Echo-Request (ping) messages.
|
||||
*/
|
||||
struct net_icmp_ping_params {
|
||||
/** An identifier to aid in matching Echo Replies to this Echo Request.
|
||||
* May be zero.
|
||||
*/
|
||||
uint16_t identifier;
|
||||
|
||||
/** A sequence number to aid in matching Echo Replies to this
|
||||
* Echo Request. May be zero.
|
||||
*/
|
||||
uint16_t sequence;
|
||||
|
||||
/** Can be either IPv4 Type-of-service field value, or IPv6 Traffic
|
||||
* Class field value. Represents combined DSCP and ECN values.
|
||||
*/
|
||||
uint8_t tc_tos;
|
||||
|
||||
/** Network packet priority. */
|
||||
int priority;
|
||||
|
||||
/* Arbitrary payload data that will be included in the Echo Reply
|
||||
* verbatim. May be NULL.
|
||||
*/
|
||||
const void *data;
|
||||
|
||||
/** Size of the Payload Data in bytes. May be zero. In case data
|
||||
* pointer is NULL, the function will generate the payload up to
|
||||
* the requested size.
|
||||
*/
|
||||
size_t data_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Initialize the ICMP context structure. Must be called before
|
||||
* ICMP messages can be sent. This will register handler to the
|
||||
* system.
|
||||
*
|
||||
* @param ctx ICMP context used in this request.
|
||||
* @param type Type of ICMP message we are handling.
|
||||
* @param code Code of ICMP message we are handling.
|
||||
* @param handler Callback function that is called when a response is received.
|
||||
*/
|
||||
int net_icmp_init_ctx(struct net_icmp_ctx *ctx, uint8_t type, uint8_t code,
|
||||
net_icmp_handler_t handler);
|
||||
|
||||
/**
|
||||
* @brief Cleanup the ICMP context structure. This will unregister the ICMP handler
|
||||
* from the system.
|
||||
*
|
||||
* @param ctx ICMP context used in this request.
|
||||
*/
|
||||
int net_icmp_cleanup_ctx(struct net_icmp_ctx *ctx);
|
||||
|
||||
/**
|
||||
* @brief Send ICMP echo request message.
|
||||
*
|
||||
* @param ctx ICMP context used in this request.
|
||||
* @param iface Network interface, can be set to NULL in which case the
|
||||
* interface is selected according to destination address.
|
||||
* @param dst IP address of the target host.
|
||||
* @param params Echo-Request specific parameters. May be NULL in which case
|
||||
* suitable default parameters are used.
|
||||
* @param user_data User supplied opaque data passed to the handler. May be NULL.
|
||||
*
|
||||
* @return Return 0 if the sending succeed, <0 otherwise.
|
||||
*/
|
||||
int net_icmp_send_echo_request(struct net_icmp_ctx *ctx,
|
||||
struct net_if *iface,
|
||||
struct sockaddr *dst,
|
||||
struct net_icmp_ping_params *params,
|
||||
void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_NET_ICMP_H */
|
||||
|
||||
/**@} */
|
|
@ -28,6 +28,7 @@ if(CONFIG_NET_NATIVE)
|
|||
zephyr_library_sources(net_context.c)
|
||||
zephyr_library_sources(net_pkt.c)
|
||||
zephyr_library_sources(net_tc.c)
|
||||
zephyr_library_sources(icmp.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NET_IP connection.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NET_6LO 6lo.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_NET_DHCPV4 dhcpv4.c)
|
||||
|
|
438
subsys/net/ip/icmp.c
Normal file
438
subsys/net/ip/icmp.c
Normal file
|
@ -0,0 +1,438 @@
|
|||
/** @file
|
||||
* @brief ICMP related functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/* Use highest log level if both IPv4 and IPv6 are defined */
|
||||
#if defined(CONFIG_NET_IPV4) && defined(CONFIG_NET_IPV6)
|
||||
|
||||
#if CONFIG_NET_ICMPV4_LOG_LEVEL > CONFIG_NET_ICMPV6_LOG_LEVEL
|
||||
#define ICMP_LOG_LEVEL CONFIG_NET_ICMPV4_LOG_LEVEL
|
||||
#else
|
||||
#define ICMP_LOG_LEVEL CONFIG_NET_ICMPV6_LOG_LEVEL
|
||||
#endif
|
||||
|
||||
#elif defined(CONFIG_NET_IPV4)
|
||||
#define ICMP_LOG_LEVEL CONFIG_NET_ICMPV4_LOG_LEVEL
|
||||
#elif defined(CONFIG_NET_IPV6)
|
||||
#define ICMP_LOG_LEVEL CONFIG_NET_ICMPV6_LOG_LEVEL
|
||||
#else
|
||||
#define ICMP_LOG_LEVEL LOG_LEVEL_INF
|
||||
#endif
|
||||
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(net_icmp, ICMP_LOG_LEVEL);
|
||||
|
||||
#include <errno.h>
|
||||
#include <zephyr/random/rand32.h>
|
||||
#include <zephyr/sys/slist.h>
|
||||
#include <zephyr/net/net_pkt.h>
|
||||
#include <zephyr/net/icmp.h>
|
||||
|
||||
#include "net_private.h"
|
||||
#include "icmpv6.h"
|
||||
#include "icmpv4.h"
|
||||
#include "ipv4.h"
|
||||
#include "ipv6.h"
|
||||
#include "net_stats.h"
|
||||
|
||||
static K_MUTEX_DEFINE(lock);
|
||||
static sys_slist_t handlers = SYS_SLIST_STATIC_INIT(&handlers);
|
||||
|
||||
#define PKT_WAIT_TIME K_SECONDS(1)
|
||||
|
||||
int net_icmp_init_ctx(struct net_icmp_ctx *ctx, uint8_t type, uint8_t code,
|
||||
net_icmp_handler_t handler)
|
||||
{
|
||||
if (ctx == NULL || handler == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(ctx, 0, sizeof(struct net_icmp_ctx));
|
||||
|
||||
ctx->handler = handler;
|
||||
ctx->type = type;
|
||||
ctx->code = code;
|
||||
|
||||
k_mutex_lock(&lock, K_FOREVER);
|
||||
|
||||
sys_slist_prepend(&handlers, &ctx->node);
|
||||
|
||||
k_mutex_unlock(&lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_icmp_cleanup_ctx(struct net_icmp_ctx *ctx)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
k_mutex_lock(&lock, K_FOREVER);
|
||||
|
||||
sys_slist_find_and_remove(&handlers, &ctx->node);
|
||||
|
||||
k_mutex_unlock(&lock);
|
||||
|
||||
memset(ctx, 0, sizeof(struct net_icmp_ctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_IPV4)
|
||||
static int send_icmpv4_echo_request(struct net_icmp_ctx *ctx,
|
||||
struct net_if *iface,
|
||||
struct in_addr *dst,
|
||||
struct net_icmp_ping_params *params,
|
||||
void *user_data)
|
||||
{
|
||||
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv4_access,
|
||||
struct net_icmpv4_echo_req);
|
||||
int ret = -ENOBUFS;
|
||||
struct net_icmpv4_echo_req *echo_req;
|
||||
const struct in_addr *src;
|
||||
struct net_pkt *pkt;
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_OFFLOAD) && net_if_is_ip_offloaded(iface)) {
|
||||
/* XXX: fixme so that we can send offloaded messages too */
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!iface->config.ip.ipv4) {
|
||||
return -ENETUNREACH;
|
||||
}
|
||||
|
||||
src = net_if_ipv4_select_src_addr(iface, dst);
|
||||
|
||||
pkt = net_pkt_alloc_with_buffer(iface,
|
||||
sizeof(struct net_icmpv4_echo_req)
|
||||
+ params->data_size,
|
||||
AF_INET, IPPROTO_ICMP,
|
||||
PKT_WAIT_TIME);
|
||||
if (!pkt) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NET_ALLOW_ANY_PRIORITY) &&
|
||||
params->priority >= NET_MAX_PRIORITIES) {
|
||||
NET_ERR("Priority %d is too large, maximum allowed is %d",
|
||||
params->priority, NET_MAX_PRIORITIES - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params->priority < 0) {
|
||||
net_pkt_set_ip_dscp(pkt, net_ipv4_get_dscp(params->tc_tos));
|
||||
net_pkt_set_ip_ecn(pkt, net_ipv4_get_ecn(params->tc_tos));
|
||||
} else {
|
||||
net_pkt_set_priority(pkt, params->priority);
|
||||
}
|
||||
|
||||
if (net_ipv4_create(pkt, src, dst) ||
|
||||
net_icmpv4_create(pkt, NET_ICMPV4_ECHO_REQUEST, 0)) {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
echo_req = (struct net_icmpv4_echo_req *)net_pkt_get_data(
|
||||
pkt, &icmpv4_access);
|
||||
if (!echo_req) {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
echo_req->identifier = htons(params->identifier);
|
||||
echo_req->sequence = htons(params->sequence);
|
||||
|
||||
net_pkt_set_data(pkt, &icmpv4_access);
|
||||
|
||||
if (params->data != NULL && params->data_size > 0) {
|
||||
net_pkt_write(pkt, params->data, params->data_size);
|
||||
} else if (params->data == NULL && params->data_size > 0) {
|
||||
/* Generate payload. */
|
||||
if (params->data_size >= sizeof(uint32_t)) {
|
||||
uint32_t time_stamp = htonl(k_cycle_get_32());
|
||||
|
||||
net_pkt_write(pkt, &time_stamp, sizeof(time_stamp));
|
||||
params->data_size -= sizeof(time_stamp);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < params->data_size; i++) {
|
||||
net_pkt_write_u8(pkt, (uint8_t)i);
|
||||
}
|
||||
} else {
|
||||
/* No payload. */
|
||||
}
|
||||
|
||||
net_pkt_cursor_init(pkt);
|
||||
|
||||
net_ipv4_finalize(pkt, IPPROTO_ICMP);
|
||||
|
||||
NET_DBG("Sending ICMPv4 Echo Request type %d from %s to %s",
|
||||
NET_ICMPV4_ECHO_REQUEST,
|
||||
net_sprint_ipv4_addr(src),
|
||||
net_sprint_ipv4_addr(dst));
|
||||
|
||||
ctx->user_data = user_data;
|
||||
ctx->iface = iface;
|
||||
|
||||
if (net_send_data(pkt) >= 0) {
|
||||
net_stats_update_icmp_sent(iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
net_stats_update_icmp_drop(iface);
|
||||
|
||||
ret = -EIO;
|
||||
|
||||
drop:
|
||||
net_pkt_unref(pkt);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
#else
|
||||
static int send_icmpv4_echo_request(struct net_icmp_ctx *ctx,
|
||||
struct net_if *iface,
|
||||
struct in_addr *dst,
|
||||
struct net_icmp_ping_params *params,
|
||||
void *user_data)
|
||||
{
|
||||
ARG_UNUSED(ctx);
|
||||
ARG_UNUSED(iface);
|
||||
ARG_UNUSED(dst);
|
||||
ARG_UNUSED(params);
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NET_IPV6)
|
||||
static int send_icmpv6_echo_request(struct net_icmp_ctx *ctx,
|
||||
struct net_if *iface,
|
||||
struct in6_addr *dst,
|
||||
struct net_icmp_ping_params *params,
|
||||
void *user_data)
|
||||
{
|
||||
NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(icmpv6_access,
|
||||
struct net_icmpv6_echo_req);
|
||||
int ret = -ENOBUFS;
|
||||
struct net_icmpv6_echo_req *echo_req;
|
||||
const struct in6_addr *src;
|
||||
struct net_pkt *pkt;
|
||||
|
||||
if (!iface->config.ip.ipv6) {
|
||||
return -ENETUNREACH;
|
||||
}
|
||||
|
||||
src = net_if_ipv6_select_src_addr(iface, dst);
|
||||
|
||||
pkt = net_pkt_alloc_with_buffer(iface,
|
||||
sizeof(struct net_icmpv6_echo_req)
|
||||
+ params->data_size,
|
||||
AF_INET6, IPPROTO_ICMPV6,
|
||||
PKT_WAIT_TIME);
|
||||
if (!pkt) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NET_ALLOW_ANY_PRIORITY) &&
|
||||
params->priority >= NET_MAX_PRIORITIES) {
|
||||
NET_ERR("Priority %d is too large, maximum allowed is %d",
|
||||
params->priority, NET_MAX_PRIORITIES - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (params->priority < 0) {
|
||||
net_pkt_set_ip_dscp(pkt, net_ipv6_get_dscp(params->tc_tos));
|
||||
net_pkt_set_ip_ecn(pkt, net_ipv6_get_ecn(params->tc_tos));
|
||||
} else {
|
||||
net_pkt_set_priority(pkt, params->priority);
|
||||
}
|
||||
|
||||
if (net_ipv6_create(pkt, src, dst) ||
|
||||
net_icmpv6_create(pkt, NET_ICMPV6_ECHO_REQUEST, 0)) {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
echo_req = (struct net_icmpv6_echo_req *)net_pkt_get_data(
|
||||
pkt, &icmpv6_access);
|
||||
if (!echo_req) {
|
||||
goto drop;
|
||||
}
|
||||
|
||||
echo_req->identifier = htons(params->identifier);
|
||||
echo_req->sequence = htons(params->sequence);
|
||||
|
||||
net_pkt_set_data(pkt, &icmpv6_access);
|
||||
|
||||
if (params->data != NULL && params->data_size > 0) {
|
||||
net_pkt_write(pkt, params->data, params->data_size);
|
||||
} else if (params->data == NULL && params->data_size > 0) {
|
||||
/* Generate payload. */
|
||||
if (params->data_size >= sizeof(uint32_t)) {
|
||||
uint32_t time_stamp = htonl(k_cycle_get_32());
|
||||
|
||||
net_pkt_write(pkt, &time_stamp, sizeof(time_stamp));
|
||||
params->data_size -= sizeof(time_stamp);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < params->data_size; i++) {
|
||||
net_pkt_write_u8(pkt, (uint8_t)i);
|
||||
}
|
||||
} else {
|
||||
/* No payload. */
|
||||
}
|
||||
|
||||
net_pkt_cursor_init(pkt);
|
||||
net_ipv6_finalize(pkt, IPPROTO_ICMPV6);
|
||||
|
||||
NET_DBG("Sending ICMPv6 Echo Request type %d from %s to %s",
|
||||
NET_ICMPV6_ECHO_REQUEST,
|
||||
net_sprint_ipv6_addr(src),
|
||||
net_sprint_ipv6_addr(dst));
|
||||
|
||||
ctx->user_data = user_data;
|
||||
ctx->iface = iface;
|
||||
|
||||
if (net_send_data(pkt) >= 0) {
|
||||
net_stats_update_icmp_sent(iface);
|
||||
return 0;
|
||||
}
|
||||
|
||||
net_stats_update_icmp_drop(iface);
|
||||
|
||||
ret = -EIO;
|
||||
|
||||
drop:
|
||||
net_pkt_unref(pkt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int send_icmpv6_echo_request(struct net_icmp_ctx *ctx,
|
||||
struct net_if *iface,
|
||||
struct in6_addr *dst,
|
||||
struct net_icmp_ping_params *params,
|
||||
void *user_data)
|
||||
{
|
||||
ARG_UNUSED(ctx);
|
||||
ARG_UNUSED(iface);
|
||||
ARG_UNUSED(dst);
|
||||
ARG_UNUSED(params);
|
||||
|
||||
return -ENOTSUP;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct net_icmp_ping_params *get_default_params(void)
|
||||
{
|
||||
static struct net_icmp_ping_params params = { 0 };
|
||||
|
||||
params.identifier = sys_rand32_get();
|
||||
|
||||
return ¶ms;
|
||||
}
|
||||
|
||||
int net_icmp_send_echo_request(struct net_icmp_ctx *ctx,
|
||||
struct net_if *iface,
|
||||
struct sockaddr *dst,
|
||||
struct net_icmp_ping_params *params,
|
||||
void *user_data)
|
||||
{
|
||||
if (ctx == NULL || dst == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iface == NULL) {
|
||||
if (IS_ENABLED(CONFIG_NET_IPV4) && dst->sa_family == AF_INET) {
|
||||
iface = net_if_ipv4_select_src_iface(&net_sin(dst)->sin_addr);
|
||||
} else if (IS_ENABLED(CONFIG_NET_IPV6) && dst->sa_family == AF_INET6) {
|
||||
iface = net_if_ipv6_select_src_iface(&net_sin6(dst)->sin6_addr);
|
||||
}
|
||||
|
||||
if (iface == NULL) {
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_IPV4) && dst->sa_family == AF_INET) {
|
||||
if (params == NULL) {
|
||||
params = get_default_params();
|
||||
}
|
||||
|
||||
return send_icmpv4_echo_request(ctx, iface, &net_sin(dst)->sin_addr,
|
||||
params, user_data);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_NET_IPV6) && dst->sa_family == AF_INET6) {
|
||||
if (params == NULL) {
|
||||
params = get_default_params();
|
||||
}
|
||||
|
||||
return send_icmpv6_echo_request(ctx, iface, &net_sin6(dst)->sin6_addr,
|
||||
params, user_data);
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int icmp_call_handlers(struct net_pkt *pkt,
|
||||
struct net_icmp_ip_hdr *ip_hdr,
|
||||
struct net_icmp_hdr *icmp_hdr)
|
||||
{
|
||||
struct net_icmp_ctx *ctx;
|
||||
int ret = -ENOENT;
|
||||
|
||||
k_mutex_lock(&lock, K_FOREVER);
|
||||
|
||||
SYS_SLIST_FOR_EACH_CONTAINER(&handlers, ctx, node) {
|
||||
if (ctx->type == icmp_hdr->type &&
|
||||
(ctx->code == icmp_hdr->code || ctx->code == 0U)) {
|
||||
/* Do not use a handler that is expecting data from different
|
||||
* network interface we sent the request.
|
||||
*/
|
||||
if (ctx->iface != NULL && ctx->iface != net_pkt_iface(pkt)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = ctx->handler(ctx, pkt, ip_hdr, icmp_hdr, ctx->user_data);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
k_mutex_unlock(&lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int net_icmp_call_ipv4_handlers(struct net_pkt *pkt,
|
||||
struct net_ipv4_hdr *ipv4_hdr,
|
||||
struct net_icmp_hdr *icmp_hdr)
|
||||
{
|
||||
struct net_icmp_ip_hdr ip_hdr;
|
||||
|
||||
ip_hdr.ipv4 = ipv4_hdr;
|
||||
ip_hdr.family = AF_INET;
|
||||
|
||||
return icmp_call_handlers(pkt, &ip_hdr, icmp_hdr);
|
||||
}
|
||||
|
||||
int net_icmp_call_ipv6_handlers(struct net_pkt *pkt,
|
||||
struct net_ipv6_hdr *ipv6_hdr,
|
||||
struct net_icmp_hdr *icmp_hdr)
|
||||
{
|
||||
struct net_icmp_ip_hdr ip_hdr;
|
||||
|
||||
ip_hdr.ipv6 = ipv6_hdr;
|
||||
ip_hdr.family = AF_INET6;
|
||||
|
||||
return icmp_call_handlers(pkt, &ip_hdr, icmp_hdr);
|
||||
}
|
|
@ -19,8 +19,6 @@
|
|||
#include <zephyr/net/net_pkt.h>
|
||||
|
||||
#define NET_ICMPV4_DST_UNREACH 3 /* Destination unreachable */
|
||||
#define NET_ICMPV4_ECHO_REQUEST 8
|
||||
#define NET_ICMPV4_ECHO_REPLY 0
|
||||
#define NET_ICMPV4_TIME_EXCEEDED 11 /* Time exceeded */
|
||||
#define NET_ICMPV4_BAD_IP_HEADER 12 /* Bad IP header */
|
||||
|
||||
|
|
|
@ -144,8 +144,6 @@ struct net_icmpv6_mld_mcast_record {
|
|||
#define NET_ICMPV6_PACKET_TOO_BIG 2 /* Packet too big */
|
||||
#define NET_ICMPV6_TIME_EXCEEDED 3 /* Time exceeded */
|
||||
#define NET_ICMPV6_PARAM_PROBLEM 4 /* IPv6 header is bad */
|
||||
#define NET_ICMPV6_ECHO_REQUEST 128
|
||||
#define NET_ICMPV6_ECHO_REPLY 129
|
||||
#define NET_ICMPV6_MLD_QUERY 130 /* Multicast Listener Query */
|
||||
#define NET_ICMPV6_RS 133 /* Router Solicitation */
|
||||
#define NET_ICMPV6_RA 134 /* Router Advertisement */
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/net/net_context.h>
|
||||
#include <zephyr/net/net_pkt.h>
|
||||
#include <zephyr/net/icmp.h>
|
||||
|
||||
#ifdef CONFIG_NET_MGMT_EVENT_INFO
|
||||
|
||||
|
@ -58,6 +59,13 @@ extern void net_if_stats_reset_all(void);
|
|||
extern void net_process_rx_packet(struct net_pkt *pkt);
|
||||
extern void net_process_tx_packet(struct net_pkt *pkt);
|
||||
|
||||
extern int net_icmp_call_ipv4_handlers(struct net_pkt *pkt,
|
||||
struct net_ipv4_hdr *ipv4_hdr,
|
||||
struct net_icmp_hdr *icmp_hdr);
|
||||
extern int net_icmp_call_ipv6_handlers(struct net_pkt *pkt,
|
||||
struct net_ipv6_hdr *ipv6_hdr,
|
||||
struct net_icmp_hdr *icmp_hdr);
|
||||
|
||||
#if defined(CONFIG_NET_NATIVE) || defined(CONFIG_NET_OFFLOAD)
|
||||
extern void net_context_init(void);
|
||||
extern const char *net_context_state(struct net_context *context);
|
||||
|
|
Loading…
Reference in a new issue