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 #include <sys/socket.h>
30 #include <linux/sockios.h>
31 #include <arpa/inet.h>
32 #if defined(ALPHA) || defined(SH) || defined(SH64)
33 # if defined(HAVE_SYS_IOCTL_H)
34 #  include <sys/ioctl.h>
35 # elif defined(HAVE_IOCTLS_H)
36 #  include <ioctls.h>
37 # endif
38 #endif
39 #include <net/if.h>
40 
41 #include "xlat/iffflags.h"
42 
43 static void
print_ifreq_addr(struct tcb * tcp,const struct ifreq * ifr,const long addr)44 print_ifreq_addr(struct tcb *tcp, const struct ifreq *ifr, const long addr)
45 {
46 	tprintf("{");
47 	printxval(addrfams, ifr->ifr_addr.sa_family, "AF_???");
48 	tprints(", ");
49 	if (ifr->ifr_addr.sa_family == AF_INET) {
50 		const struct sockaddr_in *sinp =
51 			(struct sockaddr_in *) &ifr->ifr_addr;
52 		tprintf("inet_addr(\"%s\")", inet_ntoa(sinp->sin_addr));
53 	} else
54 		printstr(tcp, addr + offsetof(struct ifreq, ifr_addr.sa_data),
55 			 sizeof(ifr->ifr_addr.sa_data));
56 	tprints("}");
57 }
58 
59 static void
print_ifname(const char * ifname)60 print_ifname(const char *ifname)
61 {
62 	print_quoted_string(ifname, IFNAMSIZ + 1, QUOTE_0_TERMINATED);
63 }
64 
65 static void
print_ifreq(struct tcb * tcp,const unsigned int code,const long arg,const struct ifreq * ifr)66 print_ifreq(struct tcb *tcp, const unsigned int code, const long arg,
67 	    const struct ifreq *ifr)
68 {
69 	switch (code) {
70 	case SIOCSIFADDR:
71 	case SIOCGIFADDR:
72 		tprints("ifr_addr=");
73 		print_ifreq_addr(tcp, ifr, arg);
74 		break;
75 	case SIOCSIFDSTADDR:
76 	case SIOCGIFDSTADDR:
77 		tprints("ifr_dstaddr=");
78 		print_ifreq_addr(tcp, ifr, arg);
79 		break;
80 	case SIOCSIFBRDADDR:
81 	case SIOCGIFBRDADDR:
82 		tprints("ifr_broadaddr=");
83 		print_ifreq_addr(tcp, ifr, arg);
84 		break;
85 	case SIOCSIFNETMASK:
86 	case SIOCGIFNETMASK:
87 		tprints("ifr_netmask=");
88 		print_ifreq_addr(tcp, ifr, arg);
89 		break;
90 	case SIOCSIFHWADDR:
91 	case SIOCGIFHWADDR: {
92 		/* XXX Are there other hardware addresses
93 		   than 6-byte MACs?  */
94 		const unsigned char *bytes =
95 			(unsigned char *) &ifr->ifr_hwaddr.sa_data;
96 		tprintf("ifr_hwaddr=%02x:%02x:%02x:%02x:%02x:%02x",
97 			bytes[0], bytes[1], bytes[2],
98 			bytes[3], bytes[4], bytes[5]);
99 		break;
100 	}
101 	case SIOCSIFFLAGS:
102 	case SIOCGIFFLAGS:
103 		tprints("ifr_flags=");
104 		printflags(iffflags, ifr->ifr_flags, "IFF_???");
105 		break;
106 	case SIOCSIFMETRIC:
107 	case SIOCGIFMETRIC:
108 		tprintf("ifr_metric=%d", ifr->ifr_metric);
109 		break;
110 	case SIOCSIFMTU:
111 	case SIOCGIFMTU:
112 		tprintf("ifr_mtu=%d", ifr->ifr_mtu);
113 		break;
114 	case SIOCSIFSLAVE:
115 	case SIOCGIFSLAVE:
116 		tprints("ifr_slave=");
117 		print_ifname(ifr->ifr_slave);
118 		break;
119 	case SIOCSIFTXQLEN:
120 	case SIOCGIFTXQLEN:
121 		tprintf("ifr_qlen=%d", ifr->ifr_qlen);
122 		break;
123 	case SIOCSIFMAP:
124 	case SIOCGIFMAP:
125 		tprintf("ifr_map={mem_start=%#lx, "
126 			"mem_end=%#lx, base_addr=%#x, "
127 			"irq=%u, dma=%u, port=%u}",
128 			ifr->ifr_map.mem_start,
129 			ifr->ifr_map.mem_end,
130 			(unsigned) ifr->ifr_map.base_addr,
131 			(unsigned) ifr->ifr_map.irq,
132 			(unsigned) ifr->ifr_map.dma,
133 			(unsigned) ifr->ifr_map.port);
134 		break;
135 	}
136 }
137 
138 static unsigned int
print_ifc_len(int len)139 print_ifc_len(int len)
140 {
141 	const unsigned int n = (unsigned int) len / sizeof(struct ifreq);
142 
143 	if (len < 0 || n * sizeof(struct ifreq) != (unsigned int) len)
144 		tprintf("%d", len);
145 	else
146 		tprintf("%u * sizeof(struct ifreq)", n);
147 
148 	return n;
149 }
150 
151 static int
decode_ifconf(struct tcb * tcp,const long addr)152 decode_ifconf(struct tcb *tcp, const long addr)
153 {
154 	struct ifconf ifc;
155 
156 	if (entering(tcp)) {
157 		tprints(", ");
158 		if (umove_or_printaddr(tcp, addr, &ifc))
159 			return RVAL_DECODED | 1;
160 		if (ifc.ifc_buf) {
161 			tprints("{");
162 			print_ifc_len(ifc.ifc_len);
163 		}
164 		return 1;
165 	}
166 
167 	if (syserror(tcp) || umove(tcp, addr, &ifc) < 0) {
168 		if (ifc.ifc_buf)
169 			tprints("}");
170 		else
171 			printaddr(addr);
172 		return RVAL_DECODED | 1;
173 	}
174 
175 	if (!ifc.ifc_buf) {
176 		tprints("{");
177 		print_ifc_len(ifc.ifc_len);
178 		tprints(", NULL}");
179 		return RVAL_DECODED | 1;
180 	}
181 
182 	tprints(" => ");
183 	const unsigned int nifra = print_ifc_len(ifc.ifc_len);
184 	if (!nifra) {
185 		tprints("}");
186 		return RVAL_DECODED | 1;
187 	}
188 
189 	struct ifreq ifra[nifra > max_strlen ? max_strlen : nifra];
190 	tprints(", ");
191 	if (umove_or_printaddr(tcp, (unsigned long) ifc.ifc_buf, &ifra)) {
192 		tprints("}");
193 		return RVAL_DECODED | 1;
194 	}
195 
196 	tprints("[");
197 	unsigned int i;
198 	for (i = 0; i < ARRAY_SIZE(ifra); ++i) {
199 		if (i > 0)
200 			tprints(", ");
201 		tprints("{ifr_name=");
202 		print_ifname(ifra[i].ifr_name);
203 		tprints(", ");
204 		if (verbose(tcp)) {
205 			tprints("ifr_addr=");
206 			print_ifreq_addr(tcp, &ifra[i],
207 					 addr + i * sizeof(ifra[0]));
208 		} else
209 			tprints("...");
210 		tprints("}");
211 	}
212 	if (i < nifra)
213 		tprints(", ...");
214 	tprints("]}");
215 
216 	return RVAL_DECODED | 1;
217 }
218 
219 int
sock_ioctl(struct tcb * tcp,const unsigned int code,const long arg)220 sock_ioctl(struct tcb *tcp, const unsigned int code, const long arg)
221 {
222 	struct ifreq ifr;
223 
224 	switch (code) {
225 	case SIOCGIFCONF:
226 		return decode_ifconf(tcp, arg);
227 
228 #ifdef SIOCBRADDBR
229 	case SIOCBRADDBR:
230 	case SIOCBRDELBR:
231 		tprints(", ");
232 		printstr(tcp, arg, -1);
233 		break;
234 #endif
235 
236 #ifdef FIOSETOWN
237 	case FIOSETOWN:
238 #endif
239 #ifdef SIOCSPGRP
240 	case SIOCSPGRP:
241 #endif
242 		tprints(", ");
243 		printnum_int(tcp, arg, "%d");
244 		break;
245 
246 #ifdef FIOGETOWN
247 	case FIOGETOWN:
248 #endif
249 #ifdef SIOCGPGRP
250 	case SIOCGPGRP:
251 #endif
252 #ifdef SIOCATMARK
253 	case SIOCATMARK:
254 #endif
255 		if (entering(tcp))
256 			return 0;
257 		tprints(", ");
258 		printnum_int(tcp, arg, "%d");
259 		break;
260 
261 #ifdef SIOCBRADDIF
262 	case SIOCBRADDIF:
263 #endif
264 #ifdef SIOCBRDELIF
265 	case SIOCBRDELIF:
266 #endif
267 		/* no arguments */
268 		break;
269 
270 	case SIOCSIFNAME:
271 	case SIOCSIFADDR:
272 	case SIOCSIFDSTADDR:
273 	case SIOCSIFBRDADDR:
274 	case SIOCSIFNETMASK:
275 	case SIOCSIFFLAGS:
276 	case SIOCSIFMETRIC:
277 	case SIOCSIFMTU:
278 	case SIOCSIFSLAVE:
279 	case SIOCSIFHWADDR:
280 	case SIOCSIFTXQLEN:
281 	case SIOCSIFMAP:
282 		tprints(", ");
283 		if (umove_or_printaddr(tcp, arg, &ifr))
284 			break;
285 
286 		tprints("{ifr_name=");
287 		print_ifname(ifr.ifr_name);
288 		tprints(", ");
289 		if (code == SIOCSIFNAME) {
290 			tprints("ifr_newname=");
291 			print_ifname(ifr.ifr_newname);
292 		} else {
293 			print_ifreq(tcp, code, arg, &ifr);
294 		}
295 		tprints("}");
296 		break;
297 
298 	case SIOCGIFNAME:
299 	case SIOCGIFINDEX:
300 	case SIOCGIFADDR:
301 	case SIOCGIFDSTADDR:
302 	case SIOCGIFBRDADDR:
303 	case SIOCGIFNETMASK:
304 	case SIOCGIFFLAGS:
305 	case SIOCGIFMETRIC:
306 	case SIOCGIFMTU:
307 	case SIOCGIFSLAVE:
308 	case SIOCGIFHWADDR:
309 	case SIOCGIFTXQLEN:
310 	case SIOCGIFMAP:
311 		if (entering(tcp)) {
312 			tprints(", ");
313 			if (umove_or_printaddr(tcp, arg, &ifr))
314 				break;
315 
316 			if (SIOCGIFNAME == code) {
317 				tprintf("{ifr_index=%d", ifr.ifr_ifindex);
318 			} else {
319 				tprints("{ifr_name=");
320 				print_ifname(ifr.ifr_name);
321 			}
322 			return 1;
323 		} else {
324 			if (syserror(tcp)) {
325 				tprints("}");
326 				break;
327 			}
328 
329 			tprints(", ");
330 			if (umove(tcp, arg, &ifr) < 0) {
331 				tprints("???}");
332 				break;
333 			}
334 
335 			if (SIOCGIFNAME == code) {
336 				tprints("ifr_name=");
337 				print_ifname(ifr.ifr_name);
338 			} else {
339 				print_ifreq(tcp, code, arg, &ifr);
340 			}
341 			tprints("}");
342 			break;
343 		}
344 
345 	default:
346 		return RVAL_DECODED;
347 	}
348 
349 	return RVAL_DECODED | 1;
350 }
351