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
14 #define ID 0x123
15 #define TC 18 /* # of testcases */
16
17 const int rx_res[TC] = { 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1 };
18 const int rxbits_res[TC] = { 4369, 4369, 4369, 4369, 17, 4352, 17, 4352, 257,
19 257, 4112, 4112, 1, 256, 16, 4096, 1, 256 };
20
21 static int s;
22
calc_id(int testcase)23 static canid_t calc_id(int testcase)
24 {
25 canid_t id = ID;
26
27 if (testcase & 1)
28 id |= CAN_EFF_FLAG;
29 if (testcase & 2)
30 id |= CAN_RTR_FLAG;
31
32 return id;
33 }
34
calc_mask(int testcase)35 static canid_t calc_mask(int testcase)
36 {
37 canid_t mask = CAN_SFF_MASK;
38
39 if (testcase > 15)
40 return CAN_EFF_MASK | CAN_EFF_FLAG | CAN_RTR_FLAG;
41
42 if (testcase & 4)
43 mask |= CAN_EFF_FLAG;
44 if (testcase & 8)
45 mask |= CAN_RTR_FLAG;
46
47 return mask;
48 }
49
setup(void)50 static void setup(void)
51 {
52 struct sockaddr_can addr;
53 struct ifreq ifr;
54 int recv_own_msgs = 1;
55
56 can_setup_vcan();
57
58 s = SAFE_SOCKET(PF_CAN, SOCK_RAW, CAN_RAW);
59
60 strcpy(ifr.ifr_name, can_dev_name);
61 SAFE_IOCTL(s, SIOCGIFINDEX, &ifr);
62
63 addr.can_family = AF_CAN;
64 addr.can_ifindex = ifr.ifr_ifindex;
65
66 SAFE_SETSOCKOPT(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS,
67 &recv_own_msgs, sizeof(recv_own_msgs));
68
69 SAFE_BIND(s, (struct sockaddr *)&addr, sizeof(addr));
70 }
71
cleanup(void)72 static void cleanup(void)
73 {
74 if (s)
75 SAFE_CLOSE(s);
76
77 can_cleanup_vcan();
78 }
79
run(unsigned int n)80 static void run(unsigned int n)
81 {
82 fd_set rdfs;
83 struct timeval tv;
84 struct can_frame frame;
85 static struct can_filter rfilter;
86 int testcase = n;
87 int have_rx = 1;
88 int rx = 0;
89 int rxbits = 0, rxbitval;
90
91 rfilter.can_id = calc_id(testcase);
92 rfilter.can_mask = calc_mask(testcase);
93 SAFE_SETSOCKOPT(s, SOL_CAN_RAW, CAN_RAW_FILTER,
94 &rfilter, sizeof(rfilter));
95
96 tst_res(TINFO, "testcase %2d filters : can_id = 0x%08X can_mask = "
97 "0x%08X", testcase, rfilter.can_id, rfilter.can_mask);
98
99 tst_res(TINFO, "testcase %2d sending patterns ... ", testcase);
100
101 frame.can_dlc = 1;
102 frame.data[0] = testcase;
103
104 frame.can_id = ID;
105 SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame));
106
107 frame.can_id = (ID | CAN_RTR_FLAG);
108 SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame));
109
110 frame.can_id = (ID | CAN_EFF_FLAG);
111 SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame));
112
113 frame.can_id = (ID | CAN_EFF_FLAG | CAN_RTR_FLAG);
114 SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame));
115
116 tst_res(TPASS, "testcase %2d Sent patterns", testcase);
117
118 while (have_rx) {
119
120 have_rx = 0;
121 FD_ZERO(&rdfs);
122 FD_SET(s, &rdfs);
123 tv.tv_sec = 0;
124 tv.tv_usec = 50000; /* 50ms timeout */
125
126 if (select(s + 1, &rdfs, NULL, NULL, &tv) < 0)
127 tst_brk(TBROK | TERRNO, "select");
128
129 if (FD_ISSET(s, &rdfs)) {
130 have_rx = 1;
131 SAFE_READ(1, s, &frame, sizeof(struct can_frame));
132
133 if ((frame.can_id & CAN_SFF_MASK) != ID)
134 tst_res(TFAIL, "received wrong can_id!");
135
136 if (frame.data[0] != testcase)
137 tst_res(TFAIL, "received wrong testcase!");
138
139 /* test & calc rxbits */
140 rxbitval = 1 << ((frame.can_id &
141 (CAN_EFF_FLAG | CAN_RTR_FLAG |
142 CAN_ERR_FLAG)) >> 28);
143
144 /* only receive a rxbitval once */
145 if ((rxbits & rxbitval) == rxbitval) {
146 tst_res(TFAIL, "received rxbitval %d twice!",
147 rxbitval);
148 }
149 rxbits |= rxbitval;
150 rx++;
151
152 tst_res(TINFO, "testcase %2d rx : can_id = 0x%08X rx = "
153 "%d rxbits = %d", testcase,
154 frame.can_id, rx, rxbits);
155 }
156 }
157 /* rx timed out -> check the received results */
158 if (rx_res[testcase] != rx) {
159 tst_brk(TBROK,
160 "wrong rx value in testcase %d : %d (expected "
161 "%d)", testcase, rx, rx_res[testcase]);
162 }
163 if (rxbits_res[testcase] != rxbits) {
164 tst_brk(TBROK,
165 "wrong rxbits value in testcase %d : %d "
166 "(expected %d)", testcase, rxbits,
167 rxbits_res[testcase]);
168 }
169 tst_res(TPASS, "testcase %2d ok", testcase);
170 }
171
172 static struct tst_test test = {
173 .tcnt = TC,
174 .options = (struct tst_option[]) {
175 {"d:", &can_dev_name, "CAN device name"},
176 {}
177 },
178 .setup = setup,
179 .cleanup = cleanup,
180 .test = run,
181 .caps = (struct tst_cap []) {
182 TST_CAP(TST_CAP_REQ, CAP_NET_RAW),
183 TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN),
184 {}
185 },
186 .needs_drivers = (const char *const[]) {
187 "vcan",
188 "can-raw",
189 NULL
190 }
191 };
192
193 #else
194
195 TST_TEST_TCONF("The linux/can.h was missing upon compilation");
196
197 #endif /* HAVE_LINUX_CAN_H */
198