xref: /netbsd-src/sys/compat/linux/common/linux_socket.c (revision 4472dbe5e3bd91ef2540bada7a7ca7384627ff9b)
1 /*	$NetBSD: linux_socket.c,v 1.24 2000/05/03 21:41:43 thorpej 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 	struct sys_ioctl_args ia;
601 
602 	com = SCARG(uap, com);
603 	retval[0] = 0;
604 
605 	switch (com) {
606 	case LINUX_SIOCGIFCONF:
607 		SCARG(&ia, com) = OSIOCGIFCONF;
608 		break;
609 	case LINUX_SIOCGIFFLAGS:
610 		SCARG(&ia, com) = SIOCGIFFLAGS;
611 		break;
612 	case LINUX_SIOCGIFADDR:
613 		SCARG(&ia, com) = OSIOCGIFADDR;
614 		break;
615 	case LINUX_SIOCGIFDSTADDR:
616 		SCARG(&ia, com) = OSIOCGIFDSTADDR;
617 		break;
618 	case LINUX_SIOCGIFBRDADDR:
619 		SCARG(&ia, com) = OSIOCGIFBRDADDR;
620 		break;
621 	case LINUX_SIOCGIFNETMASK:
622 		SCARG(&ia, com) = OSIOCGIFNETMASK;
623 		break;
624 	case LINUX_SIOCADDMULTI:
625 		SCARG(&ia, com) = SIOCADDMULTI;
626 		break;
627 	case LINUX_SIOCDELMULTI:
628 		SCARG(&ia, com) = SIOCDELMULTI;
629 		break;
630 	case LINUX_SIOCGIFHWADDR:
631 	        return linux_getifhwaddr(p, retval, SCARG(uap, fd),
632 					 SCARG(uap, data));
633 	default:
634 		return EINVAL;
635 	}
636 
637 	SCARG(&ia, fd) = SCARG(uap, fd);
638 	SCARG(&ia, data) = SCARG(uap, data);
639 	return sys_ioctl(p, &ia, retval);
640 }
641 
642 int
643 linux_sys_connect(p, v, retval)
644 	struct proc *p;
645 	void *v;
646 	register_t *retval;
647 {
648 	int error;
649 
650 	struct sys_connect_args /* {
651 		syscallarg(int) s;
652 		syscallarg(const struct sockaddr *) name;
653 		syscallarg(unsigned int) namelen;
654 	} */ *uap = v;
655 
656 	error = sys_connect (p, v, retval);
657 
658 	if (error == EISCONN) {
659 		struct file *fp;
660 		struct socket *so;
661 		int s, state, prflags;
662 
663 		/* getsock() will use the descriptor for us */
664 	    	if (getsock(p->p_fd, SCARG(uap, s), &fp) != 0)
665 		    	return EISCONN;
666 
667 		s = splsoftnet();
668 		so = (struct socket *)fp->f_data;
669 		state = so->so_state;
670 		prflags = so->so_proto->pr_flags;
671 		splx(s);
672 		FILE_UNUSE(fp, p);
673 		/*
674 		 * We should only let this call succeed once per
675 		 * non-blocking connect; however we don't have
676 		 * a convenient place to keep that state..
677 		 */
678 		if ((state & SS_NBIO) && (state & SS_ISCONNECTED) &&
679 		    (prflags & PR_CONNREQUIRED))
680 			return 0;
681 	}
682 
683 	return error;
684 }
685