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

commit 5d3b2d07d61be260b7cbc7dc26d407c591ba4613
Author: meijian <[email protected]>
AuthorDate: Fri Mar 14 17:23:30 2025 +0800

    ping: add -I for bind device
    
    Add -I option to specify the network device to use for sending ICMP
    echo requests. This allows users to explicitly bind ping to a
    specific network interface, which is particularly useful in
    multi-homed systems with multiple network interfaces.
    
    Signed-off-by: meijian <[email protected]>
---
 include/netutils/icmp_ping.h   |  4 ++++
 include/netutils/icmpv6_ping.h |  4 ++++
 netutils/ping/icmp_ping.c      | 14 ++++++++++++++
 netutils/ping/icmpv6_ping.c    | 14 ++++++++++++++
 system/ping/ping.c             | 17 ++++++++++++++++-
 system/ping6/ping6.c           | 17 ++++++++++++++++-
 6 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/include/netutils/icmp_ping.h b/include/netutils/icmp_ping.h
index eec500de9..3f8d6c29d 100644
--- a/include/netutils/icmp_ping.h
+++ b/include/netutils/icmp_ping.h
@@ -50,6 +50,7 @@
 #define ICMP_E_POLL        -11 /* extra: error code    */
 #define ICMP_E_RECVFROM    -13 /* extra: error code    */
 #define ICMP_E_RECVSMALL   -15 /* extra: recv bytes    */
+#define ICMP_E_BINDDEV     -17 /* extra: error bind    */
 
 /* Negative even number represent warning(recoverable) */
 
@@ -70,6 +71,9 @@ struct ping_result_s;
 struct ping_info_s
 {
   FAR const char *hostname; /* Host name to ping */
+#ifdef CONFIG_NET_BINDTODEVICE
+  FAR const char *devname;  /* Device name to bind */
+#endif
   uint16_t count;           /* Number of pings requested */
   uint16_t datalen;         /* Number of bytes to be sent */
   uint16_t delay;           /* Deciseconds to delay between pings */
diff --git a/include/netutils/icmpv6_ping.h b/include/netutils/icmpv6_ping.h
index 3f793f741..33db0fc6f 100644
--- a/include/netutils/icmpv6_ping.h
+++ b/include/netutils/icmpv6_ping.h
@@ -50,6 +50,7 @@
 #define ICMPv6_E_POLL        -11 /* extra: error code    */
 #define ICMPv6_E_RECVFROM    -13 /* extra: error code    */
 #define ICMPv6_E_RECVSMALL   -15 /* extra: recv bytes    */
+#define ICMPV6_E_BINDDEV     -17 /* extra: error bind    */
 
 /* Negative even number represent warning(recoverable) */
 
@@ -70,6 +71,9 @@ struct ping6_result_s;
 struct ping6_info_s
 {
   FAR const char *hostname; /* Host name to ping */
+#ifdef CONFIG_NET_BINDTODEVICE
+  FAR const char *devname;  /* Device name to bind */
+#endif
   uint16_t count;           /* Number of pings requested */
   uint16_t datalen;         /* Number of bytes to be sent */
   uint16_t delay;           /* Deciseconds to delay between pings */
diff --git a/netutils/ping/icmp_ping.c b/netutils/ping/icmp_ping.c
index efbc8a61a..7aa1d3973 100644
--- a/netutils/ping/icmp_ping.c
+++ b/netutils/ping/icmp_ping.c
@@ -232,6 +232,20 @@ void icmp_ping(FAR const struct ping_info_s *info)
       return;
     }
 
+#ifdef CONFIG_NET_BINDTODEVICE
+  if (info->devname)
+    {
+      ret = setsockopt(priv->sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+                       info->devname, strlen(info->devname));
+      if (ret < 0)
+        {
+          icmp_callback(&result, ICMP_E_BINDDEV, errno);
+          free(priv);
+          return;
+        }
+    }
+#endif
+
   priv->kickoff = clock();
 
   memset(&priv->destaddr, 0, sizeof(struct sockaddr_in));
diff --git a/netutils/ping/icmpv6_ping.c b/netutils/ping/icmpv6_ping.c
index 74cd59ee9..e6a93fc98 100644
--- a/netutils/ping/icmpv6_ping.c
+++ b/netutils/ping/icmpv6_ping.c
@@ -218,6 +218,20 @@ void icmp6_ping(FAR const struct ping6_info_s *info)
       return;
     }
 
+#ifdef CONFIG_NET_BINDTODEVICE
+  if (info->devname)
+    {
+      ret = setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+                       info->devname, strlen(info->devname));
+      if (ret < 0)
+        {
+          icmp6_callback(&result, ICMPV6_E_BINDDEV, errno);
+          free(iobuffer);
+          return;
+        }
+    }
+#endif
+
   kickoff = clock();
 
   memset(&destaddr, 0, sizeof(struct sockaddr_in6));
diff --git a/system/ping/ping.c b/system/ping/ping.c
index 804522112..1abee622a 100644
--- a/system/ping/ping.c
+++ b/system/ping/ping.c
@@ -100,6 +100,7 @@ static void show_usage(FAR const char *progname, int 
exitcode)
   printf("  -s <size> specifies the number of data bytes to be sent.  "
          "Default %u.\n",
          ICMP_PING_DATALEN);
+  printf("  -I <interface> is the bind device for traffic\n");
   printf("  -h shows this text and exits.\n");
   exit(exitcode);
 }
@@ -172,6 +173,12 @@ static void ping_result(FAR const struct ping_result_s 
*result)
         fprintf(stderr, "ERROR: short ICMP packet: %ld\n", result->extra);
         break;
 
+#ifdef CONFIG_NET_BINDTODEVICE
+      case ICMP_E_BINDDEV:
+        fprintf(stderr, "ERROR: setsockopt error: %ld\n", result->extra);
+        break;
+#endif
+
       case ICMP_W_IDDIFF:
         fprintf(stderr,
                 "WARNING: Ignoring ICMP reply with ID %ld.  "
@@ -300,7 +307,7 @@ int main(int argc, FAR char *argv[])
 
   exitcode = EXIT_FAILURE;
 
-  while ((option = getopt(argc, argv, ":c:i:W:s:h")) != ERROR)
+  while ((option = getopt(argc, argv, ":c:i:W:s:I:h")) != ERROR)
     {
       switch (option)
         {
@@ -360,6 +367,14 @@ int main(int argc, FAR char *argv[])
             }
             break;
 
+          case 'I':
+#ifdef CONFIG_NET_BINDTODEVICE
+            info.devname = optarg;
+#else
+            fprintf(stderr, "ERROR: Bind to device not supported\n");
+#endif
+            break;
+
           case 'h':
             exitcode = EXIT_SUCCESS;
             goto errout_with_usage;
diff --git a/system/ping6/ping6.c b/system/ping6/ping6.c
index 5d18637b8..409f3db0e 100644
--- a/system/ping6/ping6.c
+++ b/system/ping6/ping6.c
@@ -100,6 +100,7 @@ static void show_usage(FAR const char *progname, int 
exitcode)
   printf("  -s <size> specifies the number of data bytes to be sent. "
          " Default %u.\n",
          ICMPv6_PING6_DATALEN);
+  printf("  -I <interface> is the bind device for traffic\n");
   printf("  -h shows this text and exits.\n");
   exit(exitcode);
 }
@@ -176,6 +177,12 @@ static void ping6_result(FAR const struct ping6_result_s 
*result)
                 result->extra, result->id);
         break;
 
+#ifdef CONFIG_NET_BINDTODEVICE
+      case ICMPV6_E_BINDDEV:
+        fprintf(stderr, "ERROR: setsockopt error: %ld\n", result->extra);
+        break;
+#endif
+
       case ICMPv6_W_SEQNOBIG:
         fprintf(stderr,
                 "WARNING: Ignoring ICMP reply to sequence %ld.  "
@@ -295,7 +302,7 @@ int main(int argc, FAR char *argv[])
 
   exitcode = EXIT_FAILURE;
 
-  while ((option = getopt(argc, argv, ":c:i:W:s:h")) != ERROR)
+  while ((option = getopt(argc, argv, ":c:i:W:s:I:h")) != ERROR)
     {
       switch (option)
         {
@@ -355,6 +362,14 @@ int main(int argc, FAR char *argv[])
             }
             break;
 
+            case 'I':
+#ifdef CONFIG_NET_BINDTODEVICE
+            info.devname = optarg;
+#else
+            fprintf(stderr, "ERROR: Bind to device not supported\n");
+#endif
+            break;
+
           case 'h':
             exitcode = EXIT_SUCCESS;
             goto errout_with_usage;

Reply via email to