33 *
44 * Tests for special ioctls:
55 * - SIOCIFCONF
6+ * - SIOCETHTOOL
67 *
78 * (special - passed structure has a pointer
89 * to arbitrary memory -> needs flattening
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
4039static int fd = -1 ;
40+ static struct ifconf ifc ;
4141static 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
4486TEST_GROUP (test_ioctl_special );
4587
4688
4789TEST_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
63103TEST (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+
87271TEST_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
100294int 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