This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new 859fc54c9 netutils/ping: change socket type to SOCK_RAW
859fc54c9 is described below
commit 859fc54c967d26dbfa72bcd80a7cd811e650b970
Author: daichuan <[email protected]>
AuthorDate: Fri Mar 28 10:16:53 2025 +0800
netutils/ping: change socket type to SOCK_RAW
The ping socket creation method is changed from SOCK_DGRAM to SOCK_RAW,
because SOCK_DGRAM may not have permission in some environments (e.g.
Docker).
Also add checksum calculation when send, and perform IP header processing
when receive.
Signed-off-by: daichuan <[email protected]>
---
netutils/ping/icmp_ping.c | 67 +++++++++++++++++++++++++++++++++++------------
1 file changed, 50 insertions(+), 17 deletions(-)
diff --git a/netutils/ping/icmp_ping.c b/netutils/ping/icmp_ping.c
index 55db84854..aa88d0a18 100644
--- a/netutils/ping/icmp_ping.c
+++ b/netutils/ping/icmp_ping.c
@@ -45,6 +45,7 @@
#include <nuttx/clock.h>
#include <nuttx/net/icmp.h>
+#include <nuttx/net/ip.h>
#include "netutils/icmp_ping.h"
@@ -64,7 +65,6 @@ struct ping_priv_s
{
struct sockaddr_in destaddr;
struct sockaddr_in fromaddr;
- struct icmp_hdr_s outhdr;
struct pollfd recvfd;
socklen_t addrlen;
clock_t kickoff;
@@ -74,6 +74,7 @@ struct ping_priv_s
long elapsed;
bool retry;
int sockfd;
+ struct icmp_hdr_s outhdr;
};
/****************************************************************************
@@ -181,6 +182,31 @@ static void icmp_callback(FAR struct ping_result_s *result,
result->info->callback(result);
}
+/****************************************************************************
+ * Name: icmp_checksum
+ ****************************************************************************/
+
+static uint16_t icmp_checksum(FAR const void *buffer, size_t datalen)
+{
+ FAR const uint16_t *wptr = (FAR const uint16_t *)buffer;
+ size_t words = (sizeof(struct icmp_hdr_s) + datalen + 1) / 2;
+ uint32_t sum = 0;
+ size_t i;
+
+ for (i = 0; i < words; i++)
+ {
+ sum += *wptr++;
+ if (sum & 0x80000000)
+ {
+ sum = (sum & 0XFFFF) + (sum >> 16);
+ }
+ }
+
+ sum = (sum >> 16) + (sum & 0XFFFF);
+ sum += (sum >> 16);
+ return (uint16_t)(~sum);
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -196,6 +222,7 @@ void icmp_ping(FAR const struct ping_info_s *info)
FAR struct icmp_hdr_s *inhdr;
FAR uint8_t *iobuffer;
FAR uint8_t *ptr;
+ int recvlen;
int ret;
int ch;
int i;
@@ -219,16 +246,17 @@ void icmp_ping(FAR const struct ping_info_s *info)
/* Allocate memory to hold private data and ping buffer */
- priv = malloc(sizeof(*priv) + result.outsize);
+ priv = malloc(sizeof(*priv) + sizeof(struct ipv4_hdr_s) + result.outsize);
+
if (priv == NULL)
{
icmp_callback(&result, ICMP_E_MEMORY, 0);
return;
}
- iobuffer = (FAR uint8_t *)(priv + 1);
+ iobuffer = (FAR uint8_t *)(&priv->outhdr);
- priv->sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ priv->sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (priv->sockfd < 0)
{
icmp_callback(&result, ICMP_E_SOCKET, errno);
@@ -257,11 +285,6 @@ void icmp_ping(FAR const struct ping_info_s *info)
priv->destaddr.sin_port = 0;
priv->destaddr.sin_addr.s_addr = result.dest.s_addr;
- memset(&priv->outhdr, 0, sizeof(struct icmp_hdr_s));
- priv->outhdr.type = ICMP_ECHO_REQUEST;
- priv->outhdr.id = htons(result.id);
- priv->outhdr.seqno = htons(result.seqno);
-
icmp_callback(&result, ICMP_I_BEGIN, 0);
while (result.nrequests < info->count)
@@ -271,9 +294,10 @@ void icmp_ping(FAR const struct ping_info_s *info)
break;
}
- /* Copy the ICMP header into the I/O buffer */
-
- memcpy(iobuffer, &priv->outhdr, sizeof(struct icmp_hdr_s));
+ memset(&priv->outhdr, 0, sizeof(struct icmp_hdr_s));
+ priv->outhdr.type = ICMP_ECHO_REQUEST;
+ priv->outhdr.id = htons(result.id);
+ priv->outhdr.seqno = htons(result.seqno);
/* Add some easily verifiable payload data */
@@ -289,6 +313,10 @@ void icmp_ping(FAR const struct ping_info_s *info)
}
}
+ /* Calculate checksum after data padding */
+
+ priv->outhdr.icmpchksum = icmp_checksum(iobuffer, info->datalen);
+
priv->start = clock();
result.nrequests++;
priv->nsent = sendto(priv->sockfd, iobuffer, result.outsize, 0,
@@ -334,9 +362,10 @@ void icmp_ping(FAR const struct ping_info_s *info)
/* Get the ICMP response (ignoring the sender) */
+ recvlen = sizeof(struct ipv4_hdr_s) + result.outsize;
priv->addrlen = sizeof(struct sockaddr_in);
priv->nrecvd = recvfrom(priv->sockfd, iobuffer,
- result.outsize, 0,
+ recvlen, 0,
(FAR struct sockaddr *)&priv->fromaddr,
&priv->addrlen);
if (priv->nrecvd < 0)
@@ -350,8 +379,11 @@ void icmp_ping(FAR const struct ping_info_s *info)
goto wait;
}
+ /* Skip IP header, IP header length including options */
+
priv->elapsed = TICK2USEC(clock() - priv->start);
- inhdr = (FAR struct icmp_hdr_s *)iobuffer;
+ inhdr = (FAR struct icmp_hdr_s *)
+ (iobuffer + sizeof(struct ipv4_hdr_s));
if (inhdr->type == ICMP_ECHO_REPLY)
{
@@ -383,16 +415,17 @@ void icmp_ping(FAR const struct ping_info_s *info)
/* Verify the payload data */
- if (priv->nrecvd != result.outsize)
+ if (priv->nrecvd != recvlen)
{
icmp_callback(&result, ICMP_W_RECVBIG, priv->nrecvd);
verified = false;
}
else
{
- ptr = &iobuffer[sizeof(struct icmp_hdr_s)];
- ch = 0x20;
+ /* Data start offset: IP header + ICMP header */
+ ptr = (FAR uint8_t *)(inhdr + 1);
+ ch = 0x20;
for (i = 0; i < info->datalen; i++, ptr++)
{
if (*ptr != ch)