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)

Reply via email to