summaryrefslogtreecommitdiff
path: root/net/lwip/ping.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2024-10-16 08:12:28 -0600
committerTom Rini <trini@konsulko.com>2024-10-16 11:11:57 -0600
commit608a31bdec6284ad6f821226e4c62c9cd3052874 (patch)
treec43e6664c7530f354f73c05cb817e37d10d93615 /net/lwip/ping.c
parent1ca0ddb643f3b152439f7bb8f6ee3f5826d7102d (diff)
parent4820cb4b16c44ec332b18dbe7207ddd8c0a1d446 (diff)
Merge patch series "Introduce the lwIP network stack"
Jerome Forissier <jerome.forissier@linaro.org> says: This is a rework of a patch series by Maxim Uvarov: "net/lwip: add lwip library for the network stack" [1]. The goal is to introduce the lwIP TCP/IP stack [2] [3] as an alternative to the current implementation in net/, selectable with Kconfig, and ultimately keep only lwIP if possible. Some reasons for doing so are: - Make the support of HTTPS in the wget command easier. Javier T. and Raymond M. (CC'd) have some additional lwIP and Mbed TLS patches to do so. With that it becomes possible to fetch and launch a distro installer such as Debian etc. using a secure, authenticated connection directly from the U-Boot shell. Several use cases: * Authentication: prevent MITM attack (third party replacing the binary with a different one) * Confidentiality: prevent third parties from grabbing a copy of the image as it is being downloaded * Allow connection to servers that do not support plain HTTP anymore (this is becoming more and more common on the Internet these days) - Possibly benefit from additional features implemented in lwIP - Less code to maintain in U-Boot Prior to applying this series, the lwIP stack needs to be added as a Git subtree with the following command: $ git subtree add --squash --prefix lib/lwip/lwip \ https://github.com/lwip-tcpip/lwip.git STABLE-2_2_0_RELEASE Notes 1. A number of features are currently incompatible with NET_LWIP: DFU_TFTP, FASTBOOT, SPL_NET, ETH_SANDBOX, ETH_SANDBOX_RAW, DM_ETH. They all make assumptions on how the network stack is implemented and/or pull sybols that are not trivially exported from lwIP. Some interface rework may be needed. 2. Due to the above, and in order to provide some level of testing of the lwIP code in CI even when the legacy NET is the default, a new QEMU configuration is introduced (qemu_arm64_lwip_defconfig) which is based on qemu_arm64_defconfig with NET_LWIP and CMD_*_LWIP enabled. In addition to that, this series has some [TESTING] patches which make NET_LWIP the default. [1] https://lore.kernel.org/all/20231127125726.3735-1-maxim.uvarov@linaro.org/ [2] https://www.nongnu.org/lwip/ [3] https://en.wikipedia.org/wiki/LwIP Link: https://lore.kernel.org/r/cover.1729070678.git.jerome.forissier@linaro.org
Diffstat (limited to 'net/lwip/ping.c')
-rw-r--r--net/lwip/ping.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/net/lwip/ping.c b/net/lwip/ping.c
new file mode 100644
index 00000000000..8dafa25959f
--- /dev/null
+++ b/net/lwip/ping.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2024 Linaro Ltd. */
+
+#include <command.h>
+#include <console.h>
+#include <dm/device.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <lwip/icmp.h>
+#include <lwip/inet_chksum.h>
+#include <lwip/raw.h>
+#include <lwip/timeouts.h>
+#include <net.h>
+#include <time.h>
+
+#define PING_DELAY_MS 1000
+#define PING_COUNT 5
+/* Ping identifier - must fit on a u16_t */
+#define PING_ID 0xAFAF
+
+struct ping_ctx {
+ ip_addr_t target;
+ struct raw_pcb *pcb;
+ struct icmp_echo_hdr *iecho;
+ uint16_t seq_num;
+ bool alive;
+};
+
+static u8_t ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p,
+ const ip_addr_t *addr)
+{
+ struct ping_ctx *ctx = arg;
+ struct icmp_echo_hdr *iecho = ctx->iecho;
+
+ if (addr->addr != ctx->target.addr)
+ return 0;
+
+ if ((p->tot_len >= (IP_HLEN + sizeof(struct icmp_echo_hdr))) &&
+ pbuf_remove_header(p, IP_HLEN) == 0) {
+ iecho = (struct icmp_echo_hdr *)p->payload;
+
+ if ((iecho->id == PING_ID) &&
+ (iecho->seqno == lwip_htons(ctx->seq_num))) {
+ ctx->alive = true;
+ printf("host %s is alive\n", ipaddr_ntoa(addr));
+ pbuf_free(p);
+ return 1; /* eat the packet */
+ }
+ /* not eaten, restore original packet */
+ pbuf_add_header(p, IP_HLEN);
+ }
+
+ return 0; /* don't eat the packet */
+}
+
+static int ping_raw_init(struct ping_ctx *ctx)
+{
+ ctx->pcb = raw_new(IP_PROTO_ICMP);
+ if (!ctx->pcb)
+ return -ENOMEM;
+
+ raw_recv(ctx->pcb, ping_recv, ctx);
+ raw_bind(ctx->pcb, IP_ADDR_ANY);
+
+ return 0;
+}
+
+static void ping_raw_stop(struct ping_ctx *ctx)
+{
+ if (ctx->pcb)
+ raw_remove(ctx->pcb);
+}
+
+static void ping_prepare_echo(struct ping_ctx *ctx)
+{
+ struct icmp_echo_hdr *iecho = ctx->iecho;
+
+ ICMPH_TYPE_SET(iecho, ICMP_ECHO);
+ ICMPH_CODE_SET(iecho, 0);
+ iecho->chksum = 0;
+ iecho->id = PING_ID;
+ iecho->seqno = lwip_htons(ctx->seq_num);
+
+ iecho->chksum = inet_chksum(iecho, sizeof(*iecho));
+}
+
+static void ping_send_icmp(struct ping_ctx *ctx)
+{
+ struct pbuf *p;
+ size_t ping_size = sizeof(struct icmp_echo_hdr);
+
+ p = pbuf_alloc(PBUF_IP, (u16_t)ping_size, PBUF_RAM);
+ if (!p)
+ return;
+
+ if ((p->len == p->tot_len) && !p->next) {
+ ctx->iecho = (struct icmp_echo_hdr *)p->payload;
+ ping_prepare_echo(ctx);
+ raw_sendto(ctx->pcb, p, &ctx->target);
+ }
+
+ pbuf_free(p);
+}
+
+static void ping_send(void *arg)
+{
+ struct ping_ctx *ctx = arg;
+
+ ctx->seq_num++;
+ if (ctx->seq_num <= PING_COUNT) {
+ ping_send_icmp(ctx);
+ sys_timeout(PING_DELAY_MS, ping_send, ctx);
+ }
+}
+
+static int ping_loop(struct udevice *udev, const ip_addr_t* addr)
+{
+ struct ping_ctx ctx = {};
+ struct netif *netif;
+ int ret;
+
+ netif = net_lwip_new_netif(udev);
+ if (!netif)
+ return CMD_RET_FAILURE;
+
+ printf("Using %s device\n", udev->name);
+
+ ret = ping_raw_init(&ctx);
+ if (ret < 0) {
+ net_lwip_remove_netif(netif);
+ return ret;
+ }
+
+ ctx.target = *addr;
+
+ ping_send(&ctx);
+
+ do {
+ sys_check_timeouts();
+ net_lwip_rx(udev, netif);
+ if (ctx.alive)
+ break;
+ if (ctrlc()) {
+ printf("\nAbort\n");
+ break;
+ }
+ } while (ctx.seq_num <= PING_COUNT);
+
+ sys_untimeout(ping_send, &ctx);
+ ping_raw_stop(&ctx);
+
+ net_lwip_remove_netif(netif);
+
+ if (ctx.alive)
+ return 0;
+
+ printf("ping failed; host %s is not alive\n", ipaddr_ntoa(addr));
+ return -1;
+}
+
+int do_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ ip_addr_t addr;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ if (!ipaddr_aton(argv[1], &addr))
+ return CMD_RET_USAGE;
+
+ eth_set_current();
+
+ if (ping_loop(eth_get_dev(), &addr) < 0)
+ return CMD_RET_FAILURE;
+
+ return CMD_RET_SUCCESS;
+}