xref: /netbsd-src/sys/compat/linux/common/linux_socket.c (revision 17dd36da8292193180754d5047c0926dbb56818c)
1 /*	$NetBSD: linux_socket.c,v 1.29 2001/03/29 10:37:37 fvdl Exp $	*/
2 
3 /*-
4  * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Frank van der Linden and Eric Haszlakiewicz.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the NetBSD
21  *	Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Functions in multiarch:
41  *	linux_sys_socketcall		: linux_socketcall.c
42  */
43 
44 #include <sys/param.h>
45 #include <sys/kernel.h>
46 #include <sys/systm.h>
47 #include <sys/buf.h>
48 #include <sys/malloc.h>
49 #include <sys/ioctl.h>
50 #include <sys/tty.h>
51 #include <sys/file.h>
52 #include <sys/filedesc.h>
53 #include <sys/select.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <net/if.h>
57 #include <net/if_dl.h>
58 #include <net/if_types.h>
59 #include <netinet/in.h>
60 #include <netinet/tcp.h>
61 #include <sys/mount.h>
62 #include <sys/proc.h>
63 #include <sys/vnode.h>
64 #include <sys/device.h>
65 #include <sys/protosw.h>
66 
67 #include <sys/syscallargs.h>
68 
69 #include <compat/linux/common/linux_types.h>
70 #include <compat/linux/common/linux_util.h>
71 #include <compat/linux/common/linux_signal.h>
72 #include <compat/linux/common/linux_ioctl.h>
73 #include <compat/linux/common/linux_socket.h>
74 #include <compat/linux/common/linux_socketcall.h>
75 #include <compat/linux/common/linux_sockio.h>
76 
77 #include <compat/linux/linux_syscallargs.h>
78 
79 /*
80  * The calls in this file are entered either via the linux_socketcall()
81  * interface or, on the Alpha, as individual syscalls.  The
82  * linux_socketcall function does any massaging of arguments so that all
83  * the calls in here need not think that they are anything other
84  * than a normal syscall.
85  */
86 
87 int linux_to_bsd_domain __P((int));
88 int linux_to_bsd_sopt_level __P((int));
89 int linux_to_bsd_so_sockopt __P((int));
90 int linux_to_bsd_ip_sockopt __P((int));
91 int linux_to_bsd_tcp_sockopt __P((int));
92 int linux_to_bsd_udp_sockopt __P((int));
93 int linux_getifhwaddr __P((struct proc *, register_t *, u_int, void *));
94 
95 /*
96  * Convert between Linux and BSD socket domain values
97  */
98 int
99 linux_to_bsd_domain(ldom)
100 	int ldom;
101 {
102 
103 	switch (ldom) {
104 	case LINUX_AF_UNSPEC:
105 		return AF_UNSPEC;
106 	case LINUX_AF_UNIX:
107 		return AF_LOCAL;
108 	case LINUX_AF_INET:
109 		return AF_INET;
110 	case LINUX_AF_AX25:
111 		return AF_CCITT;
112 	case LINUX_AF_IPX:
113 		return AF_IPX;
114 	case LINUX_AF_APPLETALK:
115 		return AF_APPLETALK;
116 	case LINUX_AF_X25:
117 		return AF_CCITT;
118 	case LINUX_AF_INET6:
119 		return AF_INET6;
120 	case LINUX_AF_DECnet:
121 		return AF_DECnet;
122 	case LINUX_AF_NETLINK:
123 		return AF_ROUTE;
124 	/* NETROM, BRIDGE, ATMPVC, ROSE, NETBEUI, SECURITY, */
125 	/* pseudo_AF_KEY, PACKET, ASH, ECONET, ATMSVC, SNA */
126 	default:
127 		return -1;
128 	}
129 }
130 
131 int
132 linux_sys_socket(p, v, retval)
133 	struct proc *p;
134 	void *v;
135 	register_t *retval;
136 {
137 	struct linux_sys_socket_args /* {
138 		syscallarg(int)	domain;
139 		syscallarg(int)	type;
140 		syscallarg(int) protocol;
141 	} */ *uap = v;
142 	struct sys_socket_args bsa;
143 
144 	SCARG(&bsa, protocol) = SCARG(uap, protocol);
145 	SCARG(&bsa, type) = SCARG(uap, type);
146 	SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain));
147 	if (SCARG(&bsa, domain) == -1)
148 		return EINVAL;
149 	return sys_socket(p, &bsa, retval);
150 }
151 
152 int
153 linux_sys_socketpair(p, v, retval)
154 	struct proc *p;
155 	void *v;
156 	register_t *retval;
157 {
158 	struct linux_sys_socketpair_args /* {
159 		syscallarg(int) domain;
160 		syscallarg(int) type;
161 		syscallarg(int) protocol;
162 		syscallarg(int *) rsv;
163 	} */ *uap = v;
164 	struct sys_socketpair_args bsa;
165 
166 	SCARG(&bsa, domain) = linux_to_bsd_domain(SCARG(uap, domain));
167 	if (SCARG(&bsa, domain) == -1)
168 		return EINVAL;
169 	SCARG(&bsa, type) = SCARG(uap, type);
170 	SCARG(&bsa, protocol) = SCARG(uap, protocol);
171 	SCARG(&bsa, rsv) = SCARG(uap, rsv);
172 
173 	return sys_socketpair(p, &bsa, retval);
174 }
175 
176 int
177 linux_sys_sendto(p, v, retval)
178 	struct proc *p;
179 	void *v;
180 	register_t *retval;
181 {
182 	struct linux_sys_sendto_args /* {
183 		syscallarg(int) s;
184 		syscallarg(void *) msg;
185 		syscallarg(int) len;
186 		syscallarg(int) flags;
187 		syscallarg(sockaddr *) to;
188 		syscallarg(int) tolen;
189 	} */ *uap = v;
190 	struct sys_sendto_args bsa;
191 
192 	SCARG(&bsa, s) = SCARG(uap, s);
193 	SCARG(&bsa, buf) = SCARG(uap, msg);
194 	SCARG(&bsa, len) = SCARG(uap, len);
195 	SCARG(&bsa, flags) = SCARG(uap, flags);
196 	SCARG(&bsa, to) = (void *) SCARG(uap, to);
197 	SCARG(&bsa, tolen) = SCARG(uap, tolen);
198 
199 	return sys_sendto(p, &bsa, retval);
200 }
201 
202 int
203 linux_sys_recvfrom(p, v, retval)
204 	struct proc *p;
205 	void *v;
206 	register_t *retval;
207 {
208 	struct linux_sys_recvfrom_args /* {
209 		syscallarg(int) s;
210 		syscallarg(void *) buf;
211 		syscallarg(int) len;
212 		syscallarg(int) flags;
213 		syscallarg(struct sockaddr *) from;
214 		syscallarg(int *) fromlen;
215 	} */ *uap = v;
216 	struct compat_43_sys_recvfrom_args bra;
217 
218 	SCARG(&bra, s) = SCARG(uap, s);
219 	SCARG(&bra, buf) = SCARG(uap, buf);
220 	SCARG(&bra, len) = SCARG(uap, len);
221 	SCARG(&bra, flags) = SCARG(uap, flags);
222 	SCARG(&bra, from) = (caddr_t) SCARG(uap, from);
223 	SCARG(&bra, fromlenaddr) = SCARG(uap, fromlen);
224 
225 	return compat_43_sys_recvfrom(p, &bra, retval);
226 }
227 
228 /*
229  * Convert socket option level from Linux to NetBSD value. Only SOL_SOCKET
230  * is different, the rest matches IPPROTO_* on both systems.
231  */
232 int
233 linux_to_bsd_sopt_level(llevel)
234 	int llevel;
235 {
236 
237 	switch (llevel) {
238 	case LINUX_SOL_SOCKET:
239 		return SOL_SOCKET;
240 	case LINUX_SOL_IP:
241 		return IPPROTO_IP;
242 	case LINUX_SOL_TCP:
243 		return IPPROTO_TCP;
244 	case LINUX_SOL_UDP:
245 		return IPPROTO_UDP;
246 	default:
247 		return -1;
248 	}
249 }
250 
251 /*
252  * Convert Linux socket level socket option numbers to NetBSD values.
253  */
254 int
255 linux_to_bsd_so_sockopt(lopt)
256 	int lopt;
257 {
258 
259 	switch (lopt) {
260 	case LINUX_SO_DEBUG:
261 		return SO_DEBUG;
262 	case LINUX_SO_REUSEADDR:
263 		return SO_REUSEADDR;
264 	case LINUX_SO_TYPE:
265 		return SO_TYPE;
266 	case LINUX_SO_ERROR:
267 		return SO_ERROR;
268 	case LINUX_SO_DONTROUTE:
269 		return SO_DONTROUTE;
270 	case LINUX_SO_BROADCAST:
271 		return SO_BROADCAST;
272 	case LINUX_SO_SNDBUF:
273 		return SO_SNDBUF;
274 	case LINUX_SO_RCVBUF:
275 		return SO_RCVBUF;
276 	case LINUX_SO_KEEPALIVE:
277 		return SO_KEEPALIVE;
278 	case LINUX_SO_OOBINLINE:
279 		return SO_OOBINLINE;
280 	case LINUX_SO_LINGER:
281 		return SO_LINGER;
282 	case LINUX_SO_PRIORITY:
283 	case LINUX_SO_NO_CHECK:
284 	default:
285 		return -1;
286 	}
287 }
288 
289 /*
290  * Convert Linux IP level socket option number to NetBSD values.
291  */
292 int
293 linux_to_bsd_ip_sockopt(lopt)
294 	int lopt;
295 {
296 
297 	switch (lopt) {
298 	case LINUX_IP_TOS:
299 		return IP_TOS;
300 	case LINUX_IP_TTL:
301 		return IP_TTL;
302 	case LINUX_IP_MULTICAST_TTL:
303 		return IP_MULTICAST_TTL;
304 	case LINUX_IP_MULTICAST_LOOP:
305 		return IP_MULTICAST_LOOP;
306 	case LINUX_IP_MULTICAST_IF:
307 		return IP_MULTICAST_IF;
308 	case LINUX_IP_ADD_MEMBERSHIP:
309 		return IP_ADD_MEMBERSHIP;
310 	case LINUX_IP_DROP_MEMBERSHIP:
311 		return IP_DROP_MEMBERSHIP;
312 	default:
313 		return -1;
314 	}
315 }
316 
317 /*
318  * Convert Linux TCP level socket option number to NetBSD values.
319  */
320 int
321 linux_to_bsd_tcp_sockopt(lopt)
322 	int lopt;
323 {
324 
325 	switch (lopt) {
326 	case LINUX_TCP_NODELAY:
327 		return TCP_NODELAY;
328 	case LINUX_TCP_MAXSEG:
329 		return TCP_MAXSEG;
330 	default:
331 		return -1;
332 	}
333 }
334 
335 /*
336  * Convert Linux UDP level socket option number to NetBSD values.
337  */
338 int
339 linux_to_bsd_udp_sockopt(lopt)
340 	int lopt;
341 {
342 
343 	switch (lopt) {
344 	default:
345 		return -1;
346 	}
347 }
348 
349 /*
350  * Another reasonably straightforward function: setsockopt(2).
351  * The level and option numbers are converted; the values passed
352  * are not (yet) converted, the ones currently implemented don't
353  * need conversion, as they are the same on both systems.
354  */
355 int
356 linux_sys_setsockopt(p, v, retval)
357 	struct proc *p;
358 	void *v;
359 	register_t *retval;
360 {
361 	struct linux_sys_setsockopt_args /* {
362 		syscallarg(int) s;
363 		syscallarg(int) level;
364 		syscallarg(int) optname;
365 		syscallarg(void *) optval;
366 		syscallarg(int) optlen;
367 	} */ *uap = v;
368 	struct sys_setsockopt_args bsa;
369 	int name;
370 
371 	SCARG(&bsa, s) = SCARG(uap, s);
372 	SCARG(&bsa, level) = linux_to_bsd_sopt_level(SCARG(uap, level));
373 	SCARG(&bsa, val) = SCARG(uap, optval);
374 	SCARG(&bsa, valsize) = SCARG(uap, optlen);
375 
376 	switch (SCARG(&bsa, level)) {
377 		case SOL_SOCKET:
378 			name = linux_to_bsd_so_sockopt(SCARG(uap, optname));
379 			break;
380 		case IPPROTO_IP:
381 			name = linux_to_bsd_ip_sockopt(SCARG(uap, optname));
382 			break;
383 		case IPPROTO_TCP:
384 			name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname));
385 			break;
386 		case IPPROTO_UDP:
387 			name = linux_to_bsd_udp_sockopt(SCARG(uap, optname));
388 			break;
389 		default:
390 			return EINVAL;
391 	}
392 
393 	if (name == -1)
394 		return EINVAL;
395 	SCARG(&bsa, name) = name;
396 
397 	return sys_setsockopt(p, &bsa, retval);
398 }
399 
400 /*
401  * getsockopt(2) is very much the same as setsockopt(2) (see above)
402  */
403 int
404 linux_sys_getsockopt(p, v, retval)
405 	struct proc *p;
406 	void *v;
407 	register_t *retval;
408 {
409 	struct linux_sys_getsockopt_args /* {
410 		syscallarg(int) s;
411 		syscallarg(int) level;
412 		syscallarg(int) optname;
413 		syscallarg(void *) optval;
414 		syscallarg(int *) optlen;
415 	} */ *uap = v;
416 	struct sys_getsockopt_args bga;
417 	int name;
418 
419 	SCARG(&bga, s) = SCARG(uap, s);
420 	SCARG(&bga, level) = linux_to_bsd_sopt_level(SCARG(uap, level));
421 	SCARG(&bga, val) = SCARG(uap, optval);
422 	SCARG(&bga, avalsize) = SCARG(uap, optlen);
423 
424 	switch (SCARG(&bga, level)) {
425 		case SOL_SOCKET:
426 			name = linux_to_bsd_so_sockopt(SCARG(uap, optname));
427 			break;
428 		case IPPROTO_IP:
429 			name = linux_to_bsd_ip_sockopt(SCARG(uap, optname));
430 			break;
431 		case IPPROTO_TCP:
432 			name = linux_to_bsd_tcp_sockopt(SCARG(uap, optname));
433 			break;
434 		case IPPROTO_UDP:
435 			name = linux_to_bsd_udp_sockopt(SCARG(uap, optname));
436 			break;
437 		default:
438 			return EINVAL;
439 	}
440 
441 	if (name == -1)
442 		return EINVAL;
443 	SCARG(&bga, name) = name;
444 
445 	return sys_getsockopt(p, &bga, retval);
446 }
447 
448 #define IF_NAME_LEN 16
449 
450 int
451 linux_getifhwaddr(p, retval, fd, data)
452 	struct proc *p;
453 	register_t *retval;
454 	u_int fd;
455 	void *data;
456 {
457 	/* Not the full structure, just enough to map what we do here */
458 	struct linux_ifreq {
459 		char if_name[IF_NAME_LEN];
460 		struct osockaddr hwaddr;
461 	} lreq;
462 	struct filedesc *fdp;
463 	struct file *fp;
464 	struct ifaddr *ifa;
465 	struct ifnet *ifp;
466 	struct sockaddr_dl *sadl;
467 	int error, found;
468 	int index, ifnum;
469 
470 	/*
471 	 * We can't emulate this ioctl by calling sys_ioctl() to run
472 	 * SIOCGIFCONF, because the user buffer is not of the right
473 	 * type to take those results.  We can't use kernel buffers to
474 	 * receive the results, as the implementation of sys_ioctl()
475 	 * and ifconf() [which implements SIOCGIFCONF] use
476 	 * copyin()/copyout() which will fail on kernel addresses.
477 	 *
478 	 * So, we must duplicate code from sys_ioctl() and ifconf().  Ugh.
479 	 */
480 
481 	fdp = p->p_fd;
482 	if (fd >= fdp->fd_nfiles ||
483 	    (fp = fdp->fd_ofiles[fd]) == NULL ||
484 	    (fp->f_iflags & FIF_WANTCLOSE) != 0)
485 		return (EBADF);
486 
487 	FILE_USE(fp);
488 	if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
489 		error = EBADF;
490 		goto out;
491 	}
492 
493 	error = copyin(data, (caddr_t)&lreq, sizeof(lreq));
494 	if (error)
495 		goto out;
496 	lreq.if_name[IF_NAME_LEN-1] = '\0';		/* just in case */
497 
498 	/*
499 	 * Try real interface name first, then fake "ethX"
500 	 */
501 	for (ifp = ifnet.tqh_first, found = 0;
502 	     ifp != 0 && !found;
503 	     ifp = ifp->if_list.tqe_next) {
504 		if (strcmp(lreq.if_name, ifp->if_xname))
505 			/* not this interface */
506 			continue;
507 		found=1;
508 		if ((ifa = ifp->if_addrlist.tqh_first) != 0) {
509 			for (; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
510 				sadl = (struct sockaddr_dl *)ifa->ifa_addr;
511 				/* only return ethernet addresses */
512 				/* XXX what about FDDI, etc. ? */
513 				if (sadl->sdl_family != AF_LINK ||
514 				    sadl->sdl_type != IFT_ETHER)
515 					continue;
516 				memcpy((caddr_t)&lreq.hwaddr.sa_data,
517 				       LLADDR(sadl),
518 				       MIN(sadl->sdl_alen,
519 					   sizeof(lreq.hwaddr.sa_data)));
520 				lreq.hwaddr.sa_family =
521 					sadl->sdl_family;
522 				error = copyout((caddr_t)&lreq, data,
523 						sizeof(lreq));
524 				goto out;
525 			}
526 		} else {
527 			error = ENODEV;
528 			goto out;
529 		}
530 	}
531 
532 	if (lreq.if_name[0] == 'e' &&
533 	    lreq.if_name[1] == 't' &&
534 	    lreq.if_name[2] == 'h') {
535 		for (ifnum = 0, index = 3;
536 		     lreq.if_name[index] != '\0' && index < IF_NAME_LEN;
537 		     index++) {
538 			ifnum *= 10;
539 			ifnum += lreq.if_name[index] - '0';
540 		}
541 
542 		error = EINVAL;			/* in case we don't find one */
543 		for (ifp = ifnet.tqh_first, found = 0;
544 		     ifp != 0 && !found;
545 		     ifp = ifp->if_list.tqe_next) {
546 			memcpy(lreq.if_name, ifp->if_xname,
547 			       MIN(IF_NAME_LEN, IFNAMSIZ));
548 			if ((ifa = ifp->if_addrlist.tqh_first) == 0)
549 				/* no addresses on this interface */
550 				continue;
551 			else
552 				for (; ifa != 0; ifa = ifa->ifa_list.tqe_next) {
553 					sadl = (struct sockaddr_dl *)ifa->ifa_addr;
554 					/* only return ethernet addresses */
555 					/* XXX what about FDDI, etc. ? */
556 					if (sadl->sdl_family != AF_LINK ||
557 					    sadl->sdl_type != IFT_ETHER)
558 						continue;
559 					if (ifnum--)
560 						/* not the reqested iface */
561 						continue;
562 					memcpy((caddr_t)&lreq.hwaddr.sa_data,
563 					       LLADDR(sadl),
564 					       MIN(sadl->sdl_alen,
565 						   sizeof(lreq.hwaddr.sa_data)));
566 					lreq.hwaddr.sa_family =
567 						sadl->sdl_family;
568 					error = copyout((caddr_t)&lreq, data,
569 							sizeof(lreq));
570 					found = 1;
571 					break;
572 				}
573 		}
574 	} else {
575 		/* unknown interface, not even an "eth*" name */
576 		error = ENODEV;
577 	}
578 
579 out:
580 	FILE_UNUSE(fp, p);
581 	return error;
582 }
583 #undef IF_NAME_LEN
584 
585 int
586 linux_ioctl_socket(p, uap, retval)
587 	struct proc *p;
588 	struct linux_sys_ioctl_args /* {
589 		syscallarg(int) fd;
590 		syscallarg(u_long) com;
591 		syscallarg(caddr_t) data;
592 	} */ *uap;
593 	register_t *retval;
594 {
595 	u_long com;
596 	int error = 0, isdev = 0, dosys = 1;
597 	struct sys_ioctl_args ia;
598 	struct file *fp;
599 	struct filedesc *fdp;
600 	struct vnode *vp;
601 	int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *));
602 	struct ioctl_pt pt;
603 
604         fdp = p->p_fd;
605 	if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
606 	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL ||
607 	    (fp->f_iflags & FIF_WANTCLOSE) != 0)
608 		return (EBADF);
609 
610 	FILE_USE(fp);
611 
612 	if (fp->f_type == DTYPE_VNODE) {
613 		vp = (struct vnode *)fp->f_data;
614 		isdev = vp->v_type == VCHR;
615 	}
616 
617 	/*
618 	 * Don't try to interpret socket ioctl calls that are done
619 	 * on a device filedescriptor, just pass them through, to
620 	 * emulate Linux behaviour. Use PTIOCLINUX so that the
621 	 * device will only handle these if it's prepared to do
622 	 * so, to avoid unexpected things from happening.
623 	 */
624 	if (isdev) {
625 		dosys = 0;
626 		ioctlf = fp->f_ops->fo_ioctl;
627 		pt.com = SCARG(uap, com);
628 		pt.data = SCARG(uap, data);
629 		error = ioctlf(fp, PTIOCLINUX, (caddr_t)&pt, p);
630 		/*
631 		 * XXX hack: if the function returns EJUSTRETURN,
632 		 * it has stuffed a sysctl return value in pt.data.
633 		 */
634 		if (error == EJUSTRETURN) {
635 			retval[0] = (register_t)pt.data;
636 			error = 0;
637 		}
638 		goto out;
639 	}
640 
641 	com = SCARG(uap, com);
642 	retval[0] = 0;
643 
644 	switch (com) {
645 	case LINUX_SIOCGIFCONF:
646 		SCARG(&ia, com) = OSIOCGIFCONF;
647 		break;
648 	case LINUX_SIOCGIFFLAGS:
649 		SCARG(&ia, com) = SIOCGIFFLAGS;
650 		break;
651 	case LINUX_SIOCSIFFLAGS:
652 		SCARG(&ia, com) = SIOCSIFFLAGS;
653 		break;
654 	case LINUX_SIOCGIFADDR:
655 		SCARG(&ia, com) = OSIOCGIFADDR;
656 		break;
657 	case LINUX_SIOCGIFDSTADDR:
658 		SCARG(&ia, com) = OSIOCGIFDSTADDR;
659 		break;
660 	case LINUX_SIOCGIFBRDADDR:
661 		SCARG(&ia, com) = OSIOCGIFBRDADDR;
662 		break;
663 	case LINUX_SIOCGIFNETMASK:
664 		SCARG(&ia, com) = OSIOCGIFNETMASK;
665 		break;
666 	case LINUX_SIOCADDMULTI:
667 		SCARG(&ia, com) = SIOCADDMULTI;
668 		break;
669 	case LINUX_SIOCDELMULTI:
670 		SCARG(&ia, com) = SIOCDELMULTI;
671 		break;
672 	case LINUX_SIOCGIFHWADDR:
673 	        error = linux_getifhwaddr(p, retval, SCARG(uap, fd),
674 					 SCARG(uap, data));
675 		dosys = 0;
676 		break;
677 	default:
678 		error = EINVAL;
679 	}
680 
681 out:
682 	FILE_UNUSE(fp, p);
683 
684 	if (error ==0 && dosys) {
685 		SCARG(&ia, fd) = SCARG(uap, fd);
686 		SCARG(&ia, data) = SCARG(uap, data);
687 		error = sys_ioctl(p, &ia, retval);
688 	}
689 
690 	return error;
691 }
692 
693 int
694 linux_sys_connect(p, v, retval)
695 	struct proc *p;
696 	void *v;
697 	register_t *retval;
698 {
699 	int error;
700 
701 	struct sys_connect_args /* {
702 		syscallarg(int) s;
703 		syscallarg(const struct sockaddr *) name;
704 		syscallarg(unsigned int) namelen;
705 	} */ *uap = v;
706 
707 	error = sys_connect (p, v, retval);
708 
709 	if (error == EISCONN) {
710 		struct file *fp;
711 		struct socket *so;
712 		int s, state, prflags;
713 
714 		/* getsock() will use the descriptor for us */
715 	    	if (getsock(p->p_fd, SCARG(uap, s), &fp) != 0)
716 		    	return EISCONN;
717 
718 		s = splsoftnet();
719 		so = (struct socket *)fp->f_data;
720 		state = so->so_state;
721 		prflags = so->so_proto->pr_flags;
722 		splx(s);
723 		FILE_UNUSE(fp, p);
724 		/*
725 		 * We should only let this call succeed once per
726 		 * non-blocking connect; however we don't have
727 		 * a convenient place to keep that state..
728 		 */
729 		if ((state & SS_NBIO) && (state & SS_ISCONNECTED) &&
730 		    (prflags & PR_CONNREQUIRED))
731 			return 0;
732 	}
733 
734 	return error;
735 }
736