• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * Test cases for ethtool features
3  * Copyright 2012 Solarflare Communications Inc.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 as published
7  * by the Free Software Foundation, incorporated herein by reference.
8  */
9 
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #define TEST_NO_WRAPPERS
15 #include "internal.h"
16 
17 static const struct {
18 	struct ethtool_sset_info cmd;
19 	u32 data[1];
20 }
21 cmd_gssetinfo = { { ETHTOOL_GSSET_INFO, 0, 1ULL << ETH_SS_FEATURES }, { 34 } };
22 
23 static const struct ethtool_value
24 cmd_grxcsum_off = { ETHTOOL_GRXCSUM, 0 },
25 cmd_grxcsum_on = { ETHTOOL_GRXCSUM, 1 },
26 cmd_srxcsum_off = { ETHTOOL_SRXCSUM, 0 },
27 cmd_srxcsum_on = { ETHTOOL_SRXCSUM, 1 },
28 cmd_gtxcsum_off = { ETHTOOL_GTXCSUM, 0 },
29 cmd_gtxcsum_on = { ETHTOOL_GTXCSUM, 1 },
30 cmd_stxcsum_off = { ETHTOOL_STXCSUM, 0 },
31 cmd_stxcsum_on = { ETHTOOL_STXCSUM, 1 },
32 cmd_gsg_off = { ETHTOOL_GSG, 0 },
33 cmd_gsg_on = { ETHTOOL_GSG, 1 },
34 cmd_ssg_off = { ETHTOOL_SSG, 0 },
35 cmd_ssg_on = { ETHTOOL_SSG, 1 },
36 cmd_gtso_off = { ETHTOOL_GTSO, 0 },
37 cmd_gtso_on = { ETHTOOL_GTSO, 1 },
38 cmd_stso_off = { ETHTOOL_STSO, 0 },
39 cmd_stso_on = { ETHTOOL_STSO, 1 },
40 cmd_gufo_off = { ETHTOOL_GUFO, 0 },
41 cmd_gufo_on = { ETHTOOL_GUFO, 1 },
42 cmd_sufo_off = { ETHTOOL_SUFO, 0 },
43 cmd_sufo_on = { ETHTOOL_SUFO, 1 },
44 cmd_ggso_off = { ETHTOOL_GGSO, 0 },
45 cmd_ggso_on = { ETHTOOL_GGSO, 1 },
46 cmd_sgso_off = { ETHTOOL_SGSO, 0 },
47 cmd_sgso_on = { ETHTOOL_SGSO, 1 },
48 cmd_ggro_off = { ETHTOOL_GGRO, 0 },
49 cmd_ggro_on = { ETHTOOL_GGRO, 1 },
50 cmd_sgro_off = { ETHTOOL_SGRO, 0 },
51 cmd_sgro_on = { ETHTOOL_SGRO, 1 },
52 cmd_gflags_off = { ETHTOOL_GFLAGS, 0 },
53 cmd_gflags_on = { ETHTOOL_GFLAGS,
54 		  ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
55 		  ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH },
56 cmd_sflags_off = { ETHTOOL_SFLAGS, 0 },
57 cmd_sflags_ntuple = { ETHTOOL_GFLAGS, ETH_FLAG_NTUPLE },
58 cmd_sflags_on = { ETHTOOL_SFLAGS,
59 		  ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
60 		  ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH },
61 cmd_sflags_not_rxhash = { ETHTOOL_SFLAGS,
62 			  ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
63 			  ETH_FLAG_NTUPLE };
64 
65 static const struct cmd_expect cmd_expect_get_strings_old[] = {
66 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
67 	{ 0, 0, 0, 0, 0 }
68 };
69 
70 static const struct cmd_expect cmd_expect_get_features_off_old[] = {
71 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
72 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
73 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
74 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
75 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
76 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
77 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
78 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
79 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
80 	{ 0, 0, 0, 0, 0 }
81 };
82 
83 static const struct cmd_expect cmd_expect_get_features_off_old_some_unsup[] = {
84 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
85 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
86 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
87 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
88 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
89 	{ &cmd_gufo_off, 4, -EOPNOTSUPP },
90 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
91 	{ &cmd_ggro_off, 4, -EOPNOTSUPP },
92 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
93 	{ 0, 0, 0, 0, 0 }
94 };
95 
96 static const struct cmd_expect cmd_expect_get_features_off_old_some_priv[] = {
97 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EPERM },
98 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
99 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
100 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
101 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
102 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
103 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
104 	{ &cmd_ggro_off, 4, -EPERM },
105 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
106 	{ 0, 0, 0, 0, 0 }
107 };
108 
109 static const struct cmd_expect cmd_expect_set_features_off_old[] = {
110 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
111 	{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
112 	{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
113 	{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
114 	{ &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
115 	{ &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
116 	{ &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
117 	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
118 	{ &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
119 	{ &cmd_srxcsum_off, sizeof(cmd_srxcsum_off), 0, 0, 0 },
120 	{ &cmd_stxcsum_off, sizeof(cmd_stxcsum_off), 0, 0, 0 },
121 	{ &cmd_ssg_off, sizeof(cmd_ssg_off), 0, 0, 0 },
122 	{ &cmd_stso_off, sizeof(cmd_stso_off), 0, 0, 0 },
123 	{ &cmd_sufo_off, sizeof(cmd_sufo_off), 0, 0, 0 },
124 	{ &cmd_sgso_off, sizeof(cmd_sgso_off), 0, 0, 0 },
125 	{ &cmd_sgro_off, sizeof(cmd_sgro_off), 0, 0, 0 },
126 	{ &cmd_sflags_off, sizeof(cmd_sflags_off), 0, 0, 0 },
127 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
128 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
129 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
130 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
131 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
132 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
133 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
134 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_sflags_off) },
135 	{ 0, 0, 0, 0, 0 }
136 };
137 
138 static const struct cmd_expect cmd_expect_set_features_on_old[] = {
139 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
140 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
141 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
142 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
143 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
144 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
145 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
146 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
147 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
148 	{ &cmd_srxcsum_on, sizeof(cmd_srxcsum_on), 0, 0, 0 },
149 	{ &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), 0, 0, 0 },
150 	{ &cmd_ssg_on, sizeof(cmd_ssg_on), 0, 0, 0 },
151 	{ &cmd_stso_on, sizeof(cmd_stso_on), 0, 0, 0 },
152 	{ &cmd_sufo_on, sizeof(cmd_sufo_on), 0, 0, 0 },
153 	{ &cmd_sgso_on, sizeof(cmd_sgso_on), 0, 0, 0 },
154 	{ &cmd_sgro_on, sizeof(cmd_sgro_on), 0, 0, 0 },
155 	{ &cmd_sflags_on, sizeof(cmd_sflags_on), 0, 0, 0 },
156 	{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
157 	{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
158 	{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
159 	{ &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
160 	{ &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
161 	{ &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
162 	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
163 	{ &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
164 	{ 0, 0, 0, 0, 0 }
165 };
166 
167 static const struct cmd_expect cmd_expect_set_features_unsup_on_old[] = {
168 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd), -EINVAL },
169 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
170 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
171 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
172 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
173 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
174 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
175 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
176 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
177 	{ &cmd_stxcsum_on, sizeof(cmd_stxcsum_on), -EOPNOTSUPP },
178 	{ 0, 0, 0, 0, 0 }
179 };
180 
181 static const struct {
182 	struct ethtool_gstrings cmd;
183 	u8 data[34][ETH_GSTRING_LEN];
184 }
185 cmd_gstrings = {
186 	{ ETHTOOL_GSTRINGS, ETH_SS_FEATURES, 34 },
187 	{
188 		"tx-scatter-gather",
189 		"tx-checksum-ipv4",
190 		"",
191 		"tx-checksum-ip-generic",
192 		"tx-checksum-ipv6",
193 		"highdma",
194 		"tx-scatter-gather-fraglist",
195 		"tx-vlan-hw-insert",
196 		"rx-vlan-hw-parse",
197 		"rx-vlan-filter",
198 		"vlan-challenged",
199 		"tx-generic-segmentation",
200 		"tx-lockless",
201 		"netns-local",
202 		"rx-gro",
203 		"rx-lro",
204 		"tx-tcp-segmentation",
205 		"tx-udp-fragmentation",
206 		"tx-gso-robust",
207 		"tx-tcp-ecn-segmentation",
208 		"tx-tcp6-segmentation",
209 		"tx-fcoe-segmentation",
210 		"",
211 		"",
212 		"tx-checksum-fcoe-crc",
213 		"tx-checksum-sctp",
214 		"fcoe-mtu",
215 		"rx-ntuple-filter",
216 		"rx-hashing",
217 		"rx-checksum",
218 		"tx-nocache-copy",
219 		"loopback",
220 		"rx-fcs",
221 		"rx-all",
222 	}
223 };
224 
225 static const struct {
226 	struct ethtool_gfeatures cmd;
227 	struct ethtool_get_features_block data[2];
228 }
229 			    /* available   requested   active   never_changed */
230 /* minimal: only GRO and GSO are available (and GSO won't work) */
231 cmd_gfeatures_min_off =   { { ETHTOOL_GFEATURES, 2 },
232 			    {{ 0x00004800, 0x00000000, 0x00000000, 0x00003400},
233 			     { 0x00000000, 0x00000000, 0x00000000, 0x00000000}}
234 },
235 cmd_gfeatures_min_on =    { { ETHTOOL_GFEATURES, 2 },
236 			    {{ 0x00004800, 0x00004800, 0x00004000, 0x00003400},
237 			     { 0x00000000, 0x00000000, 0x00000000, 0x00000000}}
238 },
239 /* maximal: everything that isn't never-changed is available */
240 cmd_gfeatures_max_off =   { { ETHTOOL_GFEATURES, 2 },
241 			    {{ 0xffffcbff, 0x00000000, 0x00000000, 0x00003400 },
242 			     { 0x00000003, 0x00000000, 0x00000000, 0x00000000 }}
243 },
244 cmd_gfeatures_max_on =    { { ETHTOOL_GFEATURES, 2 },
245 			    {{ 0xffffcbff, 0xffffcbff, 0xffffcbff, 0x00003400 },
246 			     { 0x00000003, 0x00000003, 0x00000003, 0x00000000 }}
247 },
248 /* IPv4: GRO, GSO, SG and some IPv4-specific offloads are available */
249 cmd_gfeatures_ipv4_off =  { { ETHTOOL_GFEATURES, 2 },
250 			    {{ 0x00014803, 0x00000000, 0x00000000, 0x00003400 },
251 			     { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }}
252 },
253 cmd_gfeatures_ipv4_on =   { { ETHTOOL_GFEATURES, 2 },
254 			    {{ 0x00014803, 0x00014803, 0x00014803, 0x00003400 },
255 			     { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }}
256 };
257 
258 static const struct {
259 	struct ethtool_sfeatures cmd;
260 	struct ethtool_set_features_block data[2];
261 }
262 			    /* valid       requested */
263 cmd_sfeatures_min_on =   { { ETHTOOL_SFEATURES, 2 },
264 			    {{ 0x00004800, 0x00004800 },
265 			     { 0x00000000, 0x00000000 }} },
266 cmd_sfeatures_min_off =  { { ETHTOOL_SFEATURES, 2 },
267 			    {{ 0x00004800, 0x00000000 },
268 			     { 0x00000000, 0x00000000 }} },
269 cmd_sfeatures_noop =     { { ETHTOOL_SFEATURES, 2 },
270 			    {{ 0x00000000, 0x00000000 },
271 			     { 0x00000000, 0x00000000 }} },
272 cmd_sfeatures_ipv4_on =  { { ETHTOOL_SFEATURES, 2 },
273 			    {{ 0x00014803, 0x00014803 },
274 			     { 0x00000000, 0x00000000 }} };
275 
276 static const struct cmd_expect cmd_expect_get_strings[] = {
277 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
278 	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
279 	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
280 	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
281 	{ 0, 0, 0, 0, 0 }
282 };
283 
284 static const struct cmd_expect cmd_expect_get_features_min_off[] = {
285 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
286 	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
287 	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
288 	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
289 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
290 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
291 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
292 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
293 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
294 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
295 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
296 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
297 	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
298 	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
299 	{ 0, 0, 0, 0, 0 }
300 };
301 
302 static const struct cmd_expect cmd_expect_get_features_max_on[] = {
303 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
304 	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
305 	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
306 	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
307 	{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
308 	{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
309 	{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
310 	{ &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
311 	{ &cmd_gufo_on, 4, 0, &cmd_gufo_on, sizeof(cmd_gufo_on) },
312 	{ &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
313 	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
314 	{ &cmd_gflags_on, 4, 0, &cmd_gflags_on, sizeof(cmd_sflags_on) },
315 	{ &cmd_gfeatures_max_on, sizeof(cmd_gfeatures_max_on.cmd),
316 	  0, &cmd_gfeatures_max_on, sizeof(cmd_gfeatures_max_on) },
317 	{ 0, 0, 0, 0, 0 }
318 };
319 
320 static const struct cmd_expect cmd_expect_set_features_min_off_min_on[] = {
321 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
322 	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
323 	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
324 	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
325 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
326 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
327 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
328 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
329 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
330 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
331 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
332 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
333 	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
334 	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
335 	{ &cmd_sfeatures_min_on, sizeof(cmd_sfeatures_min_on),
336 	  ETHTOOL_F_WISH, 0, 0 },
337 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
338 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
339 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
340 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
341 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
342 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
343 	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
344 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
345 	{ &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on.cmd),
346 	  0, &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on) },
347 	{ 0, 0, 0, 0, 0 }
348 };
349 
350 static const struct cmd_expect cmd_expect_set_features_min_off_min_off[] = {
351 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
352 	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
353 	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
354 	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
355 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
356 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
357 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
358 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
359 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
360 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
361 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
362 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
363 	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
364 	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
365 	{ &cmd_sfeatures_min_off, sizeof(cmd_sfeatures_min_off), 0, 0, 0 },
366 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
367 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
368 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
369 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
370 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
371 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
372 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
373 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
374 	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
375 	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
376 	{ 0, 0, 0, 0, 0 }
377 };
378 
379 static const struct cmd_expect cmd_expect_set_features_min_on_min_off[] = {
380 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
381 	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
382 	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
383 	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
384 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
385 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
386 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
387 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
388 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
389 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
390 	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
391 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
392 	{ &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on.cmd),
393 	  0, &cmd_gfeatures_min_on, sizeof(cmd_gfeatures_min_on) },
394 	{ &cmd_sfeatures_min_off, sizeof(cmd_sfeatures_min_off), 0, 0, 0 },
395 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
396 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
397 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
398 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
399 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
400 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
401 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
402 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
403 	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
404 	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
405 	{ 0, 0, 0, 0, 0 }
406 };
407 
408 static const struct cmd_expect cmd_expect_set_features_min_off_unsup_on[] = {
409 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
410 	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
411 	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
412 	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
413 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
414 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
415 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
416 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
417 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
418 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
419 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
420 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
421 	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
422 	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
423 	{ &cmd_sfeatures_noop, sizeof(cmd_sfeatures_noop), 0, 0, 0 },
424 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
425 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
426 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
427 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
428 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
429 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
430 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
431 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
432 	{ &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off.cmd),
433 	  0, &cmd_gfeatures_min_off, sizeof(cmd_gfeatures_min_off) },
434 	{ 0, 0, 0, 0, 0 }
435 };
436 
437 static const struct cmd_expect cmd_expect_set_features_ipv4_off_many_on[] = {
438 	{ &cmd_gssetinfo, sizeof(cmd_gssetinfo.cmd),
439 	  0, &cmd_gssetinfo, sizeof(cmd_gssetinfo) },
440 	{ &cmd_gstrings, sizeof(cmd_gstrings.cmd),
441 	  0, &cmd_gstrings, sizeof(cmd_gstrings) },
442 	{ &cmd_grxcsum_off, 4, 0, &cmd_grxcsum_off, sizeof(cmd_grxcsum_off) },
443 	{ &cmd_gtxcsum_off, 4, 0, &cmd_gtxcsum_off, sizeof(cmd_gtxcsum_off) },
444 	{ &cmd_gsg_off, 4, 0, &cmd_gsg_off, sizeof(cmd_gsg_off) },
445 	{ &cmd_gtso_off, 4, 0, &cmd_gtso_off, sizeof(cmd_gtso_off) },
446 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
447 	{ &cmd_ggso_off, 4, 0, &cmd_ggso_off, sizeof(cmd_ggso_off) },
448 	{ &cmd_ggro_off, 4,0, &cmd_ggro_off, sizeof(cmd_ggro_off) },
449 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
450 	{ &cmd_gfeatures_ipv4_off, sizeof(cmd_gfeatures_ipv4_off.cmd),
451 	  0, &cmd_gfeatures_ipv4_off, sizeof(cmd_gfeatures_ipv4_off) },
452 	{ &cmd_sfeatures_ipv4_on, sizeof(cmd_sfeatures_ipv4_on), 0, 0, 0 },
453 	{ &cmd_grxcsum_on, 4, 0, &cmd_grxcsum_on, sizeof(cmd_grxcsum_on) },
454 	{ &cmd_gtxcsum_on, 4, 0, &cmd_gtxcsum_on, sizeof(cmd_gtxcsum_on) },
455 	{ &cmd_gsg_on, 4, 0, &cmd_gsg_on, sizeof(cmd_gsg_on) },
456 	{ &cmd_gtso_on, 4, 0, &cmd_gtso_on, sizeof(cmd_gtso_on) },
457 	{ &cmd_gufo_off, 4, 0, &cmd_gufo_off, sizeof(cmd_gufo_off) },
458 	{ &cmd_ggso_on, 4, 0, &cmd_ggso_on, sizeof(cmd_ggso_on) },
459 	{ &cmd_ggro_on, 4,0, &cmd_ggro_on, sizeof(cmd_ggro_on) },
460 	{ &cmd_gflags_off, 4, 0, &cmd_gflags_off, sizeof(cmd_gflags_off) },
461 	{ &cmd_gfeatures_ipv4_on, sizeof(cmd_gfeatures_ipv4_on.cmd),
462 	  0, &cmd_gfeatures_ipv4_on, sizeof(cmd_gfeatures_ipv4_on) },
463 	{ 0, 0, 0, 0, 0 }
464 };
465 
466 static struct test_case {
467 	int rc;
468 	const char *args;
469 	const struct cmd_expect *expect;
470 } const test_cases[] = {
471 	{ 0, "-k devname", cmd_expect_get_features_off_old },
472 	{ 0, "-k dev_unsup", cmd_expect_get_features_off_old_some_unsup },
473 	{ 0, "-k dev_priv", cmd_expect_get_features_off_old_some_priv },
474 	{ 0, "-K devname rx off tx off sg off tso off ufo off gso off lro off rxvlan off txvlan off ntuple off rxhash off gro off",
475 	  cmd_expect_set_features_off_old },
476 	{ 0, "-K devname rx on tx on sg on tso on ufo on gso on lro on rxvlan on txvlan on ntuple on rxhash on gro on",
477 	  cmd_expect_set_features_on_old },
478 	{ 1, "-K devname tx on sg on", cmd_expect_set_features_unsup_on_old },
479 	{ 0, "--show-offload devname", cmd_expect_get_features_min_off },
480 	{ 0, "--show-features devname", cmd_expect_get_features_max_on },
481 	{ 0, "-K devname rx on tx on sg on tso on ufo on gso on gro on",
482 	  cmd_expect_set_features_min_off_min_on },
483 	{ 0, "-K devname rx off tx off sg off tso off ufo off gso off gro off",
484 	  cmd_expect_set_features_min_off_min_off },
485 	{ 0, "-K devname rx off tx off sg off tso off ufo off gso off gro off",
486 	  cmd_expect_set_features_min_on_min_off },
487 	{ 1, "-K devname tx on sg on",
488 	  cmd_expect_set_features_min_off_unsup_on },
489 	{ 0, "--features devname rx on tx on sg on tso on gso on gro on",
490 	  cmd_expect_set_features_ipv4_off_many_on },
491 	{ 1, "-K devname rx foo", cmd_expect_get_strings_old },
492 	{ 1, "-K devname rx foo", cmd_expect_get_strings },
493 	{ 1, "--offload devname rx", cmd_expect_get_strings_old },
494 	{ 1, "--features devname rx", cmd_expect_get_strings },
495 	{ 1, "--features devname foo on", cmd_expect_get_strings_old },
496 	{ 1, "--offload devname foo on", cmd_expect_get_strings },
497 };
498 
499 static int expect_matched;
500 static const struct cmd_expect *expect_next;
501 
send_ioctl(struct cmd_context * ctx,void * cmd)502 int send_ioctl(struct cmd_context *ctx, void *cmd)
503 {
504 	int rc = test_ioctl(expect_next, cmd);
505 
506 	if (rc == TEST_IOCTL_MISMATCH) {
507 		expect_matched = 0;
508 		test_exit(0);
509 	}
510 	expect_next++;
511 	return rc;
512 }
513 
main(void)514 int main(void)
515 {
516 	const struct test_case *tc;
517 	int test_rc;
518 	int rc = 0;
519 
520 	for (tc = test_cases; tc < test_cases + ARRAY_SIZE(test_cases); tc++) {
521 		if (getenv("ETHTOOL_TEST_VERBOSE"))
522 			printf("I: Test command line: ethtool %s\n", tc->args);
523 		expect_matched = 1;
524 		expect_next = tc->expect;
525 		test_rc = test_cmdline(tc->args);
526 
527 		/* If we found a mismatch, or there is still another
528 		 * expected ioctl to match, the test failed.
529 		 */
530 		if (!expect_matched || expect_next->cmd) {
531 			fprintf(stderr,
532 				"E: ethtool %s deviated from the expected "
533 				"ioctl sequence after %zu calls\n",
534 				tc->args, expect_next - tc->expect);
535 			rc = 1;
536 		} else if (test_rc != tc->rc) {
537 			fprintf(stderr, "E: ethtool %s returns %d\n",
538 				tc->args, test_rc);
539 			rc = 1;
540 		}
541 	}
542 
543 	return rc;
544 }
545