Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
3 : : * All rights reserved.
4 : : *
5 : : * Redistribution and use in source and binary forms, with or without
6 : : * modification, are permitted provided that the following conditions
7 : : * are met:
8 : : * 1. Redistributions of source code must retain the above copyright
9 : : * notice, this list of conditions and the following disclaimer.
10 : : * 2. Redistributions in binary form must reproduce the above copyright
11 : : * notice, this list of conditions and the following disclaimer in the
12 : : * documentation and/or other materials provided with the distribution.
13 : : * 3. The name of the author may not be used to endorse or promote products
14 : : * derived from this software without specific prior written permission.
15 : : *
16 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : : * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : : */
27 : :
28 : : #include "defs.h"
29 : :
30 : : #include <sys/socket.h>
31 : : #if defined ALPHA || defined SH || defined SH64
32 : : # include <linux/ioctl.h>
33 : : #endif
34 : : #include <linux/sockios.h>
35 : : #include <arpa/inet.h>
36 : : #include <net/if.h>
37 : :
38 : : #include DEF_MPERS_TYPE(struct_ifconf)
39 : : #include DEF_MPERS_TYPE(struct_ifreq)
40 : :
41 : : typedef struct ifconf struct_ifconf;
42 : : typedef struct ifreq struct_ifreq;
43 : :
44 : : #include MPERS_DEFS
45 : :
46 : : #include "xlat/iffflags.h"
47 : :
48 : : #define PRINT_IFREQ_ADDR(tcp, ifr, sockaddr) \
49 : : do { \
50 : : tprints(#sockaddr "="); \
51 : : print_sockaddr(tcp, &((ifr)->sockaddr), \
52 : : sizeof((ifr)->sockaddr)); \
53 : : } while (0)
54 : :
55 : : static void
56 : 16 : print_ifname(const char *ifname)
57 : : {
58 : 16 : print_quoted_string(ifname, IFNAMSIZ + 1, QUOTE_0_TERMINATED);
59 : 16 : }
60 : :
61 : : static void
62 : 0 : print_ifreq(struct tcb *const tcp, const unsigned int code,
63 : : const kernel_ulong_t arg, const struct_ifreq *const ifr)
64 : : {
65 [ # # # # : 0 : switch (code) {
# # # # #
# # # ]
66 : : case SIOCSIFADDR:
67 : : case SIOCGIFADDR:
68 : 0 : PRINT_IFREQ_ADDR(tcp, ifr, ifr_addr);
69 : 0 : break;
70 : : case SIOCSIFDSTADDR:
71 : : case SIOCGIFDSTADDR:
72 : 0 : PRINT_IFREQ_ADDR(tcp, ifr, ifr_dstaddr);
73 : 0 : break;
74 : : case SIOCSIFBRDADDR:
75 : : case SIOCGIFBRDADDR:
76 : 0 : PRINT_IFREQ_ADDR(tcp, ifr, ifr_broadaddr);
77 : 0 : break;
78 : : case SIOCSIFNETMASK:
79 : : case SIOCGIFNETMASK:
80 : 0 : PRINT_IFREQ_ADDR(tcp, ifr, ifr_netmask);
81 : 0 : break;
82 : : case SIOCSIFHWADDR:
83 : : case SIOCGIFHWADDR: {
84 : : /* XXX Are there other hardware addresses
85 : : than 6-byte MACs? */
86 : 0 : const unsigned char *bytes =
87 : : (unsigned char *) &ifr->ifr_hwaddr.sa_data;
88 : 0 : tprintf("ifr_hwaddr=%02x:%02x:%02x:%02x:%02x:%02x",
89 : 0 : bytes[0], bytes[1], bytes[2],
90 : 0 : bytes[3], bytes[4], bytes[5]);
91 : 0 : break;
92 : : }
93 : : case SIOCSIFFLAGS:
94 : : case SIOCGIFFLAGS:
95 : 0 : tprints("ifr_flags=");
96 : 0 : printflags(iffflags, (unsigned short) ifr->ifr_flags, "IFF_???");
97 : 0 : break;
98 : : case SIOCSIFMETRIC:
99 : : case SIOCGIFMETRIC:
100 : 0 : tprintf("ifr_metric=%d", ifr->ifr_metric);
101 : 0 : break;
102 : : case SIOCSIFMTU:
103 : : case SIOCGIFMTU:
104 : 0 : tprintf("ifr_mtu=%d", ifr->ifr_mtu);
105 : 0 : break;
106 : : case SIOCSIFSLAVE:
107 : : case SIOCGIFSLAVE:
108 : 0 : tprints("ifr_slave=");
109 : 0 : print_ifname(ifr->ifr_slave);
110 : 0 : break;
111 : : case SIOCSIFTXQLEN:
112 : : case SIOCGIFTXQLEN:
113 : 0 : tprintf("ifr_qlen=%d", ifr->ifr_qlen);
114 : 0 : break;
115 : : case SIOCSIFMAP:
116 : : case SIOCGIFMAP:
117 : 0 : tprintf("ifr_map={mem_start=%#" PRI_klx ", "
118 : : "mem_end=%#" PRI_klx ", base_addr=%#x, "
119 : : "irq=%u, dma=%u, port=%u}",
120 : 0 : (kernel_ulong_t) ifr->ifr_map.mem_start,
121 : 0 : (kernel_ulong_t) ifr->ifr_map.mem_end,
122 : 0 : (unsigned) ifr->ifr_map.base_addr,
123 : 0 : (unsigned) ifr->ifr_map.irq,
124 : 0 : (unsigned) ifr->ifr_map.dma,
125 : 0 : (unsigned) ifr->ifr_map.port);
126 : 0 : break;
127 : : }
128 : 0 : }
129 : :
130 : : static unsigned int
131 : 58 : print_ifc_len(int len)
132 : : {
133 : 58 : const unsigned int n = (unsigned int) len / sizeof(struct_ifreq);
134 : :
135 [ + - ][ + + ]: 58 : if (len < 0 || n * sizeof(struct_ifreq) != (unsigned int) len)
136 : 18 : tprintf("%d", len);
137 : : else
138 : 40 : tprintf("%u * sizeof(struct ifreq)", n);
139 : :
140 : 58 : return n;
141 : : }
142 : :
143 : : static bool
144 : 16 : print_ifconf_ifreq(struct tcb *tcp, void *elem_buf, size_t elem_size,
145 : : void *dummy)
146 : : {
147 : 16 : struct_ifreq *ifr = elem_buf;
148 : :
149 : 16 : tprints("{ifr_name=");
150 : 16 : print_ifname(ifr->ifr_name);
151 : 16 : tprints(", ");
152 : 16 : PRINT_IFREQ_ADDR(tcp, ifr, ifr_addr);
153 : 16 : tprints("}");
154 : :
155 : 16 : return true;
156 : : }
157 : :
158 : : /*
159 : : * There are two different modes of operation:
160 : : *
161 : : * - Get buffer size. In this case, the callee sets ifc_buf to NULL,
162 : : * and the kernel returns the buffer size in ifc_len.
163 : : * - Get actual data. In this case, the callee specifies the buffer address
164 : : * in ifc_buf and its size in ifc_len. The kernel fills the buffer with
165 : : * the data, and its amount is returned in ifc_len.
166 : : *
167 : : * Note that, technically, the whole struct ifconf is overwritten,
168 : : * so ifc_buf could be different on exit, but current ioctl handler
169 : : * implementation does not touch it.
170 : : */
171 : : static int
172 : 96 : decode_ifconf(struct tcb *const tcp, const kernel_ulong_t addr)
173 : : {
174 : 96 : struct_ifconf *entering_ifc = NULL;
175 [ + + ]: 96 : struct_ifconf *ifc =
176 : 96 : entering(tcp) ? malloc(sizeof(*ifc)) : alloca(sizeof(*ifc));
177 : :
178 [ + + ]: 96 : if (exiting(tcp)) {
179 : 42 : entering_ifc = get_tcb_priv_data(tcp);
180 : :
181 [ - + ]: 42 : if (!entering_ifc) {
182 : 0 : error_msg("decode_ifconf: where is my ifconf?");
183 : 0 : return 0;
184 : : }
185 : : }
186 : :
187 [ + - ][ + + ]: 96 : if (!ifc || umove(tcp, addr, ifc) < 0) {
188 [ + - ]: 12 : if (entering(tcp)) {
189 : 12 : free(ifc);
190 : :
191 : 12 : tprints(", ");
192 : 12 : printaddr(addr);
193 : : } else {
194 : : /*
195 : : * We failed to fetch the structure on exiting syscall,
196 : : * print whatever was fetched on entering syscall.
197 : : */
198 [ # # ]: 0 : if (!entering_ifc->ifc_buf)
199 : 0 : print_ifc_len(entering_ifc->ifc_len);
200 : :
201 : 0 : tprints(", ifc_buf=");
202 : 0 : printaddr(ptr_to_kulong(entering_ifc->ifc_buf));
203 : :
204 : 0 : tprints("}");
205 : : }
206 : :
207 : 12 : return RVAL_DECODED | 1;
208 : : }
209 : :
210 [ + + ]: 84 : if (entering(tcp)) {
211 : 42 : tprints(", {ifc_len=");
212 [ + + ]: 42 : if (ifc->ifc_buf)
213 : 36 : print_ifc_len(ifc->ifc_len);
214 : :
215 : 42 : set_tcb_priv_data(tcp, ifc, free);
216 : :
217 : 42 : return 1;
218 : : }
219 : :
220 : : /* exiting */
221 : :
222 [ + + ][ + + ]: 42 : if (entering_ifc->ifc_buf && (entering_ifc->ifc_len != ifc->ifc_len))
223 : 16 : tprints(" => ");
224 [ + + ][ + + ]: 42 : if (!entering_ifc->ifc_buf || (entering_ifc->ifc_len != ifc->ifc_len))
225 : 22 : print_ifc_len(ifc->ifc_len);
226 : :
227 : 42 : tprints(", ifc_buf=");
228 : :
229 [ + + ][ + + ]: 42 : if (!entering_ifc->ifc_buf || syserror(tcp)) {
230 : 14 : printaddr(ptr_to_kulong(entering_ifc->ifc_buf));
231 [ - + ]: 14 : if (entering_ifc->ifc_buf != ifc->ifc_buf) {
232 : 0 : tprints(" => ");
233 : 0 : printaddr(ptr_to_kulong(ifc->ifc_buf));
234 : : }
235 : : } else {
236 : : struct_ifreq ifr;
237 : :
238 : 28 : print_array(tcp, ptr_to_kulong(ifc->ifc_buf),
239 : 28 : ifc->ifc_len / sizeof(struct_ifreq),
240 : : &ifr, sizeof(ifr),
241 : : umoven_or_printaddr, print_ifconf_ifreq, NULL);
242 : : }
243 : :
244 : 42 : tprints("}");
245 : :
246 : 42 : return RVAL_DECODED | 1;
247 : : }
248 : :
249 : 96 : 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 [ + - - - : 96 : switch (code) {
- - - - ]
256 : : case SIOCGIFCONF:
257 : 96 : return decode_ifconf(tcp, arg);
258 : :
259 : : #ifdef SIOCBRADDBR
260 : : case SIOCBRADDBR:
261 : : case SIOCBRDELBR:
262 : 0 : tprints(", ");
263 : 0 : printstr(tcp, arg);
264 : 0 : break;
265 : : #endif
266 : :
267 : : #ifdef FIOSETOWN
268 : : case FIOSETOWN:
269 : : #endif
270 : : #ifdef SIOCSPGRP
271 : : case SIOCSPGRP:
272 : : #endif
273 : 0 : tprints(", ");
274 : 0 : printnum_int(tcp, arg, "%d");
275 : 0 : break;
276 : :
277 : : #ifdef FIOGETOWN
278 : : case FIOGETOWN:
279 : : #endif
280 : : #ifdef SIOCGPGRP
281 : : case SIOCGPGRP:
282 : : #endif
283 : : #ifdef SIOCATMARK
284 : : case SIOCATMARK:
285 : : #endif
286 [ # # ]: 0 : if (entering(tcp))
287 : 0 : return 0;
288 : 0 : tprints(", ");
289 : 0 : printnum_int(tcp, arg, "%d");
290 : 0 : break;
291 : :
292 : : #ifdef SIOCBRADDIF
293 : : case SIOCBRADDIF:
294 : : #endif
295 : : #ifdef SIOCBRDELIF
296 : : case SIOCBRDELIF:
297 : : #endif
298 : : /* no arguments */
299 : 0 : break;
300 : :
301 : : case SIOCSIFNAME:
302 : : case SIOCSIFADDR:
303 : : case SIOCSIFDSTADDR:
304 : : case SIOCSIFBRDADDR:
305 : : case SIOCSIFNETMASK:
306 : : case SIOCSIFFLAGS:
307 : : case SIOCSIFMETRIC:
308 : : case SIOCSIFMTU:
309 : : case SIOCSIFSLAVE:
310 : : case SIOCSIFHWADDR:
311 : : case SIOCSIFTXQLEN:
312 : : case SIOCSIFMAP:
313 : 0 : tprints(", ");
314 [ # # ]: 0 : if (umove_or_printaddr(tcp, arg, &ifr))
315 : 0 : break;
316 : :
317 : 0 : tprints("{ifr_name=");
318 : 0 : print_ifname(ifr.ifr_name);
319 : 0 : tprints(", ");
320 [ # # ]: 0 : if (code == SIOCSIFNAME) {
321 : 0 : tprints("ifr_newname=");
322 : 0 : print_ifname(ifr.ifr_newname);
323 : : } else {
324 : 0 : print_ifreq(tcp, code, arg, &ifr);
325 : : }
326 : 0 : tprints("}");
327 : 0 : break;
328 : :
329 : : case SIOCGIFNAME:
330 : : case SIOCGIFINDEX:
331 : : case SIOCGIFADDR:
332 : : case SIOCGIFDSTADDR:
333 : : case SIOCGIFBRDADDR:
334 : : case SIOCGIFNETMASK:
335 : : case SIOCGIFFLAGS:
336 : : case SIOCGIFMETRIC:
337 : : case SIOCGIFMTU:
338 : : case SIOCGIFSLAVE:
339 : : case SIOCGIFHWADDR:
340 : : case SIOCGIFTXQLEN:
341 : : case SIOCGIFMAP:
342 [ # # ]: 0 : if (entering(tcp)) {
343 : 0 : tprints(", ");
344 [ # # ]: 0 : if (umove_or_printaddr(tcp, arg, &ifr))
345 : 0 : break;
346 : :
347 [ # # ]: 0 : if (SIOCGIFNAME == code) {
348 : 0 : tprintf("{ifr_index=%d", ifr.ifr_ifindex);
349 : : } else {
350 : 0 : tprints("{ifr_name=");
351 : 0 : print_ifname(ifr.ifr_name);
352 : : }
353 : 0 : return 1;
354 : : } else {
355 [ # # ]: 0 : if (syserror(tcp)) {
356 : 0 : tprints("}");
357 : 0 : break;
358 : : }
359 : :
360 : 0 : tprints(", ");
361 [ # # ]: 0 : if (umove(tcp, arg, &ifr) < 0) {
362 : 0 : tprints("???}");
363 : 0 : break;
364 : : }
365 : :
366 [ # # ]: 0 : if (SIOCGIFNAME == code) {
367 : 0 : tprints("ifr_name=");
368 : 0 : print_ifname(ifr.ifr_name);
369 : : } else {
370 : 0 : print_ifreq(tcp, code, arg, &ifr);
371 : : }
372 : 0 : tprints("}");
373 : 0 : break;
374 : : }
375 : :
376 : : default:
377 : 0 : return RVAL_DECODED;
378 : : }
379 : :
380 : 96 : return RVAL_DECODED | 1;
381 : : }
|