mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
gnrc_icmpv6_echo: implement gnrc_icmpv6_echo_{send, req_handle}()
This commit is contained in:
parent
7c0dd96a1c
commit
f6c1ab35a3
@ -24,7 +24,9 @@
|
||||
|
||||
#include "byteorder.h"
|
||||
#include "net/gnrc/netif.h"
|
||||
#include "net/gnrc/netif/hdr.h"
|
||||
#include "net/ipv6/hdr.h"
|
||||
#include "net/icmpv6.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -58,6 +60,49 @@ gnrc_pktsnip_t *gnrc_icmpv6_echo_build(uint8_t type, uint16_t id, uint16_t seq,
|
||||
void gnrc_icmpv6_echo_req_handle(gnrc_netif_t *netif, ipv6_hdr_t *ipv6_hdr,
|
||||
icmpv6_echo_t *echo, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief Send out ICMPv6 echo request
|
||||
*
|
||||
* @param[in] netif The interface the echo request should be sent on.
|
||||
* @param[in] addr The destination address of the echo request
|
||||
* @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] ttl Hop limit of the echo request
|
||||
* @param[in] len Length of the payload
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int gnrc_icmpv6_echo_send(const gnrc_netif_t *netif, const ipv6_addr_t *addr,
|
||||
uint16_t id, uint16_t seq, uint8_t ttl, size_t len);
|
||||
|
||||
/**
|
||||
* @brief ICMPv6 echo response callback
|
||||
*
|
||||
* @param[in] pkt Packet containing the ICMPv6 response
|
||||
* @param[in] corrupt Offset of corrupt payload, -1 if no corruption detected
|
||||
* @param[in] rtt_us round-trip-time in µs (0 if this information is not available)
|
||||
* @param[in] ctx User supplied context
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
typedef int (*gnrc_icmpv6_echo_rsp_handle_cb_t)(gnrc_pktsnip_t *pkt,
|
||||
int corrupt, uint32_t rtt_us, void *ctx);
|
||||
/**
|
||||
* @brief Parse ICMPv6 echo response
|
||||
*
|
||||
* @param[in] pkt Incoming ICMPv6 packet
|
||||
* @param[in] len Expected echo response payload length
|
||||
* @param[in] cb Callback function to execute
|
||||
* @param[in] ctx Callback function context
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 on error
|
||||
*/
|
||||
int gnrc_icmpv6_echo_rsp_handle(gnrc_pktsnip_t *pkt, size_t len,
|
||||
gnrc_icmpv6_echo_rsp_handle_cb_t cb, void *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -35,7 +35,7 @@ gnrc_pktsnip_t *gnrc_icmpv6_echo_build(uint8_t type, uint16_t id, uint16_t seq,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG("icmpv6_echo: Building echo message with type=%" PRIu8 "id=%" PRIu16
|
||||
DEBUG("icmpv6_echo: Building echo message with type=%" PRIu8 " id=%" PRIu16
|
||||
", seq=%" PRIu16, type, id, seq);
|
||||
echo = (icmpv6_echo_t *)pkt->data;
|
||||
echo->id = byteorder_htons(id);
|
||||
@ -107,4 +107,121 @@ void gnrc_icmpv6_echo_req_handle(gnrc_netif_t *netif, ipv6_hdr_t *ipv6_hdr,
|
||||
}
|
||||
}
|
||||
|
||||
static void _fill_payload(uint8_t *buf, size_t len, uint32_t now)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
|
||||
if (len >= sizeof(uint32_t)) {
|
||||
memcpy(buf, &now, sizeof(now));
|
||||
len -= sizeof(now);
|
||||
buf += sizeof(now);
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
*buf++ = i++;
|
||||
}
|
||||
}
|
||||
|
||||
static void _check_payload(const void *buf, size_t len, uint32_t now,
|
||||
uint32_t *triptime, int *corrupt)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
const uint8_t *data = buf;
|
||||
|
||||
if (len >= sizeof(uint32_t)) {
|
||||
*triptime = now - unaligned_get_u32(buf);
|
||||
len -= sizeof(uint32_t);
|
||||
data += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
while (len--) {
|
||||
if (*data++ != i++) {
|
||||
*corrupt = data - (uint8_t *)buf - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int gnrc_icmpv6_echo_send(const gnrc_netif_t *netif, const ipv6_addr_t *addr,
|
||||
uint16_t id, uint16_t seq, uint8_t ttl, size_t len)
|
||||
{
|
||||
int res = 0;
|
||||
gnrc_pktsnip_t *pkt, *tmp;
|
||||
ipv6_hdr_t *ipv6;
|
||||
uint8_t *databuf;
|
||||
|
||||
pkt = gnrc_icmpv6_echo_build(ICMPV6_ECHO_REQ, id, seq, NULL, len);
|
||||
if (pkt == NULL) {
|
||||
DEBUG("error: packet buffer full\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
databuf = (uint8_t *)(pkt->data) + sizeof(icmpv6_echo_t);
|
||||
tmp = gnrc_ipv6_hdr_build(pkt, NULL, addr);
|
||||
if (tmp == NULL) {
|
||||
puts("error: packet buffer full");
|
||||
goto error_exit;
|
||||
}
|
||||
pkt = tmp;
|
||||
ipv6 = pkt->data;
|
||||
/* if ttl is unset (i.e. 0) gnrc_ipv6 will select hop limit */
|
||||
ipv6->hl = ttl;
|
||||
if (netif != NULL) {
|
||||
tmp = gnrc_netif_hdr_build(NULL, 0, NULL, 0);
|
||||
if (tmp == NULL) {
|
||||
DEBUG("error: packet buffer full");
|
||||
res = -ENOMEM;
|
||||
goto error_exit;
|
||||
}
|
||||
gnrc_netif_hdr_set_netif(tmp->data, netif);
|
||||
pkt = gnrc_pkt_prepend(pkt, tmp);
|
||||
}
|
||||
|
||||
/* add TX timestamp & test data */
|
||||
_fill_payload(databuf, len, ztimer_now(ZTIMER_USEC));
|
||||
|
||||
res = !gnrc_netapi_dispatch_send(GNRC_NETTYPE_IPV6,
|
||||
GNRC_NETREG_DEMUX_CTX_ALL,
|
||||
pkt);
|
||||
if (res) {
|
||||
DEBUG("error: unable to send ICMPv6 echo request\n");
|
||||
res = -EBADF;
|
||||
}
|
||||
|
||||
error_exit:
|
||||
if (res) {
|
||||
gnrc_pktbuf_release(pkt);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int gnrc_icmpv6_echo_rsp_handle(gnrc_pktsnip_t *pkt, size_t len,
|
||||
gnrc_icmpv6_echo_rsp_handle_cb_t cb, void *ctx)
|
||||
{
|
||||
gnrc_pktsnip_t *ipv6, *icmpv6;
|
||||
ipv6_hdr_t *ipv6_hdr;
|
||||
uint32_t now = ztimer_now(ZTIMER_USEC);
|
||||
uint32_t triptime = 0;
|
||||
int corrupted = -1;
|
||||
|
||||
ipv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_IPV6);
|
||||
icmpv6 = gnrc_pktsnip_search_type(pkt, GNRC_NETTYPE_ICMPV6);
|
||||
if ((ipv6 == NULL) || (icmpv6 == NULL)) {
|
||||
DEBUG("No IPv6 or ICMPv6 header found in reply");
|
||||
return -EINVAL;
|
||||
}
|
||||
ipv6_hdr = ipv6->data;
|
||||
#ifdef MODULE_GNRC_IPV6_NIB
|
||||
/* successful ping to neighbor (NIB handles case if ipv6->src is not a
|
||||
* neighbor) can be taken as upper-layer hint for reachability:
|
||||
* https://tools.ietf.org/html/rfc4861#section-7.3.1 */
|
||||
gnrc_ipv6_nib_nc_mark_reachable(&ipv6_hdr->src);
|
||||
#endif
|
||||
|
||||
icmpv6_echo_t *icmpv6_hdr = icmpv6->data;
|
||||
_check_payload(icmpv6_hdr + 1, len, now, &triptime, &corrupted);
|
||||
|
||||
return cb(pkt, corrupted, triptime, ctx);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
Loading…
Reference in New Issue
Block a user