mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Oleksij Rempel <o.rempel@pengutronix.de>
To: Robin van der Gracht <robin@protonic.nl>,
	Oliver Hartkopp <socketcan@hartkopp.net>,
	Marc Kleine-Budde <mkl@pengutronix.de>,
	Shuah Khan <shuah@kernel.org>
Cc: "Oleksij Rempel" <o.rempel@pengutronix.de>,
	kernel@pengutronix.de, linux-can@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	"Alexander Hölzl" <alexander.hoelzl@gmx.net>,
	Quchaosheng <quchaosheng000406@163.com>,
	"Tetsuo Handa" <penguin-kernel@I-love.SAKURA.ne.jp>
Subject: [PATCH can-next v1 2/8] selftests: can: add J1939 base functional tests
Date: Wed, 14 Oct 2026 17:44:28 +0200	[thread overview]
Message-ID: <20261014154435.3577983-3-o.rempel@pengutronix.de> (raw)
In-Reply-To: <20261014154435.3577983-1-o.rempel@pengutronix.de>

Add a functional selftest for the SAE J1939 socket interface. It runs two
CAN_J1939 sockets (a sender and a receiver) over a vcan interface and
checks payload integrity across the transport-size transitions: single
frame (PDU1), Transport Protocol, Extended Transport Protocol, the exact
size boundaries around those transitions, and single-frame and BAM
broadcast (PDU2).

Declare j1939_tests.h as a local header dependency and enable
CONFIG_CAN_J1939 in the test config.

Assisted-by: LLM
Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 tools/testing/selftests/net/can/.gitignore    |   1 +
 tools/testing/selftests/net/can/Makefile      |  10 +-
 tools/testing/selftests/net/can/config        |   1 +
 .../selftests/net/can/test_j1939_base.c       | 160 ++++++++++++++++++
 .../selftests/net/can/test_j1939_base.sh      |   5 +
 5 files changed, 175 insertions(+), 2 deletions(-)
 create mode 100644 tools/testing/selftests/net/can/test_j1939_base.c
 create mode 100755 tools/testing/selftests/net/can/test_j1939_base.sh

diff --git a/tools/testing/selftests/net/can/.gitignore b/tools/testing/selftests/net/can/.gitignore
index 764a53fc837f..0ab563fe9ddf 100644
--- a/tools/testing/selftests/net/can/.gitignore
+++ b/tools/testing/selftests/net/can/.gitignore
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test_raw_filter
+test_j1939_base
diff --git a/tools/testing/selftests/net/can/Makefile b/tools/testing/selftests/net/can/Makefile
index e2092c289109..cf4bd2461a6c 100644
--- a/tools/testing/selftests/net/can/Makefile
+++ b/tools/testing/selftests/net/can/Makefile
@@ -4,10 +4,16 @@ top_srcdir = ../../../../..
 
 CFLAGS += -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INCLUDES)
 
-TEST_PROGS := test_raw_filter.sh
+LOCAL_HDRS := j1939_tests.h
+
+TEST_PROGS := \
+	test_raw_filter.sh \
+	test_j1939_base.sh \
 
 TEST_FILES := j1939_lib.sh
 
-TEST_GEN_FILES := test_raw_filter
+TEST_GEN_FILES := \
+	test_raw_filter \
+	test_j1939_base \
 
 include ../../lib.mk
diff --git a/tools/testing/selftests/net/can/config b/tools/testing/selftests/net/can/config
index 188f79796670..52a186bd1055 100644
--- a/tools/testing/selftests/net/can/config
+++ b/tools/testing/selftests/net/can/config
@@ -1,3 +1,4 @@
 CONFIG_CAN=m
 CONFIG_CAN_DEV=m
 CONFIG_CAN_VCAN=m
+CONFIG_CAN_J1939=m
diff --git a/tools/testing/selftests/net/can/test_j1939_base.c b/tools/testing/selftests/net/can/test_j1939_base.c
new file mode 100644
index 000000000000..59f1448b7fb2
--- /dev/null
+++ b/tools/testing/selftests/net/can/test_j1939_base.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+/*
+ * J1939 base functional selftests.
+ *
+ * Run two SOCK_DGRAM/CAN_J1939 sockets (a sender and a receiver) over a vcan
+ * interface and verify payload integrity across the transport-size transitions:
+ * a single frame (PDU1), Transport Protocol, Extended Transport Protocol, the
+ * exact boundaries between them, and single-frame and BAM broadcast (PDU2).
+ *
+ * The vcan interface is set up by the caller (see test_j1939_base.sh); its name
+ * is passed via the CANIF environment variable.
+ */
+#include <errno.h>
+
+#include "kselftest_harness.h"
+#include "j1939_tests.h"
+
+#define SA_TX			0x80
+#define SA_RX			0x90
+#define PGN_PDU1		0x0ab00	/* PF 0xab (< 240): destination specific */
+#define PGN_PDU2		0x0feee	/* PF 0xfe (>= 240): broadcast */
+
+FIXTURE(j1939_base)
+{
+	int ifindex;
+	int tx;
+	int rx;
+};
+
+FIXTURE_SETUP(j1939_base)
+{
+	self->tx = -1;
+	self->rx = -1;
+	J1939_SETUP_IFINDEX(self);
+}
+
+FIXTURE_TEARDOWN(j1939_base)
+{
+	if (self->tx >= 0)
+		close(self->tx);
+	if (self->rx >= 0)
+		close(self->rx);
+}
+
+/*
+ * Set up a receiver bound to (rx_addr, pgn) and a sender bound to SA_TX and
+ * connected to (tx_dst, pgn). Any pair opened by a previous call is closed
+ * first. Returns 0 on success, -1 otherwise.
+ */
+static int pair_up(FIXTURE_DATA(j1939_base) *self, uint8_t rx_addr,
+		   uint8_t tx_dst, pgn_t pgn, int bcast)
+{
+	int flags = bcast ? J1939_OPEN_BCAST : 0;
+
+	if (self->tx >= 0) {
+		close(self->tx);
+		self->tx = -1;
+	}
+	if (self->rx >= 0) {
+		close(self->rx);
+		self->rx = -1;
+	}
+
+	self->rx = j1939_open_flags(self->ifindex, J1939_NO_NAME, rx_addr, pgn,
+				   flags);
+	if (self->rx < 0) {
+		fprintf(stderr, "# open rx failed: %d\n", errno);
+		return -1;
+	}
+
+	self->tx = j1939_open_flags(self->ifindex, J1939_NO_NAME, SA_TX,
+				   J1939_NO_PGN, flags);
+	if (self->tx < 0) {
+		fprintf(stderr, "# open tx failed: %d\n", errno);
+		return -1;
+	}
+
+	if (j1939_connect(self->tx, self->ifindex, tx_dst, pgn)) {
+		fprintf(stderr, "# connect tx failed: %d\n", errno);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Send a deterministic payload of the given size on tx and verify it is
+ * received byte for byte on rx. Returns 0 on success, -1 otherwise.
+ */
+static int roundtrip(FIXTURE_DATA(j1939_base) *self, size_t size)
+{
+	uint8_t *tx_buf;
+	int rc;
+
+	tx_buf = malloc(size);
+	if (!tx_buf) {
+		fprintf(stderr, "# alloc failed\n");
+		return -1;
+	}
+	fill_pattern(tx_buf, size);
+
+	rc = send_recv_verify(self->tx, self->rx, tx_buf, size,
+			      J1939_RECV_TIMEOUT_MS);
+	if (rc)
+		fprintf(stderr, "# round-trip failed at size %zu, errno %d\n",
+			size, errno);
+
+	free(tx_buf);
+	return rc;
+}
+
+/* single frame (<= 8 bytes), unicast PDU1. */
+TEST_F(j1939_base, single_frame_pdu1)
+{
+	ASSERT_EQ(pair_up(self, SA_RX, SA_RX, PGN_PDU1, 0), 0);
+	EXPECT_EQ(roundtrip(self, 8), 0);
+}
+
+/* Transport Protocol (9 .. 1785 bytes), unicast. */
+TEST_F(j1939_base, tp_roundtrip)
+{
+	ASSERT_EQ(pair_up(self, SA_RX, SA_RX, PGN_PDU1, 0), 0);
+	EXPECT_EQ(roundtrip(self, 128), 0);
+}
+
+/* Extended Transport Protocol (> 1785 bytes), unicast. */
+TEST_F(j1939_base, etp_roundtrip)
+{
+	ASSERT_EQ(pair_up(self, SA_RX, SA_RX, PGN_PDU1, 0), 0);
+	EXPECT_EQ(roundtrip(self, 2000), 0);
+}
+
+/* exact size boundaries around single / TP / ETP transitions. */
+TEST_F(j1939_base, size_boundaries)
+{
+	static const size_t sizes[] = { 8, 9, 1785, 1786 };
+	size_t k;
+
+	for (k = 0; k < ARRAY_SIZE(sizes); k++) {
+		ASSERT_EQ(pair_up(self, SA_RX, SA_RX, PGN_PDU1, 0), 0);
+		EXPECT_EQ(roundtrip(self, sizes[k]), 0)
+			TH_LOG("failed at boundary size %zu", sizes[k]);
+	}
+}
+
+/* single-frame broadcast, PDU2. */
+TEST_F(j1939_base, single_frame_broadcast_pdu2)
+{
+	ASSERT_EQ(pair_up(self, SA_RX, J1939_NO_ADDR, PGN_PDU2, 1), 0);
+	EXPECT_EQ(roundtrip(self, 8), 0);
+}
+
+/* BAM (broadcast transport). */
+TEST_F(j1939_base, bam_broadcast)
+{
+	ASSERT_EQ(pair_up(self, SA_RX, J1939_NO_ADDR, PGN_PDU2, 1), 0);
+	EXPECT_EQ(roundtrip(self, 128), 0);
+}
+
+J1939_TEST_MAIN();
diff --git a/tools/testing/selftests/net/can/test_j1939_base.sh b/tools/testing/selftests/net/can/test_j1939_base.sh
new file mode 100755
index 000000000000..3cd2b14a74bb
--- /dev/null
+++ b/tools/testing/selftests/net/can/test_j1939_base.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+J1939_TEST_PROG=test_j1939_base
+source "$(dirname "$0")/j1939_lib.sh"
-- 
2.47.3


  parent reply	other threads:[~2026-10-14 15:44 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-14 15:44 [PATCH can-next v1 0/8] selftests: can: add J1939 socket and transport tests Oleksij Rempel
2026-10-14 15:44 ` [PATCH can-next v1 1/8] selftests: can: add J1939 test helper header and library Oleksij Rempel
2026-10-16  6:59   ` netdev-bot+sashiko
2026-10-14 15:44 ` Oleksij Rempel [this message]
2026-10-16  7:00   ` [PATCH can-next v1 2/8] selftests: can: add J1939 base functional tests netdev-bot+sashiko
2026-10-14 15:44 ` [PATCH can-next v1 3/8] selftests: can: add J1939 socket option and metadata tests Oleksij Rempel
2026-10-16  7:00   ` netdev-bot+sashiko
2026-10-14 15:44 ` [PATCH can-next v1 4/8] selftests: can: add J1939 addressing and concurrency tests Oleksij Rempel
2026-10-16  7:00   ` netdev-bot+sashiko
2026-10-14 15:44 ` [PATCH can-next v1 5/8] selftests: can: add J1939 wire-format tests against CAN_RAW Oleksij Rempel
2026-10-16  7:00   ` netdev-bot+sashiko
2026-10-14 15:44 ` [PATCH can-next v1 6/8] selftests: can: add J1939 TP/ETP multi-frame " Oleksij Rempel
2026-10-16  7:00   ` netdev-bot+sashiko
2026-10-14 15:44 ` [PATCH can-next v1 7/8] selftests: can: cover J1939 transport abort and timeout paths Oleksij Rempel
2026-10-16  7:00   ` netdev-bot+sashiko
2026-10-14 15:44 ` [PATCH can-next v1 8/8] selftests: can: check SO_J1939_PROMISC receive effect Oleksij Rempel
2026-10-14 22:19 ` [PATCH can-next v1 0/8] selftests: can: add J1939 socket and transport tests Marc Kleine-Budde

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261014154435.3577983-3-o.rempel@pengutronix.de \
    --to=o.rempel@pengutronix.de \
    --cc=alexander.hoelzl@gmx.net \
    --cc=kernel@pengutronix.de \
    --cc=linux-can@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=mkl@pengutronix.de \
    --cc=penguin-kernel@I-love.SAKURA.ne.jp \
    --cc=quchaosheng000406@163.com \
    --cc=robin@protonic.nl \
    --cc=shuah@kernel.org \
    --cc=socketcan@hartkopp.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®