Skip to content

Commit 9145b6e

Browse files
ioctl: add tests for ethtool ioctl
JIRA: RTOS-1014
1 parent fc40010 commit 9145b6e

File tree

1 file changed

+228
-14
lines changed

1 file changed

+228
-14
lines changed

ioctl/test-ioctl-special.c

Lines changed: 228 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* Tests for special ioctls:
55
* - SIOCIFCONF
6+
* - SIOCETHTOOL
67
*
78
* (special - passed structure has a pointer
89
* to arbitrary memory -> needs flattening
@@ -16,38 +17,77 @@
1617
* %LICENSE%
1718
*/
1819
#include <errno.h>
20+
#include <stdbool.h>
1921
#include <stdio.h>
20-
#include <unistd.h>
2122
#include <stdlib.h>
2223
#include <string.h>
2324
#include <sys/ioctl.h>
25+
#include <unistd.h>
2426

25-
#include <sys/socket.h>
26-
#include <net/if.h>
2727
#include <arpa/inet.h>
28+
#include <ifaddrs.h>
29+
#include <net/if.h>
30+
#include <sys/socket.h>
31+
32+
#include <phoenix/ethtool.h>
2833

2934
#include "unity_fixture.h"
3035

31-
#define GET_IFADDRS(fd, ifc_ptr) \
32-
do { \
33-
TEST_ASSERT_EQUAL_MESSAGE(0, ioctl(fd, SIOCGIFCONF, (ifc_ptr)), strerror(errno)); \
34-
(ifc_ptr)->ifc_req = malloc((ifc_ptr)->ifc_len); \
35-
TEST_ASSERT_NOT_NULL_MESSAGE((ifc_ptr)->ifc_req, strerror(errno)); \
36-
TEST_ASSERT_EQUAL_MESSAGE(0, ioctl(fd, SIOCGIFCONF, (ifc_ptr)), strerror(errno)); \
37-
} while (0)
36+
#define ERR_MSG_LEN 64
3837

3938

4039
static int fd = -1;
40+
static struct ifconf ifc;
4141
static struct ifconf current_ifc;
42+
static struct ifreq current_ifr;
43+
44+
45+
static inline int get_ifconf(int fd, struct ifconf *ifc)
46+
{
47+
int err = ioctl(fd, SIOCGIFCONF, ifc);
48+
if (err < 0) {
49+
return -1;
50+
}
51+
52+
ifc->ifc_req = malloc(ifc->ifc_len);
53+
if (ifc->ifc_req == NULL) {
54+
return -1;
55+
}
56+
57+
err = ioctl(fd, SIOCGIFCONF, ifc);
58+
if (err < 0) {
59+
return -1;
60+
}
61+
62+
return 0;
63+
}
64+
65+
66+
/* returns: 0 or errno on success, -1 on fail */
67+
static inline int ethtool_ioctl(struct ifreq *ifr, void *ethtool_struct, uint32_t cmd, char *err_msg_buf)
68+
{
69+
*((uint32_t *)ethtool_struct) = cmd;
70+
ifr->ifr_data = (void *)ethtool_struct;
71+
if (ioctl(fd, SIOCETHTOOL, ifr) < 0) {
72+
if (errno == ENXIO) {
73+
snprintf(err_msg_buf, ERR_MSG_LEN, "Interface '%.*s', not found", IFNAMSIZ, ifr->ifr_name);
74+
return -1;
75+
}
76+
if (errno == EOPNOTSUPP) {
77+
return EOPNOTSUPP;
78+
}
79+
snprintf(err_msg_buf, ERR_MSG_LEN, "Interface '%.*s': %s", IFNAMSIZ, ifr->ifr_name, strerror(errno));
80+
return -1;
81+
}
82+
return 0;
83+
}
4284

4385

4486
TEST_GROUP(test_ioctl_special);
4587

4688

4789
TEST_SETUP(test_ioctl_special)
4890
{
49-
fd = socket(AF_INET, SOCK_STREAM, 0);
50-
TEST_ASSERT_GREATER_OR_EQUAL_MESSAGE(0, fd, strerror(errno));
5191
}
5292

5393

@@ -62,7 +102,7 @@ TEST_TEAR_DOWN(test_ioctl_special)
62102

63103
TEST(test_ioctl_special, ifconf)
64104
{
65-
GET_IFADDRS(fd, &current_ifc);
105+
TEST_ASSERT_EQUAL_MESSAGE(0, get_ifconf(fd, &current_ifc), strerror(errno));
66106
}
67107

68108

@@ -84,10 +124,164 @@ TEST(test_ioctl_special, ifconf_not_enough_space)
84124
}
85125

86126

127+
TEST(test_ioctl_special, ethtool_gset)
128+
{
129+
struct ethtool_cmd cmd = { 0 };
130+
char err_msg_buf[ERR_MSG_LEN] = { 0 };
131+
132+
int err = ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_GSET, err_msg_buf);
133+
if (err == EOPNOTSUPP) {
134+
TEST_IGNORE_MESSAGE("Operation not supported for this interface");
135+
}
136+
else if (err < 0) {
137+
TEST_FAIL_MESSAGE(err_msg_buf);
138+
}
139+
}
140+
141+
142+
TEST(test_ioctl_special, ethtool_sset)
143+
{
144+
int err = 0;
145+
int last_port = -1;
146+
struct ethtool_cmd cmd = { 0 };
147+
char err_msg_buf[ERR_MSG_LEN] = { 0 };
148+
do {
149+
err = ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_GSET, err_msg_buf);
150+
if (err == EOPNOTSUPP) {
151+
TEST_IGNORE_MESSAGE("Operation not supported for this interface");
152+
}
153+
else if (err < 0) {
154+
break;
155+
}
156+
157+
last_port = cmd.port;
158+
cmd.port = 123;
159+
err = ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_SSET, err_msg_buf);
160+
if (err == EOPNOTSUPP) {
161+
TEST_IGNORE_MESSAGE("Operation not supported for this interface");
162+
}
163+
else if (err < 0) {
164+
break;
165+
}
166+
TEST_ASSERT_EQUAL(123, cmd.port);
167+
168+
} while (0);
169+
170+
if (last_port != -1) {
171+
cmd.port = last_port;
172+
(void)ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_SSET, err_msg_buf);
173+
}
174+
if (err < 0) {
175+
TEST_FAIL_MESSAGE(err_msg_buf);
176+
}
177+
}
178+
179+
180+
TEST(test_ioctl_special, ethtool_test)
181+
{
182+
struct ethtool_test cmd = { 0 };
183+
char err_msg_buf[ERR_MSG_LEN] = { 0 };
184+
cmd.flags = ETH_TEST_FL_OFFLINE;
185+
186+
int err = ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_TEST, err_msg_buf);
187+
if (err == EOPNOTSUPP) {
188+
TEST_IGNORE_MESSAGE("Operation not supported for this interface");
189+
}
190+
else if (err < 0) {
191+
TEST_FAIL_MESSAGE(err_msg_buf);
192+
}
193+
TEST_ASSERT_EQUAL_MESSAGE(0, cmd.flags & ETH_TEST_FL_FAILED, "driver PHYSELFTEST failed");
194+
}
195+
196+
197+
TEST(test_ioctl_special, ethtool_gloopback)
198+
{
199+
struct ethtool_value cmd = { 0 };
200+
char err_msg_buf[ERR_MSG_LEN] = { 0 };
201+
202+
int err = ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_GLOOPBACK, err_msg_buf);
203+
if (err == EOPNOTSUPP) {
204+
TEST_IGNORE_MESSAGE("Operation not supported for this interface");
205+
}
206+
else if (err < 0) {
207+
TEST_FAIL_MESSAGE(err_msg_buf);
208+
}
209+
}
210+
211+
212+
TEST(test_ioctl_special, ethtool_sloopback)
213+
{
214+
int err = 0;
215+
int last_loopback = -1;
216+
struct ethtool_value cmd = { 0 };
217+
char err_msg_buf[ERR_MSG_LEN] = { 0 };
218+
219+
do {
220+
err = ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_GLOOPBACK, err_msg_buf);
221+
if (err == EOPNOTSUPP) {
222+
TEST_IGNORE_MESSAGE("Operation not supported for this interface");
223+
}
224+
else if (err < 0) {
225+
break;
226+
}
227+
last_loopback = cmd.data;
228+
uint32_t expected = (cmd.data != 0) ? ETH_PHY_LOOPBACK_DISABLED : ETH_PHY_LOOPBACK_ENABLED;
229+
230+
cmd.data = expected;
231+
err = ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_SLOOPBACK, err_msg_buf);
232+
if (err == EOPNOTSUPP) {
233+
TEST_IGNORE_MESSAGE("Operation not supported for this interface");
234+
}
235+
if (err < 0) {
236+
break;
237+
}
238+
239+
if (cmd.data == ETH_PHY_LOOPBACK_SET_FAILED) {
240+
snprintf(err_msg_buf, ERR_MSG_LEN, "Interface %.*s: couldn't set loopback", IFNAMSIZ, current_ifr.ifr_name);
241+
err = -1;
242+
break;
243+
}
244+
245+
cmd.data = 0;
246+
err = ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_GLOOPBACK, err_msg_buf);
247+
if (err == EOPNOTSUPP) {
248+
TEST_IGNORE_MESSAGE("Operation not supported for this interface");
249+
}
250+
else if (err < 0) {
251+
break;
252+
}
253+
else if (cmd.data != expected) {
254+
snprintf(err_msg_buf, ERR_MSG_LEN, "Interface %.*s: loopback set incorrectly", IFNAMSIZ, current_ifr.ifr_name);
255+
err = -1;
256+
break;
257+
}
258+
} while (0);
259+
260+
if (last_loopback != -1) {
261+
cmd.data = last_loopback;
262+
(void)ethtool_ioctl(&current_ifr, &cmd, ETHTOOL_SLOOPBACK, err_msg_buf);
263+
}
264+
265+
if (err < 0) {
266+
TEST_FAIL_MESSAGE(err_msg_buf);
267+
}
268+
}
269+
270+
87271
TEST_GROUP_RUNNER(test_ioctl_special)
88272
{
89273
RUN_TEST_CASE(test_ioctl_special, ifconf);
90274
RUN_TEST_CASE(test_ioctl_special, ifconf_not_enough_space);
275+
276+
for (int i = 0; i < (ifc.ifc_len / sizeof(struct ifreq)); i++) {
277+
current_ifr = ifc.ifc_req[i];
278+
fprintf(stderr, "IF: %.*s\n", IFNAMSIZ, current_ifr.ifr_name);
279+
RUN_TEST_CASE(test_ioctl_special, ethtool_gset);
280+
RUN_TEST_CASE(test_ioctl_special, ethtool_sset);
281+
RUN_TEST_CASE(test_ioctl_special, ethtool_test);
282+
RUN_TEST_CASE(test_ioctl_special, ethtool_gloopback);
283+
RUN_TEST_CASE(test_ioctl_special, ethtool_sloopback);
284+
}
91285
}
92286

93287

@@ -99,5 +293,25 @@ void runner(void)
99293

100294
int main(int argc, char *argv[])
101295
{
102-
return (UnityMain(argc, (const char **)argv, runner) == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
296+
int err;
297+
fd = socket(AF_INET, SOCK_STREAM, 0);
298+
if (fd < 0) {
299+
perror("Couldn't open socket");
300+
return EXIT_FAILURE;
301+
}
302+
303+
if (get_ifconf(fd, &ifc) < 0) {
304+
perror("Couldn't get ifconf");
305+
return EXIT_FAILURE;
306+
}
307+
308+
err = UnityMain(argc, (const char **)argv, runner);
309+
if (ifc.ifc_req != NULL) {
310+
free(ifc.ifc_req);
311+
}
312+
if (fd != -1) {
313+
close(fd);
314+
}
315+
316+
return (err == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
103317
}

0 commit comments

Comments
 (0)