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


Reply via email to