diff mbox series

[11/17] net: ping6: Add ping6 command

Message ID 20220830123104.256224-12-v.v.mitrofanov@yadro.com
State Superseded
Delegated to: Ramon Fried
Headers show
Series IPv6 support | expand

Commit Message

Vyacheslav V. Mitrofanov Aug. 30, 2022, 12:30 p.m. UTC
Implement ping6 command to ping hosts using IPv6. It works the same way as
an ordinary ping command. There is no ICMP request so it is not possible
to ping our host. This patch adds options in Kconfig and Makefile to
build ping6 command.

Signed-off-by: Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com>
---
 cmd/Kconfig    |   7 +++
 cmd/net.c      |  26 +++++++++++
 include/net.h  |   4 +-
 include/net6.h |  17 +++++++
 net/Makefile   |   1 +
 net/net.c      |  13 ++++++
 net/net6.c     |   4 ++
 net/ping6.c    | 117 +++++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 187 insertions(+), 2 deletions(-)
 create mode 100644 net/ping6.c

Comments

Simon Glass Sept. 1, 2022, 2:27 a.m. UTC | #1
On Tue, 30 Aug 2022 at 07:02, Viacheslav Mitrofanov
<v.v.mitrofanov@yadro.com> wrote:
>
> Implement ping6 command to ping hosts using IPv6. It works the same way as
> an ordinary ping command. There is no ICMP request so it is not possible
> to ping our host. This patch adds options in Kconfig and Makefile to
> build ping6 command.
>
> Signed-off-by: Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com>
> ---
>  cmd/Kconfig    |   7 +++
>  cmd/net.c      |  26 +++++++++++
>  include/net.h  |   4 +-
>  include/net6.h |  17 +++++++
>  net/Makefile   |   1 +
>  net/net.c      |  13 ++++++
>  net/net6.c     |   4 ++
>  net/ping6.c    | 117 +++++++++++++++++++++++++++++++++++++++++++++++++
>  8 files changed, 187 insertions(+), 2 deletions(-)
>  create mode 100644 net/ping6.c
>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 8ea064b8d2..4c95c6fd9b 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -1801,6 +1801,13 @@ config CMD_PING
>         help
>           Send ICMP ECHO_REQUEST to network host
>
> +config CMD_PING6
> +       bool "ping6"
> +       depends on IPV6
> +       default y if (CMD_PING && IPV6)
> +       help
> +         Send ICMPv6 ECHO_REQUEST to network host
> +
>  config CMD_CDP
>         bool "cdp"
>         help
> diff --git a/cmd/net.c b/cmd/net.c
> index 0225f9ce3e..cd24813bcd 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -334,6 +334,32 @@ U_BOOT_CMD(
>  );
>  #endif
>
> +#if IS_ENABLED(CONFIG_CMD_PING6)
> +int do_ping6(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
> +{
> +       if (string_to_ip6(argv[1], &net_ping_ip6) != 0)
> +               return CMD_RET_USAGE;
> +
> +       use_ip6 = true;
> +       if (net_loop(PING6) < 0) {
> +               use_ip6 = false;
> +               printf("ping6 failed; host %pI6c is not alive\n",
> +                      &net_ping_ip6);
> +               return 1;
> +       }
> +
> +       use_ip6 = false;
> +       printf("host %pI6c is alive\n", &net_ping_ip6);
> +       return 0;
> +}
> +
> +U_BOOT_CMD(
> +       ping6,  2,      1,      do_ping6,
> +       "send ICMPv6 ECHO_REQUEST to network host",
> +       "pingAddress"
> +);
> +#endif /* CONFIG_CMD_PING6 */
> +
>  #if defined(CONFIG_CMD_CDP)
>
>  static void cdp_update_env(void)
> diff --git a/include/net.h b/include/net.h
> index c06b577808..72d32d358a 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -559,8 +559,8 @@ extern ushort               net_native_vlan;        /* Our Native VLAN */
>  extern int             net_restart_wrap;       /* Tried all network devices */
>
>  enum proto_t {
> -       BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
> -       TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP
> +       BOOTP, RARP, ARP, TFTPGET, DHCP, PING, PING6, DNS, NFS, CDP, NETCONS,
> +       SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP
>  };
>
>  extern char    net_boot_file_name[1024];/* Boot File name */
> diff --git a/include/net6.h b/include/net6.h
> index a7be2496d9..08d31b8197 100644
> --- a/include/net6.h
> +++ b/include/net6.h
> @@ -175,6 +175,7 @@ extern struct in6_addr net_ip6;     /* Our IPv6 addr (0 = unknown) */
>  extern struct in6_addr net_link_local_ip6;     /* Our link local IPv6 addr */
>  extern u32 net_prefix_length;  /* Our prefixlength (0 = unknown) */
>  extern struct in6_addr net_server_ip6; /* Server IPv6 addr (0 = unknown) */
> +extern struct in6_addr net_ping_ip6; /* the ipv6 address to ping */
>  extern bool use_ip6;
>
>  #if IS_ENABLED(CONFIG_IPV6)
> @@ -292,4 +293,20 @@ static inline void net_copy_ip6(void *to, const void *from)
>  }
>  #endif
>
> +#if IS_ENABLED(CONFIG_CMD_PING6)
> +/* starts a Ping6 process */
> +void ping6_start(void);
> +/* handles reception of icmpv6 echo request/reply */
> +void ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len);

Proper comments again. Also It seems that this one can fail?

> +#else
> +static inline void ping6_start(void)
> +{
> +}
> +
> +static inline
> +void ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
> +{
> +}
> +#endif /* CONFIG_CMD_PING6 */
> +

[..]

Regards,
Simon
diff mbox series

Patch

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 8ea064b8d2..4c95c6fd9b 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1801,6 +1801,13 @@  config CMD_PING
 	help
 	  Send ICMP ECHO_REQUEST to network host
 
+config CMD_PING6
+	bool "ping6"
+	depends on IPV6
+	default y if (CMD_PING && IPV6)
+	help
+	  Send ICMPv6 ECHO_REQUEST to network host
+
 config CMD_CDP
 	bool "cdp"
 	help
diff --git a/cmd/net.c b/cmd/net.c
index 0225f9ce3e..cd24813bcd 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -334,6 +334,32 @@  U_BOOT_CMD(
 );
 #endif
 
+#if IS_ENABLED(CONFIG_CMD_PING6)
+int do_ping6(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
+{
+	if (string_to_ip6(argv[1], &net_ping_ip6) != 0)
+		return CMD_RET_USAGE;
+
+	use_ip6 = true;
+	if (net_loop(PING6) < 0) {
+		use_ip6 = false;
+		printf("ping6 failed; host %pI6c is not alive\n",
+		       &net_ping_ip6);
+		return 1;
+	}
+
+	use_ip6 = false;
+	printf("host %pI6c is alive\n", &net_ping_ip6);
+	return 0;
+}
+
+U_BOOT_CMD(
+	ping6,  2,      1,      do_ping6,
+	"send ICMPv6 ECHO_REQUEST to network host",
+	"pingAddress"
+);
+#endif /* CONFIG_CMD_PING6 */
+
 #if defined(CONFIG_CMD_CDP)
 
 static void cdp_update_env(void)
diff --git a/include/net.h b/include/net.h
index c06b577808..72d32d358a 100644
--- a/include/net.h
+++ b/include/net.h
@@ -559,8 +559,8 @@  extern ushort		net_native_vlan;	/* Our Native VLAN */
 extern int		net_restart_wrap;	/* Tried all network devices */
 
 enum proto_t {
-	BOOTP, RARP, ARP, TFTPGET, DHCP, PING, DNS, NFS, CDP, NETCONS, SNTP,
-	TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP
+	BOOTP, RARP, ARP, TFTPGET, DHCP, PING, PING6, DNS, NFS, CDP, NETCONS,
+	SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP
 };
 
 extern char	net_boot_file_name[1024];/* Boot File name */
diff --git a/include/net6.h b/include/net6.h
index a7be2496d9..08d31b8197 100644
--- a/include/net6.h
+++ b/include/net6.h
@@ -175,6 +175,7 @@  extern struct in6_addr net_ip6;	/* Our IPv6 addr (0 = unknown) */
 extern struct in6_addr net_link_local_ip6;	/* Our link local IPv6 addr */
 extern u32 net_prefix_length;	/* Our prefixlength (0 = unknown) */
 extern struct in6_addr net_server_ip6;	/* Server IPv6 addr (0 = unknown) */
+extern struct in6_addr net_ping_ip6; /* the ipv6 address to ping */
 extern bool use_ip6;
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -292,4 +293,20 @@  static inline void net_copy_ip6(void *to, const void *from)
 }
 #endif
 
+#if IS_ENABLED(CONFIG_CMD_PING6)
+/* starts a Ping6 process */
+void ping6_start(void);
+/* handles reception of icmpv6 echo request/reply */
+void ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len);
+#else
+static inline void ping6_start(void)
+{
+}
+
+static inline
+void ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
+{
+}
+#endif /* CONFIG_CMD_PING6 */
+
 #endif /* __NET6_H__ */
diff --git a/net/Makefile b/net/Makefile
index 766dd04135..e32e913d68 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -25,6 +25,7 @@  obj-$(CONFIG_NET)      += net.o
 obj-$(CONFIG_IPV6)     += net6.o
 obj-$(CONFIG_CMD_NFS)  += nfs.o
 obj-$(CONFIG_CMD_PING) += ping.o
+obj-$(CONFIG_CMD_PING6) += ping6.o
 obj-$(CONFIG_CMD_PCAP) += pcap.o
 obj-$(CONFIG_CMD_RARP) += rarp.o
 obj-$(CONFIG_CMD_SNTP) += sntp.o
diff --git a/net/net.c b/net/net.c
index 77f42d1d59..babc4e2c17 100644
--- a/net/net.c
+++ b/net/net.c
@@ -526,6 +526,11 @@  restart:
 			ping_start();
 			break;
 #endif
+#if defined(CONFIG_CMD_PING6)
+		case PING6:
+			ping6_start();
+			break;
+#endif
 #if defined(CONFIG_CMD_NFS) && !defined(CONFIG_SPL_BUILD)
 		case NFS:
 			nfs_start();
@@ -1377,6 +1382,14 @@  static int net_check_prereq(enum proto_t protocol)
 		}
 		goto common;
 #endif
+#if defined(CONFIG_CMD_PING6)
+	case PING6:
+		if (ip6_is_unspecified_addr(&net_ping_ip6)) {
+			puts("*** ERROR: ping address not given\n");
+			return 1;
+		}
+		goto common;
+#endif
 #if defined(CONFIG_CMD_DNS)
 	case DNS:
 		if (net_dns_server.s_addr == 0) {
diff --git a/net/net6.c b/net/net6.c
index 0799d411b2..a3b89ded24 100644
--- a/net/net6.c
+++ b/net/net6.c
@@ -444,6 +444,10 @@  void net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
 			return;
 
 		switch (icmp->icmp6_type) {
+		case IPV6_ICMP_ECHO_REQUEST:
+		case IPV6_ICMP_ECHO_REPLY:
+			ping6_receive(et, ip6, len);
+			break;
 		case IPV6_NDISC_NEIGHBOUR_SOLICITATION:
 		case IPV6_NDISC_NEIGHBOUR_ADVERTISEMENT:
 			ndisc_receive(et, ip6, len);
diff --git a/net/ping6.c b/net/ping6.c
new file mode 100644
index 0000000000..3284e314ae
--- /dev/null
+++ b/net/ping6.c
@@ -0,0 +1,117 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2013 Allied Telesis Labs NZ
+ * Chris Packham, <judge.packham@gmail.com>
+ *
+ * Copyright (C) 2022 YADRO
+ * Viacheslav Mitrofanov <v.v.mitrofanov@yadro.com>
+ */
+
+/*
+ * Simple ping6 implementation
+ */
+
+#include <common.h>
+#include <net.h>
+#include <net6.h>
+#include "ndisc.h"
+
+static ushort seq_no;
+
+/* the ipv6 address to ping */
+struct in6_addr net_ping_ip6;
+
+int
+ip6_make_ping(uchar *eth_dst_addr, struct in6_addr *neigh_addr, uchar *pkt)
+{
+	struct echo_msg *msg;
+	__u16 len;
+	uchar *pkt_old = pkt;
+
+	len = sizeof(struct echo_msg);
+
+	pkt += net_set_ether(pkt, eth_dst_addr, PROT_IP6);
+	pkt += ip6_add_hdr(pkt, &net_ip6, neigh_addr, IPPROTO_ICMPV6,
+			   IPV6_NDISC_HOPLIMIT, len);
+
+	/* ICMPv6 - Echo */
+	msg = (struct echo_msg *)pkt;
+	msg->icmph.icmp6_type = IPV6_ICMP_ECHO_REQUEST;
+	msg->icmph.icmp6_code = 0;
+	msg->icmph.icmp6_cksum = 0;
+	msg->icmph.icmp6_identifier = 0;
+	msg->icmph.icmp6_sequence = htons(seq_no++);
+	msg->id = msg->icmph.icmp6_identifier;	/* these seem redundant */
+	msg->sequence = msg->icmph.icmp6_sequence;
+
+	/* checksum */
+	msg->icmph.icmp6_cksum = csum_ipv6_magic(&net_ip6, neigh_addr, len,
+						 IPPROTO_ICMPV6,
+						 csum_partial((u8 *)msg,
+							      len, 0));
+
+	pkt += len;
+
+	return pkt - pkt_old;
+}
+
+int ping6_send(void)
+{
+	uchar *pkt;
+	static uchar mac[6];
+
+	/* always send neighbor solicit */
+
+	memcpy(mac, net_null_ethaddr, 6);
+
+	net_nd_sol_packet_ip6 = net_ping_ip6;
+	net_nd_packet_mac = mac;
+
+	pkt = net_nd_tx_packet;
+	pkt += ip6_make_ping(mac, &net_ping_ip6, pkt);
+
+	/* size of the waiting packet */
+	net_nd_tx_packet_size = (pkt - net_nd_tx_packet);
+
+	/* and do the ARP request */
+	net_nd_try = 1;
+	net_nd_timer_start = get_timer(0);
+	ndisc_request();
+	return 1;		/* waiting */
+}
+
+static void ping6_timeout(void)
+{
+	eth_halt();
+	net_set_state(NETLOOP_FAIL);	/* we did not get the reply */
+}
+
+void ping6_start(void)
+{
+	printf("Using %s device\n", eth_get_name());
+	net_set_timeout_handler(10000UL, ping6_timeout);
+
+	ping6_send();
+}
+
+void ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
+{
+	struct icmp6hdr *icmp =
+	    (struct icmp6hdr *)(((uchar *)ip6) + IP6_HDR_SIZE);
+	struct in6_addr src_ip;
+
+	switch (icmp->icmp6_type) {
+	case IPV6_ICMP_ECHO_REPLY:
+		src_ip = ip6->saddr;
+		if (memcmp(&net_ping_ip6, &src_ip, sizeof(struct in6_addr)))
+			return;
+		net_set_state(NETLOOP_SUCCESS);
+		break;
+	case IPV6_ICMP_ECHO_REQUEST:
+		debug("Got ICMPv6 ECHO REQUEST from %pI6c\n", &ip6->saddr);
+		/* ignore for now.... */
+		break;
+	default:
+		debug("Unexpected ICMPv6 type 0x%x\n", icmp->icmp6_type);
+	}
+}