1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 /*
3 * Copyright (c) 2011 Volkswagen Group Electronic Research
4 * Copyright (c) 2021 SUSE LLC
5 */
6
7 #include "config.h"
8 #include "tst_test.h"
9
10 #ifdef HAVE_LINUX_CAN_H
11
12 #include "can_common.h"
13 #include "tst_minmax.h"
14
15 static int s, t;
16
test_sockets(canid_t can_id,int expect_rxs,int expect_rxt)17 static void test_sockets(canid_t can_id, int expect_rxs, int expect_rxt)
18 {
19 fd_set rdfs;
20 struct timeval tv;
21 int m = MAX(s, t) + 1;
22 int have_rx = 1;
23 struct can_frame frame;
24 int rxs = 0, rxt = 0;
25
26 frame.can_id = can_id;
27 frame.can_dlc = 0;
28 SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame));
29
30 while (have_rx) {
31
32 FD_ZERO(&rdfs);
33 FD_SET(s, &rdfs);
34 FD_SET(t, &rdfs);
35 tv.tv_sec = 0;
36 tv.tv_usec = 50000; /* 50ms timeout */
37 have_rx = 0;
38
39 if (select(m, &rdfs, NULL, NULL, &tv) < 0)
40 tst_brk(TBROK | TERRNO, "select");
41
42 if (FD_ISSET(s, &rdfs)) {
43
44 have_rx = 1;
45 SAFE_READ(1, s, &frame, sizeof(struct can_frame));
46
47 if (frame.can_id != can_id)
48 tst_res(TFAIL, "received wrong can_id!");
49
50 rxs++;
51 }
52
53 if (FD_ISSET(t, &rdfs)) {
54
55 have_rx = 1;
56 SAFE_READ(1, t, &frame, sizeof(struct can_frame));
57
58 if (frame.can_id != can_id)
59 tst_res(TFAIL, "received wrong can_id!");
60
61 rxt++;
62 }
63 }
64
65 /* timeout */
66
67 tst_res(rxs == expect_rxs && rxt == expect_rxt ? TPASS : TFAIL,
68 "s received %d of %d, t received %d of %d",
69 rxs, expect_rxs, rxt, expect_rxt);
70 }
71
setopts(int loopback,int recv_own_msgs)72 static void setopts(int loopback, int recv_own_msgs)
73 {
74 SAFE_SETSOCKOPT(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback,
75 sizeof(loopback));
76 SAFE_SETSOCKOPT(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &recv_own_msgs,
77 sizeof(recv_own_msgs));
78
79 tst_res(TINFO, "set loopback = %d, recv_own_msgs = %d",
80 loopback, recv_own_msgs);
81 }
82
setup(void)83 static void setup(void)
84 {
85 struct sockaddr_can addr;
86 struct ifreq ifr;
87
88 can_setup_vcan();
89
90 s = SAFE_SOCKET(PF_CAN, SOCK_RAW, CAN_RAW);
91 t = SAFE_SOCKET(PF_CAN, SOCK_RAW, CAN_RAW);
92
93 strcpy(ifr.ifr_name, can_dev_name);
94 SAFE_IOCTL(s, SIOCGIFINDEX, &ifr);
95
96 addr.can_ifindex = ifr.ifr_ifindex;
97 addr.can_family = AF_CAN;
98
99 SAFE_BIND(s, (struct sockaddr *)&addr, sizeof(addr));
100 SAFE_BIND(t, (struct sockaddr *)&addr, sizeof(addr));
101 }
102
cleanup(void)103 static void cleanup(void)
104 {
105 if (s)
106 SAFE_CLOSE(s);
107 if (t)
108 SAFE_CLOSE(t);
109
110 can_cleanup_vcan();
111 }
112
run(void)113 static void run(void)
114 {
115 tst_res(TINFO, "Starting PF_CAN frame flow test.");
116 tst_res(TINFO, "checking socket default settings");
117 test_sockets(0x340, 0, 1);
118
119 setopts(0, 0);
120 test_sockets(0x341, 0, 0);
121
122 setopts(0, 1);
123 test_sockets(0x342, 0, 0);
124
125 setopts(1, 0);
126 test_sockets(0x343, 0, 1);
127
128 setopts(1, 1);
129 test_sockets(0x344, 1, 1);
130
131 /* Return to defaults for when -i is used */
132 setopts(1, 0);
133 }
134
135 static struct tst_test test = {
136 .options = (struct tst_option[]) {
137 {"D:", &can_dev_name, "CAN device name"},
138 {}
139 },
140 .setup = setup,
141 .cleanup = cleanup,
142 .test_all = run,
143 .caps = (struct tst_cap []) {
144 TST_CAP(TST_CAP_REQ, CAP_NET_RAW),
145 TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN),
146 {}
147 },
148 .needs_drivers = (const char *const[]) {
149 "vcan",
150 "can-raw",
151 NULL
152 }
153 };
154
155 #else
156
157 TST_TEST_TCONF("The linux/can.h was missing upon compilation");
158
159 #endif /* HAVE_LINUX_CAN_H */
160