Tests for the can subsytem have been in the can-tests repository[1] so far. Start moving the tests to kernel selftests by importing the current tst-filter test. Subsequent patches will update the test to be more aligned with the kernel selftests and follow the coding style.
The imported test verifies that the single filters on raw CAN sockets work as expected.
[1]: https://github.com/linux-can/can-tests
Signed-off-by: Felix Maurer fmaurer@redhat.com ---
Notes: I have removed the long form of the licenses in the beginning of the file during the import, as that is covered by the SPDX line anyways. The copyright is left as it was originally.
MAINTAINERS | 2 + tools/testing/selftests/Makefile | 1 + tools/testing/selftests/net/can/.gitignore | 2 + tools/testing/selftests/net/can/Makefile | 9 + .../selftests/net/can/test_raw_filter.c | 204 ++++++++++++++++++ .../selftests/net/can/test_raw_filter.sh | 37 ++++ 6 files changed, 255 insertions(+) create mode 100644 tools/testing/selftests/net/can/.gitignore create mode 100644 tools/testing/selftests/net/can/Makefile create mode 100644 tools/testing/selftests/net/can/test_raw_filter.c create mode 100755 tools/testing/selftests/net/can/test_raw_filter.sh
diff --git a/MAINTAINERS b/MAINTAINERS index 241ca9e260a2..55749b492ebb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5155,6 +5155,7 @@ F: include/uapi/linux/can/isotp.h F: include/uapi/linux/can/raw.h F: net/can/ F: net/sched/em_canid.c +F: tools/testing/selftests/net/can/
CAN-J1939 NETWORK LAYER M: Robin van der Gracht robin@protonic.nl @@ -16577,6 +16578,7 @@ X: net/ceph/ X: net/mac80211/ X: net/rfkill/ X: net/wireless/ +X: tools/testing/selftests/net/can/
NETWORKING [IPSEC] M: Steffen Klassert steffen.klassert@secunet.com diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 8daac70c2f9d..e5c9ecd52b73 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -64,6 +64,7 @@ TARGETS += mqueue TARGETS += nci TARGETS += net TARGETS += net/af_unix +TARGETS += net/can TARGETS += net/forwarding TARGETS += net/hsr TARGETS += net/mptcp diff --git a/tools/testing/selftests/net/can/.gitignore b/tools/testing/selftests/net/can/.gitignore new file mode 100644 index 000000000000..764a53fc837f --- /dev/null +++ b/tools/testing/selftests/net/can/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +test_raw_filter diff --git a/tools/testing/selftests/net/can/Makefile b/tools/testing/selftests/net/can/Makefile new file mode 100644 index 000000000000..44ef37f064ad --- /dev/null +++ b/tools/testing/selftests/net/can/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 + +top_srcdir = ../../../../.. + +TEST_PROGS := test_raw_filter.sh + +TEST_GEN_FILES := test_raw_filter + +include ../../lib.mk diff --git a/tools/testing/selftests/net/can/test_raw_filter.c b/tools/testing/selftests/net/can/test_raw_filter.c new file mode 100644 index 000000000000..c84260f36565 --- /dev/null +++ b/tools/testing/selftests/net/can/test_raw_filter.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +/* + * Copyright (c) 2011 Volkswagen Group Electronic Research + * All rights reserved. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <net/if.h> + +#include <linux/can.h> +#include <linux/can/raw.h> + +#define ID 0x123 +#define TC 18 /* # of testcases */ + +const int rx_res[TC] = {4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1}; +const int rxbits_res[TC] = {4369, 4369, 4369, 4369, 17, 4352, 17, 4352, 257, 257, 4112, 4112, 1, 256, 16, 4096, 1, 256}; + +#define VCANIF "vcan0" + +canid_t calc_id(int testcase) +{ + canid_t id = ID; + + if (testcase & 1) + id |= CAN_EFF_FLAG; + if (testcase & 2) + id |= CAN_RTR_FLAG; + + return id; +} + +canid_t calc_mask(int testcase) +{ + canid_t mask = CAN_SFF_MASK; + + if (testcase > 15) + return (CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG); + + if (testcase & 4) + mask |= CAN_EFF_FLAG; + if (testcase & 8) + mask |= CAN_RTR_FLAG; + + return mask; +} + +int main(int argc, char **argv) +{ + fd_set rdfs; + struct timeval tv; + int s; + struct sockaddr_can addr; + struct can_filter rfilter; + struct can_frame frame; + int testcase; + int have_rx; + int rx; + int rxbits, rxbitval; + int ret; + int recv_own_msgs = 1; + int err = 0; + struct ifreq ifr; + + if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) { + perror("socket"); + err = 1; + goto out; + } + + strcpy(ifr.ifr_name, VCANIF); + if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { + perror("SIOCGIFINDEX"); + err = 1; + goto out_socket; + } + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, + &recv_own_msgs, sizeof(recv_own_msgs)); + + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + perror("bind"); + err = 1; + goto out_socket; + } + + printf("---\n"); + + for (testcase = 0; testcase < TC; testcase++) { + + rfilter.can_id = calc_id(testcase); + rfilter.can_mask = calc_mask(testcase); + setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, + &rfilter, sizeof(rfilter)); + + printf("testcase %2d filters : can_id = 0x%08X can_mask = 0x%08X\n", + testcase, rfilter.can_id, rfilter.can_mask); + + printf("testcase %2d sending patterns ... ", testcase); + + frame.can_dlc = 1; + frame.data[0] = testcase; + + frame.can_id = ID; + if (write(s, &frame, sizeof(frame)) < 0) { + perror("write"); + exit(1); + } + frame.can_id = (ID | CAN_RTR_FLAG); + if (write(s, &frame, sizeof(frame)) < 0) { + perror("write"); + exit(1); + } + frame.can_id = (ID | CAN_EFF_FLAG); + if (write(s, &frame, sizeof(frame)) < 0) { + perror("write"); + exit(1); + } + frame.can_id = (ID | CAN_EFF_FLAG | CAN_RTR_FLAG); + if (write(s, &frame, sizeof(frame)) < 0) { + perror("write"); + exit(1); + } + + printf("ok\n"); + + have_rx = 1; + rx = 0; + rxbits = 0; + + while (have_rx) { + + have_rx = 0; + FD_ZERO(&rdfs); + FD_SET(s, &rdfs); + tv.tv_sec = 0; + tv.tv_usec = 50000; /* 50ms timeout */ + + ret = select(s+1, &rdfs, NULL, NULL, &tv); + if (ret < 0) { + perror("select"); + exit(1); + } + + if (FD_ISSET(s, &rdfs)) { + have_rx = 1; + ret = read(s, &frame, sizeof(struct can_frame)); + if (ret < 0) { + perror("read"); + exit(1); + } + if ((frame.can_id & CAN_SFF_MASK) != ID) { + fprintf(stderr, "received wrong can_id!\n"); + exit(1); + } + if (frame.data[0] != testcase) { + fprintf(stderr, "received wrong testcase!\n"); + exit(1); + } + + /* test & calc rxbits */ + rxbitval = 1 << ((frame.can_id & (CAN_EFF_FLAG|CAN_RTR_FLAG|CAN_ERR_FLAG)) >> 28); + + /* only receive a rxbitval once */ + if ((rxbits & rxbitval) == rxbitval) { + fprintf(stderr, "received rxbitval %d twice!\n", rxbitval); + exit(1); + } + rxbits |= rxbitval; + rx++; + + printf("testcase %2d rx : can_id = 0x%08X rx = %d rxbits = %d\n", + testcase, frame.can_id, rx, rxbits); + } + } + /* rx timed out -> check the received results */ + if (rx_res[testcase] != rx) { + fprintf(stderr, "wrong rx value in testcase %d : %d (expected %d)\n", + testcase, rx, rx_res[testcase]); + exit(1); + } + if (rxbits_res[testcase] != rxbits) { + fprintf(stderr, "wrong rxbits value in testcase %d : %d (expected %d)\n", + testcase, rxbits, rxbits_res[testcase]); + exit(1); + } + printf("testcase %2d ok\n---\n", testcase); + } + +out_socket: + close(s); +out: + return err; +} diff --git a/tools/testing/selftests/net/can/test_raw_filter.sh b/tools/testing/selftests/net/can/test_raw_filter.sh new file mode 100755 index 000000000000..e5f175c8b27b --- /dev/null +++ b/tools/testing/selftests/net/can/test_raw_filter.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +#set -x + +ALL_TESTS=" + test_raw_filter +" + +net_dir=$(dirname $0)/.. +source $net_dir/lib.sh + +VCANIF="vcan0" + +setup() +{ + ip link add name $VCANIF type vcan || exit $ksft_skip + ip link set dev $VCANIF up + pwd +} + +cleanup() +{ + ip link delete $VCANIF +} + +test_raw_filter() +{ + ./test_raw_filter +} + +trap cleanup EXIT +setup + +tests_run + +exit $EXIT_STATUS