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