[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