1 /*
2 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
3 * Copyright (c) 1996-2023 The strace developers.
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8
9 #include "defs.h"
10
11 #include DEF_MPERS_TYPE(struct_ifconf)
12 #include DEF_MPERS_TYPE(struct_ifreq)
13
14 #include <sys/socket.h>
15 #include <net/if.h>
16
17 typedef struct ifconf struct_ifconf;
18 typedef struct ifreq struct_ifreq;
19
20 #include MPERS_DEFS
21
22 #include <linux/ioctl.h>
23 #include <linux/sockios.h>
24 #include <arpa/inet.h>
25
26 #include "xlat/iffflags.h"
27
28 #define XLAT_MACROS_ONLY
29 #include "xlat/arp_hardware_types.h"
30 #undef XLAT_MACROS_ONLY
31
32 static void
33 print_ifr_hwaddr(const typeof_field(struct_ifreq, ifr_hwaddr) *const p)
34 {
35 tprint_struct_begin();
36 PRINT_FIELD_XVAL(*p, sa_family, arp_hardware_types, "ARPHRD_???");
37 tprint_struct_next();
38 PRINT_FIELD_HWADDR_SZ(*p, sa_data, sizeof(p->sa_data), p->sa_family);
39 tprint_struct_end();
40 }
41
42 static void
43 print_ifr_map(const typeof_field(struct_ifreq, ifr_map) *const p)
44 {
45 tprint_struct_begin();
46 PRINT_FIELD_X(*p, mem_start);
47 tprint_struct_next();
48 PRINT_FIELD_X(*p, mem_end);
49 tprint_struct_next();
50 PRINT_FIELD_X(*p, base_addr);
51 tprint_struct_next();
52 PRINT_FIELD_X(*p, irq);
53 tprint_struct_next();
54 PRINT_FIELD_X(*p, dma);
55 tprint_struct_next();
56 PRINT_FIELD_X(*p, port);
57 tprint_struct_end();
58 }
59
60 static void
61 print_ifreq(struct tcb *const tcp, const unsigned int code,
62 const kernel_ulong_t arg, const struct_ifreq *const ifr)
63 {
64 switch (code) {
65 case SIOCSIFADDR:
66 case SIOCGIFADDR:
67 PRINT_FIELD_SOCKADDR(*ifr, ifr_addr, tcp);
68 break;
69 case SIOCSIFDSTADDR:
70 case SIOCGIFDSTADDR:
71 PRINT_FIELD_SOCKADDR(*ifr, ifr_dstaddr, tcp);
72 break;
73 case SIOCSIFBRDADDR:
74 case SIOCGIFBRDADDR:
75 PRINT_FIELD_SOCKADDR(*ifr, ifr_broadaddr, tcp);
76 break;
77 case SIOCSIFNETMASK:
78 case SIOCGIFNETMASK:
79 PRINT_FIELD_SOCKADDR(*ifr, ifr_netmask, tcp);
80 break;
81 case SIOCADDMULTI:
82 case SIOCDELMULTI:
83 case SIOCGIFHWADDR:
84 case SIOCSIFHWADDR:
85 case SIOCSIFHWBROADCAST:
86 PRINT_FIELD_OBJ_PTR(*ifr, ifr_hwaddr, print_ifr_hwaddr);
87 break;
88 case SIOCSIFFLAGS:
89 case SIOCGIFFLAGS:
90 PRINT_FIELD_FLAGS(*ifr, ifr_flags, iffflags, "IFF_???");
91 break;
92 case SIOCGIFINDEX:
93 PRINT_FIELD_D(*ifr, ifr_ifindex);
94 break;
95 case SIOCSIFMETRIC:
96 case SIOCGIFMETRIC:
97 PRINT_FIELD_D(*ifr, ifr_metric);
98 break;
99 case SIOCSIFMTU:
100 case SIOCGIFMTU:
101 PRINT_FIELD_D(*ifr, ifr_mtu);
102 break;
103 case SIOCSIFSLAVE:
104 case SIOCGIFSLAVE:
105 PRINT_FIELD_CSTRING(*ifr, ifr_slave);
106 break;
107 case SIOCSIFNAME:
108 PRINT_FIELD_CSTRING(*ifr, ifr_newname);
109 break;
110 case SIOCGIFNAME:
111 PRINT_FIELD_CSTRING(*ifr, ifr_name);
112 break;
113 case SIOCSIFTXQLEN:
114 case SIOCGIFTXQLEN:
115 PRINT_FIELD_D(*ifr, ifr_qlen);
116 break;
117 case SIOCSIFMAP:
118 case SIOCGIFMAP:
119 PRINT_FIELD_OBJ_PTR(*ifr, ifr_map, print_ifr_map);
120 break;
121 }
122 }
123
124 static unsigned int
125 print_ifc_len(int len)
126 {
127 PRINT_VAL_D(len);
128
129 const unsigned int n = (unsigned int) len / sizeof(struct_ifreq);
130 if (len > 0 && n * sizeof(struct_ifreq) == (unsigned int) len) {
131 tprint_comment_begin();
132 PRINT_VAL_U(n);
133 tprints_string(" * sizeof(struct ifreq)");
134 tprint_comment_end();
135 }
136
137 return n;
138 }
139
140 static bool
141 print_ifconf_ifreq(struct tcb *tcp, void *elem_buf, size_t elem_size,
142 void *dummy)
143 {
144 struct_ifreq *ifr = elem_buf;
145
146 tprint_struct_begin();
147 PRINT_FIELD_CSTRING(*ifr, ifr_name);
148 tprint_struct_next();
149 PRINT_FIELD_SOCKADDR(*ifr, ifr_addr, tcp);
150 tprint_struct_end();
151
152 return true;
153 }
154
155 /*
156 * There are two different modes of operation:
157 *
158 * - Get buffer size. In this case, the callee sets ifc_buf to NULL,
159 * and the kernel returns the buffer size in ifc_len.
160 * - Get actual data. In this case, the callee specifies the buffer address
161 * in ifc_buf and its size in ifc_len. The kernel fills the buffer with
162 * the data, and its amount is returned in ifc_len.
163 *
164 * Note that, technically, the whole struct ifconf is overwritten,
165 * so ifc_buf could be different on exit, but current ioctl handler
166 * implementation does not touch it.
167 */
168 static int
169 decode_ifconf(struct tcb *const tcp, const kernel_ulong_t addr)
170 {
171 struct_ifconf *entering_ifc = NULL;
172 struct_ifconf *ifc =
173 entering(tcp) ? malloc(sizeof(*ifc)) : alloca(sizeof(*ifc));
174
175 if (exiting(tcp)) {
176 entering_ifc = get_tcb_priv_data(tcp);
177
178 if (!entering_ifc) {
179 error_func_msg("where is my ifconf?");
180 return 0;
181 }
182 }
183
184 if (!ifc || umove(tcp, addr, ifc) < 0) {
185 if (entering(tcp)) {
186 free(ifc);
187
188 tprint_arg_next();
189 printaddr(addr);
190 } else {
191 /*
192 * We failed to fetch the structure on exiting syscall,
193 * print whatever was fetched on entering syscall.
194 */
195 if (!entering_ifc->ifc_buf)
196 print_ifc_len(entering_ifc->ifc_len);
197
198 tprint_struct_next();
199 PRINT_FIELD_PTR(*entering_ifc, ifc_buf);
200
201 tprint_struct_end();
202 }
203
204 return RVAL_IOCTL_DECODED;
205 }
206
207 if (entering(tcp)) {
208 tprint_arg_next();
209 tprint_struct_begin();
210 tprints_field_name("ifc_len");
211 if (ifc->ifc_buf)
212 print_ifc_len(ifc->ifc_len);
213
214 set_tcb_priv_data(tcp, ifc, free);
215
216 return 0;
217 }
218
219 /* exiting */
220
221 if (entering_ifc->ifc_buf && (entering_ifc->ifc_len != ifc->ifc_len))
222 tprint_value_changed();
223 if (!entering_ifc->ifc_buf || (entering_ifc->ifc_len != ifc->ifc_len))
224 print_ifc_len(ifc->ifc_len);
225
226 if (!entering_ifc->ifc_buf || syserror(tcp)) {
227 tprint_struct_next();
228 PRINT_FIELD_PTR(*entering_ifc, ifc_buf);
229 if (entering_ifc->ifc_buf != ifc->ifc_buf) {
230 tprint_value_changed();
231 printaddr(ptr_to_kulong(ifc->ifc_buf));
232 }
233 } else {
234 struct_ifreq ifr;
235
236 tprint_struct_next();
237 tprints_field_name("ifc_buf");
238 print_array(tcp, ptr_to_kulong(ifc->ifc_buf),
239 ifc->ifc_len / sizeof(struct_ifreq),
240 &ifr, sizeof(ifr),
241 tfetch_mem, print_ifconf_ifreq, NULL);
242 }
243
244 tprint_struct_end();
245
246 return RVAL_IOCTL_DECODED;
247 }
248
249 MPERS_PRINTER_DECL(int, sock_ioctl,
250 struct tcb *tcp, const unsigned int code,
251 const kernel_ulong_t arg)
252 {
253 struct_ifreq ifr;
254
255 switch (code) {
256 case SIOCGIFCONF:
257 return decode_ifconf(tcp, arg);
258
259 case SIOCBRADDBR:
260 case SIOCBRDELBR:
261 tprint_arg_next();
262 printstr_ex(tcp, arg, sizeof(ifr.ifr_name), QUOTE_0_TERMINATED);
263 break;
264
265 case FIOGETOWN:
266 case SIOCATMARK:
267 case SIOCGIFENCAP:
268 case SIOCGPGRP:
269 #ifdef SIOCOUTQNSD
270 case SIOCOUTQNSD:
271 #endif
272 if (entering(tcp))
273 return 0;
274 ATTRIBUTE_FALLTHROUGH;
275
276 case FIOSETOWN:
277 case SIOCSIFENCAP:
278 case SIOCSPGRP:
279 tprint_arg_next();
280 printnum_int(tcp, arg, "%d");
281 break;
282
283 case SIOCBRADDIF:
284 case SIOCBRDELIF:
285 tprint_arg_next();
286 if (!umove_or_printaddr(tcp, arg, &ifr)) {
287 tprint_struct_begin();
288 PRINT_FIELD_IFINDEX(ifr, ifr_ifindex);
289 tprint_struct_end();
290 }
291 break;
292
293 case SIOCADDMULTI:
294 case SIOCDELMULTI:
295 case SIOCSIFADDR:
296 case SIOCSIFBRDADDR:
297 case SIOCSIFDSTADDR:
298 case SIOCSIFFLAGS:
299 case SIOCSIFHWADDR:
300 case SIOCSIFHWBROADCAST:
301 case SIOCSIFMAP:
302 case SIOCSIFMETRIC:
303 case SIOCSIFMTU:
304 case SIOCSIFNAME:
305 case SIOCSIFNETMASK:
306 case SIOCSIFSLAVE:
307 case SIOCSIFTXQLEN:
308 tprint_arg_next();
309 if (umove_or_printaddr(tcp, arg, &ifr))
310 break;
311
312 tprint_struct_begin();
313 PRINT_FIELD_CSTRING(ifr, ifr_name);
314 tprint_arg_next();
315 print_ifreq(tcp, code, arg, &ifr);
316 tprint_struct_end();
317 break;
318
319 case SIOCGIFADDR:
320 case SIOCGIFBRDADDR:
321 case SIOCGIFDSTADDR:
322 case SIOCGIFFLAGS:
323 case SIOCGIFHWADDR:
324 case SIOCGIFINDEX:
325 case SIOCGIFMAP:
326 case SIOCGIFMETRIC:
327 case SIOCGIFMTU:
328 case SIOCGIFNAME:
329 case SIOCGIFNETMASK:
330 case SIOCGIFSLAVE:
331 case SIOCGIFTXQLEN:
332 if (entering(tcp)) {
333 tprint_arg_next();
334 if (umove_or_printaddr(tcp, arg, &ifr))
335 break;
336
337 if (SIOCGIFNAME == code) {
338 tprint_struct_begin();
339 PRINT_FIELD_D(ifr, ifr_ifindex);
340 } else {
341 tprint_struct_begin();
342 PRINT_FIELD_CSTRING(ifr, ifr_name);
343 }
344 return 0;
345 } else {
346 if (!syserror(tcp) && !umove(tcp, arg, &ifr)) {
347 tprint_struct_next();
348 print_ifreq(tcp, code, arg, &ifr);
349 }
350 tprint_struct_end();
351 break;
352 }
353
354 case SIOCADDDLCI:
355 case SIOCADDRT:
356 case SIOCBONDCHANGEACTIVE:
357 case SIOCBONDENSLAVE:
358 case SIOCBONDINFOQUERY:
359 case SIOCBONDRELEASE:
360 case SIOCBONDSETHWADDR:
361 case SIOCBONDSLAVEINFOQUERY:
362 case SIOCDARP:
363 case SIOCDELDLCI:
364 case SIOCDELRT:
365 case SIOCDIFADDR:
366 case SIOCDRARP:
367 case SIOCETHTOOL:
368 case SIOCGARP:
369 #ifdef SIOCGHWTSTAMP
370 case SIOCGHWTSTAMP:
371 #endif
372 case SIOCGIFBR:
373 case SIOCGIFCOUNT:
374 case SIOCGIFMEM:
375 case SIOCGIFPFLAGS:
376 case SIOCGIFVLAN:
377 case SIOCGMIIPHY:
378 case SIOCGMIIREG:
379 case SIOCGRARP:
380 #ifdef SIOCGSKNS
381 case SIOCGSKNS:
382 #endif
383 #ifdef SIOCGSTAMP_OLD
384 case SIOCGSTAMP_OLD:
385 #endif
386 #ifdef SIOCGSTAMP_NEW
387 case SIOCGSTAMP_NEW:
388 #endif
389 #ifdef SIOCGSTAMPNS_OLD
390 case SIOCGSTAMPNS_OLD:
391 #endif
392 #ifdef SIOCGSTAMPNS_NEW
393 case SIOCGSTAMPNS_NEW:
394 #endif
395 case SIOCRTMSG:
396 case SIOCSARP:
397 #ifdef SIOCSHWTSTAMP
398 case SIOCSHWTSTAMP:
399 #endif
400 case SIOCSIFBR:
401 case SIOCSIFLINK:
402 case SIOCSIFMEM:
403 case SIOCSIFPFLAGS:
404 case SIOCSIFVLAN:
405 case SIOCSMIIREG:
406 case SIOCSRARP:
407 case SIOCWANDEV:
408 tprint_arg_next();
409 printaddr(arg);
410 break;
411
412 default:
413 return RVAL_DECODED;
414 }
415
416 return RVAL_IOCTL_DECODED;
417 }