From f781d0d071fe9f24d9167d23afad0263f0afd512 Mon Sep 17 00:00:00 2001 From: Daniel Rossier Date: Sun, 23 Aug 2026 13:34:25 +0200 Subject: [PATCH 1/3] usr: parse the ICMP reply out of the IP datagram in ping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ping did not build any more: the kernel-side lwIP headers (lwip/icmp.h, lwip/inet.h, lwip/netif.h) are not on the user-space include path, and they are not needed either — musl's already provides ICMP_ECHO/ICMP_ECHOREPLY and struct iphdr. Dropping them alone would still have left the reply check wrong. The magic 69 it used to compare against was never an ICMP type: it is 0x45, the first byte of the IP header (version 4, IHL 5). A raw socket hands over the whole IP datagram — lwIP delivers the pbuf to the raw pcb with the payload still pointing at the IP header — so the ICMP message starts at iphdr->ihl * 4, not at offset 0. Parse the reply accordingly: - receive into a buffer sized for the IP header plus the ICMP message; the previous 64-byte buffer truncated the payload, - reject a reply too short to hold an ICMP header, - check type/code at the right offset, against ICMP_ECHOREPLY, - report the TTL that came back rather than the one we asked for. While here, initialise rtt_total (it was summed into uninitialised) and close the socket on the way out instead of leaving the close commented out under a dead label. --- so3/usr/src/ping.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/so3/usr/src/ping.c b/so3/usr/src/ping.c index 9ba71431e6..ebe17144c9 100644 --- a/so3/usr/src/ping.c +++ b/so3/usr/src/ping.c @@ -1,5 +1,7 @@ /* - * Copyright (C) 2020 Julien Quartier + * Copyright (c) 2020-2026 REDS Institute, HEIG-VD + * Author: Julien Quartier + * Author: Daniel Rossier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -164,10 +166,14 @@ void parse_args(int argc, char **argv) int main(int argc, char **argv) { int s, i = 0, msg_count = 0, msg_count_succeed = 0, attempt = 0; + int len, hlen; unsigned int size = 0; - float rtt = 0, rtt_total, rtt_min = 1000000.0, rtt_max = 0.0; + float rtt = 0, rtt_total = 0.0, rtt_min = 1000000.0, rtt_max = 0.0; char ip[100]; struct ping_pkt packet; + char reply[sizeof(struct iphdr) + PING_PKT_LEN]; + struct iphdr *iph; + struct icmphdr *icmph; struct sockaddr_in ping_addr, recv_addr; struct timeval timeout, start, end; @@ -223,7 +229,9 @@ int main(int argc, char **argv) size = sizeof(recv_addr); - if (recvfrom(s, &packet, sizeof(packet), 0, (struct sockaddr *) &recv_addr, &size) <= 0 && msg_count > 1) { + len = recvfrom(s, reply, sizeof(reply), 0, (struct sockaddr *) &recv_addr, &size); + + if (len <= 0 && msg_count > 1) { printf("Packet receive failed!!\n"); continue; } @@ -234,10 +242,24 @@ int main(int argc, char **argv) rtt = end.tv_usec / 1000.0 + end.tv_sec * 1000 - (start.tv_usec / 1000.0 + start.tv_sec * 1000); - if (!(packet.hdr.type == 69 && packet.hdr.code == 0)) { - printf("Error... Packet received with ICMP type %d code %d\n", packet.hdr.type, packet.hdr.code); + /* A raw socket hands over the whole IP datagram, so the ICMP + * message starts after the IP header, whose length is given by + * the IHL field. */ + + iph = (struct iphdr *) reply; + hlen = iph->ihl * 4; + + if (len < hlen + (int) sizeof(struct icmphdr)) { + printf("Error... Truncated reply of %d bytes\n", len); + continue; + } + + icmph = (struct icmphdr *) (reply + hlen); + + if (!(icmph->type == ICMP_ECHOREPLY && icmph->code == 0)) { + printf("Error... Packet received with ICMP type %d code %d\n", icmph->type, icmph->code); } else { - printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%f ms\n", PING_PKT_LEN, ip, msg_count, ttl, rtt); + printf("%d bytes from %s: icmp_seq=%d ttl=%d time=%f ms\n", len - hlen, ip, msg_count, iph->ttl, rtt); rtt_max = fmaxf(rtt_max, rtt); rtt_min = fminf(rtt_min, rtt); @@ -254,10 +276,6 @@ int main(int argc, char **argv) if (msg_count_succeed > 0) printf("rtt min/avg/max = %f/%f/%f ms\n", rtt_min, rtt_total / msg_count_succeed, rtt_max); + close(s); return 0; - - /*end: - - close(s); - return 0;*/ } From 35388e686f92dddb6d1101d88681e2e40b5c32fb Mon Sep 17 00:00:00 2001 From: Daniel Rossier Date: Sun, 23 Aug 2026 13:34:33 +0200 Subject: [PATCH 2/3] build: show bsp-so3 in the container examples This tree's default target is SO3, so the first thing the build container suggests should be the SO3 BSP, not the Linux one. Switch the examples in the container banner, in dbuild.sh's header and --help, in docker/README.md, in the Dockerfile header and in the build-system chapter; the bsp-linux mention stays as the alternative. --- doc/source/build_system.rst | 2 +- docker/README.md | 4 ++-- docker/build-env/Dockerfile | 2 +- docker/build-env/bashrc | 4 ++-- scripts/dbuild.sh | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/source/build_system.rst b/doc/source/build_system.rst index ac74a14e35..91b6ec0dd3 100644 --- a/doc/source/build_system.rst +++ b/doc/source/build_system.rst @@ -33,7 +33,7 @@ layers. The canonical, continuously-tested list is the base container recipe ``docker/Dockerfile.toolchains`` — mirror it when setting up a bare host. For development, the same environment is available as a ready-made build container: ``scripts/dbuild.sh --build`` then ``scripts/dbuild.sh build.sh -bsp-linux`` (or bare ``dbuild.sh`` for a shell) runs any front-end script +bsp-so3`` (or bare ``dbuild.sh`` for a shell) runs any front-end script inside it, with the repository bind-mounted at its own path and the container running as the calling user — see ``docker/README.md``. diff --git a/docker/README.md b/docker/README.md index ed59545272..32f3ce5343 100644 --- a/docker/README.md +++ b/docker/README.md @@ -17,13 +17,13 @@ user so everything it writes stays yours. ``` ./scripts/dbuild.sh --build # build the so3-build:1.0 image (once) -./scripts/dbuild.sh build.sh bsp-linux # run any front-end script inside +./scripts/dbuild.sh build.sh bsp-so3 # run any front-end script inside ./scripts/dbuild.sh # interactive shell, env.sh sourced ./scripts/dbuild.sh st.sh -d # graphical QEMU from the container ``` Caller environment variables are not forwarded; pass them through the -command: `./scripts/dbuild.sh env IB_FORCE_ATTACH=1 build.sh bsp-linux`. +command: `./scripts/dbuild.sh env IB_FORCE_ATTACH=1 build.sh bsp-so3`. The images below remain the CI/perf-rig side of the house. diff --git a/docker/build-env/Dockerfile b/docker/build-env/Dockerfile index 1c8d879988..ca073a63d2 100644 --- a/docker/build-env/Dockerfile +++ b/docker/build-env/Dockerfile @@ -8,7 +8,7 @@ # CMake caches and the *.attach.sha256 manifests all embed absolute paths). # # Build the image: scripts/dbuild.sh --build -# Use it: scripts/dbuild.sh build.sh bsp-linux +# Use it: scripts/dbuild.sh build.sh bsp-so3 # scripts/dbuild.sh st.sh -d # # The build context is this directory only — never the project root, diff --git a/docker/build-env/bashrc b/docker/build-env/bashrc index b463d7d6f3..debf83c4df 100644 --- a/docker/build-env/bashrc +++ b/docker/build-env/bashrc @@ -54,8 +54,8 @@ you are running as the host user, so anything you produce stays yours. env.sh is already sourced. build.sh -l list recipes - build.sh bsp-linux build the Linux BSP (bsp-so3 for SO3) - deploy.sh bsp-linux deploy (FIT + rootfs + sdcard) + build.sh bsp-so3 build the SO3 BSP (bsp-linux for Linux) + deploy.sh bsp-so3 deploy (FIT + rootfs + sdcard) st.sh / st.sh -d run in QEMU (headless / graphical) exit leave the container diff --git a/scripts/dbuild.sh b/scripts/dbuild.sh index 42fb549cc2..f75ab1e634 100755 --- a/scripts/dbuild.sh +++ b/scripts/dbuild.sh @@ -10,8 +10,8 @@ # Usage: # dbuild.sh --build Build (or rebuild) the image # dbuild.sh Interactive shell inside the container -# dbuild.sh build.sh bsp-linux Run a build -# dbuild.sh deploy.sh bsp-linux Deploy it +# dbuild.sh build.sh bsp-so3 Run a build +# dbuild.sh deploy.sh bsp-so3 Deploy it # dbuild.sh st.sh -d Run it under QEMU, graphical # # The command runs with the project root bind-mounted at its OWN @@ -54,8 +54,8 @@ pr_usage() printf " scripts/ and bitbake are on PATH.\n\n" printf "Examples:\n" printf " %s --build\n" "$progname" - printf " %s build.sh bsp-linux\n" "$progname" - printf " %s deploy.sh bsp-linux\n" "$progname" + printf " %s build.sh bsp-so3\n" "$progname" + printf " %s deploy.sh bsp-so3\n" "$progname" printf " %s st.sh -d\n" "$progname" } From 9d5d5755ffdd5aca1d03aff14086dd91b0898b71 Mon Sep 17 00:00:00 2001 From: Daniel Rossier Date: Sun, 23 Aug 2026 13:34:33 +0200 Subject: [PATCH 3/3] build: keep tezi-feed-serve --ensure quiet with no feed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --ensure runs after every build and deploy, including on the soft- and hard-storage platforms that never publish a TEZI feed, so an absent feed directory is the normal case there — yet each command ended with a "feed directory does not exist yet / run a deploy first" pair on stderr. Test for the feed quietly in do_ensure and leave the explaining to check_feed, which now only runs when the server is asked for explicitly (foreground invocation), where the hint is what the user wants. --- scripts/tezi-feed-serve.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/tezi-feed-serve.sh b/scripts/tezi-feed-serve.sh index 3a4354487a..d0c2cea72c 100755 --- a/scripts/tezi-feed-serve.sh +++ b/scripts/tezi-feed-serve.sh @@ -199,7 +199,13 @@ do_ensure() fi running_pid >/dev/null && return 0 - check_feed || return 0 + + # Called after every build and deploy, including on platforms that never + # publish a feed (soft/hard storage), so a missing feed is the normal + # case here: stay quiet and leave the explaining to check_feed, which + # only runs when the server is asked for explicitly. + + [ -d "$feed" ] && [ -f "$feed/image_list.json" ] || return 0 command -v python3 >/dev/null 2>&1 || { printf "%s: python3 not found — cannot serve the feed\n" "$progname" >&2