Add a test that exercises the SO_J1939_PROMISC receive effect. The existing coverage only round-trips the flag through set/getsockopt, so a kernel that stores it but never acts on it in the RX path stays green.
The test binds an rx socket to a specific (address, PGN), checks that a frame to a different destination address and PGN is not delivered, then enables SO_J1939_PROMISC and checks the same otherwise-unmatched frame is now delivered unchanged. Assisted-by: LLM Signed-off-by: Oleksij Rempel <[email protected]> --- .../selftests/net/can/test_j1939_opts.c | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/net/can/test_j1939_opts.c b/tools/testing/selftests/net/can/test_j1939_opts.c index f761a42db213..3afda9b4e4a8 100644 --- a/tools/testing/selftests/net/can/test_j1939_opts.c +++ b/tools/testing/selftests/net/can/test_j1939_opts.c @@ -5,8 +5,8 @@ * On top of the basic transport, cover the user-visible J1939 socket options and * addressing: the SO_J1939_FILTER PGN whitelist, the SO_J1939_SEND_PRIO send * priority seen in the CAN id (via a CAN_RAW peer, including the default of 6), - * unconnected sendto(2), a wrong-family bind rejection, and SO_J1939_ERRQUEUE - * TX-completion notifications. + * unconnected sendto(2), a wrong-family bind rejection, SO_J1939_ERRQUEUE + * TX-completion notifications, and the SO_J1939_PROMISC receive effect. * * The vcan interface is set up by the caller (see test_j1939_opts.sh); its name * is passed via the CANIF environment variable. @@ -22,6 +22,7 @@ #define SA_TX 0x80 #define SA_RX 0x90 +#define SA_OTHER 0x50 #define PGN_A 0x0ab00 #define PGN_B 0x0cd00 #define PRIO_SET 3 @@ -123,6 +124,47 @@ TEST_F(j1939_opts, filter_pgn) TH_LOG("PGN_B was received but should have been filtered out"); } +/* SO_J1939_PROMISC delivers a frame that does not match the bound (addr,pgn). */ +TEST_F(j1939_opts, promisc_receive) +{ + uint8_t tx_buf[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + uint8_t rx_buf[8]; + int enable = 1; + int ret; + + self->rx = j1939_open(self->ifindex, SA_RX, PGN_A); + ASSERT_GE(self->rx, 0); + self->tx = j1939_open(self->ifindex, SA_TX, J1939_NO_PGN); + ASSERT_GE(self->tx, 0); + + /* + * This frame uses a different address and PGN than rx is bound to. + * Without promisc, rx must not receive it. + */ + ret = j1939_sendto(self->tx, tx_buf, sizeof(tx_buf), self->ifindex, + J1939_NO_NAME, SA_OTHER, PGN_B); + ASSERT_EQ(ret, (int)sizeof(tx_buf)) + TH_LOG("sendto unmatched frame failed: %d", errno); + EXPECT_EQ(recv_timeout(self->rx, rx_buf, sizeof(rx_buf), + J1939_NEG_RECV_TIMEOUT_MS), -1) + TH_LOG("unmatched frame was received without promisc"); + + /* SO_J1939_PROMISC returns the flag value (1), not 0, on success. */ + ASSERT_GE(setsockopt(self->rx, SOL_CAN_J1939, SO_J1939_PROMISC, + &enable, sizeof(enable)), 0) + TH_LOG("SO_J1939_PROMISC failed: %d", errno); + + /* The same otherwise-unmatched frame must now be delivered. */ + ret = j1939_sendto(self->tx, tx_buf, sizeof(tx_buf), self->ifindex, + J1939_NO_NAME, SA_OTHER, PGN_B); + ASSERT_EQ(ret, (int)sizeof(tx_buf)) + TH_LOG("sendto unmatched frame failed: %d", errno); + ASSERT_EQ(recv_timeout(self->rx, rx_buf, sizeof(rx_buf), + J1939_RECV_TIMEOUT_MS), (int)sizeof(tx_buf)) + TH_LOG("unmatched frame not received despite promisc"); + EXPECT_EQ(memcmp(tx_buf, rx_buf, sizeof(tx_buf)), 0); +} + /* without SO_J1939_SEND_PRIO the J1939 default priority (6) is used. */ TEST_F(j1939_opts, send_prio_default) { -- 2.47.3

