[PATCH 11/17] net: ping6: Add ping6 command
Ramon Fried
rfried.dev at gmail.com
Mon Sep 12 09:22:35 CEST 2022
On Tue, Sep 6, 2022 at 6:10 PM Viacheslav Mitrofanov
<v.v.mitrofanov at 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 at yadro.com>
> ---
> cmd/Kconfig | 7 +++
> cmd/net.c | 27 +++++++++++
> include/net.h | 4 +-
> include/net6.h | 26 +++++++++++
> net/Makefile | 1 +
> net/net.c | 13 ++++++
> net/net6.c | 4 ++
> net/ping6.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++
> 8 files changed, 200 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 0f4f9a5625..3266620587 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -241,6 +241,7 @@ static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
> * mis-interpreted as a valid number.
> */
> addr = hextoul(argv[1], &end);
> +
> if (end == (argv[1] + strlen(argv[1]))) {
> image_load_addr = addr;
> /* refresh bootfile name from env */
> @@ -347,6 +348,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], strlen(argv[1]), &net_ping_ip6))
> + 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 cf52d023db..138636158b 100644
> --- a/include/net6.h
> +++ b/include/net6.h
> @@ -172,6 +172,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)
> @@ -403,4 +404,29 @@ static inline void net_copy_ip6(void *to, const void *from)
> }
> #endif
>
> +#if IS_ENABLED(CONFIG_CMD_PING6)
> +/* Send ping requset*/
> +void ping6_start(void);
> +
> +/**
> + * Handle reception of ICMPv6 echo request/reply
> + *
> + * @param et pointer to incoming patcket
> + * @param ip6 pointer to IPv6 protocol
> + * @param len packet length
> + * @return 0 if success, -EINVAL in case of failure during reception
> + */
> +int ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len);
> +#else
> +static inline void ping6_start(void)
> +{
> +}
> +
> +static inline
> +int ping6_receive(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
> +{
> + return -EINVAL;
> +}
> +#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 eaf78c4980..b40c22c45d 100644
> --- a/net/net.c
> +++ b/net/net.c
> @@ -509,6 +509,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();
> @@ -1360,6 +1365,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 e604227fe5..fdea078788 100644
> --- a/net/net6.c
> +++ b/net/net6.c
> @@ -404,6 +404,10 @@ int net_ip6_handler(struct ethernet_hdr *et, struct ip6_hdr *ip6, int len)
> return -EINVAL;
>
> 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..c39eb6146d
> --- /dev/null
> +++ b/net/ping6.c
> @@ -0,0 +1,120 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2013 Allied Telesis Labs NZ
> + * Chris Packham, <judge.packham at gmail.com>
> + *
> + * Copyright (C) 2022 YADRO
> + * Viacheslav Mitrofanov <v.v.mitrofanov at 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;
> + u16 csum_p;
> + 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, PROT_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 */
> + csum_p = csum_partial((u8 *)msg, len, 0);
> + msg->icmph.icmp6_cksum = csum_ipv6_magic(&net_ip6, neigh_addr, len,
> + PROT_ICMPV6, csum_p);
> +
> + 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();
> +}
> +
> +int 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 -EINVAL;
> + net_set_state(NETLOOP_SUCCESS);
> + break;
> + case IPV6_ICMP_ECHO_REQUEST:
> + /* ignore for now.... */
> + debug("Got ICMPv6 ECHO REQUEST from %pI6c\n", &ip6->saddr);
> + return -EINVAL;
> + default:
> + debug("Unexpected ICMPv6 type 0x%x\n", icmp->icmp6_type);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> --
> 2.25.1
>
Reviewed-by: Ramon Fried <rfried.dev at gmail.com>
More information about the U-Boot
mailing list