xref: /freebsd/sys/compat/linux/linux_socket.c (revision 2e21a3ef7e069120595b83bf20a785a1668c3906)
1 /*-
2  * Copyright (c) 1995 S�ren Schmidt
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  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 /* XXX we use functions that might not exist. */
33 #include "opt_compat.h"
34 #include "opt_inet6.h"
35 
36 #include <sys/param.h>
37 #include <sys/proc.h>
38 #include <sys/systm.h>
39 #include <sys/sysproto.h>
40 #include <sys/fcntl.h>
41 #include <sys/file.h>
42 #include <sys/limits.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mutex.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/syscallsubr.h>
50 #include <sys/uio.h>
51 #include <sys/syslog.h>
52 
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #ifdef INET6
57 #include <netinet/ip6.h>
58 #include <netinet6/ip6_var.h>
59 #endif
60 
61 #ifdef COMPAT_LINUX32
62 #include <machine/../linux32/linux.h>
63 #include <machine/../linux32/linux32_proto.h>
64 #else
65 #include <machine/../linux/linux.h>
66 #include <machine/../linux/linux_proto.h>
67 #endif
68 #include <compat/linux/linux_socket.h>
69 #include <compat/linux/linux_util.h>
70 
71 static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
72     struct malloc_type *);
73 static int linux_to_bsd_domain(int);
74 
75 #ifdef __alpha__
76 #define	STATIC
77 #else
78 #define	STATIC static
79 #endif
80 
81 /*
82  * Reads a linux sockaddr and does any necessary translation.
83  * Linux sockaddrs don't have a length field, only a family.
84  */
85 static int
86 linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
87 {
88 	int osalen = len;
89 
90 	return (do_sa_get(sap, osa, &osalen, M_SONAME));
91 }
92 
93 /*
94  * Copy the osockaddr structure pointed to by osa to kernel, adjust
95  * family and convert to sockaddr.
96  */
97 static int
98 do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
99     struct malloc_type *mtype)
100 {
101 	int error=0, bdom;
102 	struct sockaddr *sa;
103 	struct osockaddr *kosa;
104 	int alloclen;
105 #ifdef INET6
106 	int oldv6size;
107 	struct sockaddr_in6 *sin6;
108 #endif
109 
110 	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
111 		return (EINVAL);
112 
113 	alloclen = *osalen;
114 #ifdef INET6
115 	oldv6size = 0;
116 	/*
117 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
118 	 * if it's a v4-mapped address, so reserve the proper space
119 	 * for it.
120 	 */
121 	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
122 		alloclen = sizeof (struct sockaddr_in6);
123 		oldv6size = 1;
124 	}
125 #endif
126 
127 	MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
128 
129 	if ((error = copyin(osa, kosa, *osalen)))
130 		goto out;
131 
132 	bdom = linux_to_bsd_domain(kosa->sa_family);
133 	if (bdom == -1) {
134 		error = EINVAL;
135 		goto out;
136 	}
137 
138 #ifdef INET6
139 	/*
140 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
141 	 * which lacks the scope id compared with RFC2553 one. If we detect
142 	 * the situation, reject the address and write a message to system log.
143 	 *
144 	 * Still accept addresses for which the scope id is not used.
145 	 */
146 	if (oldv6size && bdom == AF_INET6) {
147 		sin6 = (struct sockaddr_in6 *)kosa;
148 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
149 		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
150 		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
151 		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
152 		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
153 		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
154 			sin6->sin6_scope_id = 0;
155 		} else {
156 			log(LOG_DEBUG,
157 			    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
158 			error = EINVAL;
159 			goto out;
160 		}
161 	} else
162 #endif
163 	if (bdom == AF_INET)
164 		alloclen = sizeof(struct sockaddr_in);
165 
166 	sa = (struct sockaddr *) kosa;
167 	sa->sa_family = bdom;
168 	sa->sa_len = alloclen;
169 
170 	*sap = sa;
171 	*osalen = alloclen;
172 	return (0);
173 
174 out:
175 	FREE(kosa, mtype);
176 	return (error);
177 }
178 
179 static int
180 linux_to_bsd_domain(int domain)
181 {
182 
183 	switch (domain) {
184 	case LINUX_AF_UNSPEC:
185 		return (AF_UNSPEC);
186 	case LINUX_AF_UNIX:
187 		return (AF_LOCAL);
188 	case LINUX_AF_INET:
189 		return (AF_INET);
190 	case LINUX_AF_INET6:
191 		return (AF_INET6);
192 	case LINUX_AF_AX25:
193 		return (AF_CCITT);
194 	case LINUX_AF_IPX:
195 		return (AF_IPX);
196 	case LINUX_AF_APPLETALK:
197 		return (AF_APPLETALK);
198 	}
199 	return (-1);
200 }
201 
202 static int
203 bsd_to_linux_domain(int domain)
204 {
205 
206 	switch (domain) {
207 	case AF_UNSPEC:
208 		return (LINUX_AF_UNSPEC);
209 	case AF_LOCAL:
210 		return (LINUX_AF_UNIX);
211 	case AF_INET:
212 		return (LINUX_AF_INET);
213 	case AF_INET6:
214 		return (LINUX_AF_INET6);
215 	case AF_CCITT:
216 		return (LINUX_AF_AX25);
217 	case AF_IPX:
218 		return (LINUX_AF_IPX);
219 	case AF_APPLETALK:
220 		return (LINUX_AF_APPLETALK);
221 	}
222 	return (-1);
223 }
224 
225 static int
226 linux_to_bsd_sockopt_level(int level)
227 {
228 
229 	switch (level) {
230 	case LINUX_SOL_SOCKET:
231 		return (SOL_SOCKET);
232 	}
233 	return (level);
234 }
235 
236 static int
237 bsd_to_linux_sockopt_level(int level)
238 {
239 
240 	switch (level) {
241 	case SOL_SOCKET:
242 		return (LINUX_SOL_SOCKET);
243 	}
244 	return (level);
245 }
246 
247 #ifndef __alpha__
248 static int
249 linux_to_bsd_ip_sockopt(int opt)
250 {
251 
252 	switch (opt) {
253 	case LINUX_IP_TOS:
254 		return (IP_TOS);
255 	case LINUX_IP_TTL:
256 		return (IP_TTL);
257 	case LINUX_IP_OPTIONS:
258 		return (IP_OPTIONS);
259 	case LINUX_IP_MULTICAST_IF:
260 		return (IP_MULTICAST_IF);
261 	case LINUX_IP_MULTICAST_TTL:
262 		return (IP_MULTICAST_TTL);
263 	case LINUX_IP_MULTICAST_LOOP:
264 		return (IP_MULTICAST_LOOP);
265 	case LINUX_IP_ADD_MEMBERSHIP:
266 		return (IP_ADD_MEMBERSHIP);
267 	case LINUX_IP_DROP_MEMBERSHIP:
268 		return (IP_DROP_MEMBERSHIP);
269 	case LINUX_IP_HDRINCL:
270 		return (IP_HDRINCL);
271 	}
272 	return (-1);
273 }
274 
275 static int
276 linux_to_bsd_so_sockopt(int opt)
277 {
278 
279 	switch (opt) {
280 	case LINUX_SO_DEBUG:
281 		return (SO_DEBUG);
282 	case LINUX_SO_REUSEADDR:
283 		return (SO_REUSEADDR);
284 	case LINUX_SO_TYPE:
285 		return (SO_TYPE);
286 	case LINUX_SO_ERROR:
287 		return (SO_ERROR);
288 	case LINUX_SO_DONTROUTE:
289 		return (SO_DONTROUTE);
290 	case LINUX_SO_BROADCAST:
291 		return (SO_BROADCAST);
292 	case LINUX_SO_SNDBUF:
293 		return (SO_SNDBUF);
294 	case LINUX_SO_RCVBUF:
295 		return (SO_RCVBUF);
296 	case LINUX_SO_KEEPALIVE:
297 		return (SO_KEEPALIVE);
298 	case LINUX_SO_OOBINLINE:
299 		return (SO_OOBINLINE);
300 	case LINUX_SO_LINGER:
301 		return (SO_LINGER);
302 	}
303 	return (-1);
304 }
305 #endif /* !__alpha__*/
306 
307 static int
308 linux_to_bsd_msg_flags(int flags)
309 {
310 	int ret_flags = 0;
311 
312 	if (flags & LINUX_MSG_OOB)
313 		ret_flags |= MSG_OOB;
314 	if (flags & LINUX_MSG_PEEK)
315 		ret_flags |= MSG_PEEK;
316 	if (flags & LINUX_MSG_DONTROUTE)
317 		ret_flags |= MSG_DONTROUTE;
318 	if (flags & LINUX_MSG_CTRUNC)
319 		ret_flags |= MSG_CTRUNC;
320 	if (flags & LINUX_MSG_TRUNC)
321 		ret_flags |= MSG_TRUNC;
322 	if (flags & LINUX_MSG_DONTWAIT)
323 		ret_flags |= MSG_DONTWAIT;
324 	if (flags & LINUX_MSG_EOR)
325 		ret_flags |= MSG_EOR;
326 	if (flags & LINUX_MSG_WAITALL)
327 		ret_flags |= MSG_WAITALL;
328 	if (flags & LINUX_MSG_NOSIGNAL)
329 		ret_flags |= MSG_NOSIGNAL;
330 #if 0 /* not handled */
331 	if (flags & LINUX_MSG_PROXY)
332 		;
333 	if (flags & LINUX_MSG_FIN)
334 		;
335 	if (flags & LINUX_MSG_SYN)
336 		;
337 	if (flags & LINUX_MSG_CONFIRM)
338 		;
339 	if (flags & LINUX_MSG_RST)
340 		;
341 	if (flags & LINUX_MSG_ERRQUEUE)
342 		;
343 #endif
344 	return ret_flags;
345 }
346 
347 /*
348 * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
349 * native syscall will fault.  Thus, we don't really need to check the
350 * return values for these functions.
351 */
352 
353 static int
354 bsd_to_linux_sockaddr(struct sockaddr *arg)
355 {
356 	struct sockaddr sa;
357 	size_t sa_len = sizeof(struct sockaddr);
358 	int error;
359 
360 	if ((error = copyin(arg, &sa, sa_len)))
361 		return (error);
362 
363 	*(u_short *)&sa = sa.sa_family;
364 
365 	error = copyout(&sa, arg, sa_len);
366 
367 	return (error);
368 }
369 
370 static int
371 linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
372 {
373 	struct sockaddr sa;
374 	size_t sa_len = sizeof(struct sockaddr);
375 	int error;
376 
377 	if ((error = copyin(arg, &sa, sa_len)))
378 		return (error);
379 
380 	sa.sa_family = *(sa_family_t *)&sa;
381 	sa.sa_len = len;
382 
383 	error = copyout(&sa, arg, sa_len);
384 
385 	return (error);
386 }
387 
388 
389 static int
390 linux_sa_put(struct osockaddr *osa)
391 {
392 	struct osockaddr sa;
393 	int error, bdom;
394 
395 	/*
396 	 * Only read/write the osockaddr family part, the rest is
397 	 * not changed.
398 	 */
399 	error = copyin(osa, &sa, sizeof(sa.sa_family));
400 	if (error)
401 		return (error);
402 
403 	bdom = bsd_to_linux_domain(sa.sa_family);
404 	if (bdom == -1)
405 		return (EINVAL);
406 
407 	sa.sa_family = bdom;
408 	error = copyout(&sa, osa, sizeof(sa.sa_family));
409 	if (error)
410 		return (error);
411 
412 	return (0);
413 }
414 
415 static int
416 linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
417     enum uio_seg segflg)
418 {
419 	struct mbuf *control;
420 	struct sockaddr *to;
421 	int error;
422 
423 	if (mp->msg_name != NULL) {
424 		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
425 		if (error)
426 			return (error);
427 		mp->msg_name = to;
428 	} else
429 		to = NULL;
430 
431 	if (mp->msg_control != NULL) {
432 		struct cmsghdr *cmsg;
433 
434 		if (mp->msg_controllen < sizeof(struct cmsghdr)) {
435 			error = EINVAL;
436 			goto bad;
437 		}
438 		error = sockargs(&control, mp->msg_control,
439 		    mp->msg_controllen, MT_CONTROL);
440 		if (error)
441 			goto bad;
442 
443 		cmsg = mtod(control, struct cmsghdr *);
444 		cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level);
445 	} else
446 		control = NULL;
447 
448 	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
449 	    segflg);
450 
451 bad:
452 	if (to)
453 		FREE(to, M_SONAME);
454 	return (error);
455 }
456 
457 #ifndef __alpha__
458 /* Return 0 if IP_HDRINCL is set for the given socket. */
459 static int
460 linux_check_hdrincl(struct thread *td, int s)
461 {
462 	int error, optval, size_val;
463 
464 	size_val = sizeof(optval);
465 	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
466 	    &optval, UIO_SYSSPACE, &size_val);
467 	if (error)
468 		return (error);
469 
470 	return (optval == 0);
471 }
472 
473 struct linux_sendto_args {
474 	int s;
475 	l_uintptr_t msg;
476 	int len;
477 	int flags;
478 	l_uintptr_t to;
479 	int tolen;
480 };
481 
482 /*
483  * Updated sendto() when IP_HDRINCL is set:
484  * tweak endian-dependent fields in the IP packet.
485  */
486 static int
487 linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
488 {
489 /*
490  * linux_ip_copysize defines how many bytes we should copy
491  * from the beginning of the IP packet before we customize it for BSD.
492  * It should include all the fields we modify (ip_len and ip_off).
493  */
494 #define linux_ip_copysize	8
495 
496 	struct ip *packet;
497 	struct msghdr msg;
498 	struct iovec aiov[1];
499 	int error;
500 
501 	/* Check that the packet isn't too big or too small. */
502 	if (linux_args->len < linux_ip_copysize ||
503 	    linux_args->len > IP_MAXPACKET)
504 		return (EINVAL);
505 
506 	packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
507 
508 	/* Make kernel copy of the packet to be sent */
509 	if ((error = copyin(PTRIN(linux_args->msg), packet,
510 	    linux_args->len)))
511 		goto goout;
512 
513 	/* Convert fields from Linux to BSD raw IP socket format */
514 	packet->ip_len = linux_args->len;
515 	packet->ip_off = ntohs(packet->ip_off);
516 
517 	/* Prepare the msghdr and iovec structures describing the new packet */
518 	msg.msg_name = PTRIN(linux_args->to);
519 	msg.msg_namelen = linux_args->tolen;
520 	msg.msg_iov = aiov;
521 	msg.msg_iovlen = 1;
522 	msg.msg_control = NULL;
523 	msg.msg_flags = 0;
524 	aiov[0].iov_base = (char *)packet;
525 	aiov[0].iov_len = linux_args->len;
526 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
527 	    UIO_SYSSPACE);
528 goout:
529 	free(packet, M_TEMP);
530 	return (error);
531 }
532 
533 struct linux_socket_args {
534 	int domain;
535 	int type;
536 	int protocol;
537 };
538 
539 static int
540 linux_socket(struct thread *td, struct linux_socket_args *args)
541 {
542 	struct linux_socket_args linux_args;
543 	struct socket_args /* {
544 		int domain;
545 		int type;
546 		int protocol;
547 	} */ bsd_args;
548 	int error;
549 	int retval_socket;
550 
551 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
552 		return (error);
553 
554 	bsd_args.protocol = linux_args.protocol;
555 	bsd_args.type = linux_args.type;
556 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
557 	if (bsd_args.domain == -1)
558 		return (EINVAL);
559 
560 	retval_socket = socket(td, &bsd_args);
561 	if (bsd_args.type == SOCK_RAW
562 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
563 	    && bsd_args.domain == AF_INET
564 	    && retval_socket >= 0) {
565 		/* It's a raw IP socket: set the IP_HDRINCL option. */
566 		int hdrincl;
567 
568 		hdrincl = 1;
569 		/* We ignore any error returned by kern_setsockopt() */
570 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
571 		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
572 	}
573 #ifdef INET6
574 	/*
575 	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
576 	 * default and some apps depend on this. So, set V6ONLY to 0
577 	 * for Linux apps if the sysctl value is set to 1.
578 	 */
579 	if (bsd_args.domain == PF_INET6 && retval_socket >= 0
580 #ifndef KLD_MODULE
581 	    /*
582 	     * XXX: Avoid undefined symbol error with an IPv4 only
583 	     * kernel.
584 	     */
585 	    && ip6_v6only
586 #endif
587 	    ) {
588 		int v6only;
589 
590 		v6only = 0;
591 		/* We ignore any error returned by setsockopt() */
592 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
593 		    &v6only, UIO_SYSSPACE, sizeof(v6only));
594 	}
595 #endif
596 
597 	return (retval_socket);
598 }
599 
600 struct linux_bind_args {
601 	int s;
602 	l_uintptr_t name;
603 	int namelen;
604 };
605 
606 static int
607 linux_bind(struct thread *td, struct linux_bind_args *args)
608 {
609 	struct linux_bind_args linux_args;
610 	struct sockaddr *sa;
611 	int error;
612 
613 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
614 		return (error);
615 
616 	error = linux_getsockaddr(&sa, PTRIN(linux_args.name),
617 	    linux_args.namelen);
618 	if (error)
619 		return (error);
620 
621 	return (kern_bind(td, linux_args.s, sa));
622 }
623 #endif /* !__alpha__*/
624 
625 struct l_connect_args {
626 	int s;
627 	l_uintptr_t name;
628 	int namelen;
629 };
630 #ifndef __alpha__
631 #define	linux_connect_args l_connect_args
632 int linux_connect(struct thread *, struct linux_connect_args *);
633 #endif /* !__alpha__*/
634 
635 int
636 linux_connect(struct thread *td, struct linux_connect_args *args)
637 {
638 	struct l_connect_args linux_args;
639 	struct socket *so;
640 	struct sockaddr *sa;
641 	u_int fflag;
642 	int error;
643 
644 #ifdef __alpha__
645 	bcopy(args, &linux_args, sizeof(linux_args));
646 #else
647 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
648 		return (error);
649 #endif /* __alpha__ */
650 
651 	error = linux_getsockaddr(&sa,
652 	    (struct osockaddr *)PTRIN(linux_args.name),
653 	    linux_args.namelen);
654 	if (error)
655 		return (error);
656 
657 	error = kern_connect(td, linux_args.s, sa);
658 	if (error != EISCONN)
659 		return (error);
660 
661 	/*
662 	 * Linux doesn't return EISCONN the first time it occurs,
663 	 * when on a non-blocking socket. Instead it returns the
664 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
665 	 */
666 	NET_LOCK_GIANT();
667 	error = fgetsock(td, linux_args.s, &so, &fflag);
668 	if (error == 0) {
669 		error = EISCONN;
670 		if (fflag & FNONBLOCK) {
671 			SOCK_LOCK(so);
672 			if (so->so_emuldata == 0)
673 				error = so->so_error;
674 			so->so_emuldata = (void *)1;
675 			SOCK_UNLOCK(so);
676 		}
677 		fputsock(so);
678 	}
679 	NET_UNLOCK_GIANT();
680 	return (error);
681 }
682 
683 #ifndef __alpha__
684 struct linux_listen_args {
685 	int s;
686 	int backlog;
687 };
688 
689 static int
690 linux_listen(struct thread *td, struct linux_listen_args *args)
691 {
692 	struct linux_listen_args linux_args;
693 	struct listen_args /* {
694 		int s;
695 		int backlog;
696 	} */ bsd_args;
697 	int error;
698 
699 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
700 		return (error);
701 
702 	bsd_args.s = linux_args.s;
703 	bsd_args.backlog = linux_args.backlog;
704 	return (listen(td, &bsd_args));
705 }
706 #endif /* !__alpha__*/
707 
708 struct l_accept_args {
709 	int s;
710 	l_uintptr_t addr;
711 	l_uintptr_t namelen;
712 };
713 
714 #ifndef __alpha__
715 #define	linux_accept_args l_accept_args
716 #endif
717 
718 STATIC int
719 linux_accept(struct thread *td, struct linux_accept_args *args)
720 {
721 	struct l_accept_args linux_args;
722 	struct accept_args /* {
723 		int	s;
724 		struct sockaddr * __restrict name;
725 		socklen_t * __restrict anamelen;
726 	} */ bsd_args;
727 	struct close_args /* {
728 		int     fd;
729 	} */ c_args;
730 	int error, fd;
731 
732 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
733 		return (error);
734 
735 	bsd_args.s = linux_args.s;
736 	/* XXX: */
737 	bsd_args.name = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
738 	bsd_args.anamelen = PTRIN(linux_args.namelen);/* XXX */
739 	error = accept(td, &bsd_args);
740 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
741 	if (error)
742 		return (error);
743 	if (linux_args.addr) {
744 		error = linux_sa_put(PTRIN(linux_args.addr));
745 		if (error) {
746 			c_args.fd = td->td_retval[0];
747 			(void)close(td, &c_args);
748 			return (error);
749 		}
750 	}
751 
752 	/*
753 	 * linux appears not to copy flags from the parent socket to the
754 	 * accepted one, so we must clear the flags in the new descriptor.
755 	 * Ignore any errors, because we already have an open fd.
756 	 */
757 	fd = td->td_retval[0];
758 	(void)kern_fcntl(td, fd, F_SETFL, 0);
759 	td->td_retval[0] = fd;
760 	return (0);
761 }
762 
763 struct l_getsockname_args {
764 	int s;
765 	l_uintptr_t addr;
766 	l_uintptr_t namelen;
767 };
768 
769 #ifndef __alpha__
770 #define linux_getsockname_args l_getsockname_args
771 #endif
772 
773 STATIC int
774 linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
775 {
776 	struct l_getsockname_args linux_args;
777 	struct getsockname_args /* {
778 		int	fdes;
779 		struct sockaddr * __restrict asa;
780 		socklen_t * __restrict alen;
781 	} */ bsd_args;
782 	int error;
783 
784 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
785 		return (error);
786 
787 	bsd_args.fdes = linux_args.s;
788 	/* XXX: */
789 	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
790 	bsd_args.alen = PTRIN(linux_args.namelen);	/* XXX */
791 	error = getsockname(td, &bsd_args);
792 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
793 	if (error)
794 		return (error);
795 	error = linux_sa_put(PTRIN(linux_args.addr));
796 	if (error)
797 		return (error);
798 	return (0);
799 }
800 
801 struct l_getpeername_args {
802 	int s;
803 	l_uintptr_t addr;
804 	l_uintptr_t namelen;
805 };
806 
807 #ifndef __alpha__
808 #define linux_getpeername_args l_getpeername_args
809 #endif
810 
811 STATIC int
812 linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
813 {
814 	struct l_getpeername_args linux_args;
815 	struct getpeername_args /* {
816 		int fdes;
817 		caddr_t asa;
818 		int *alen;
819 	} */ bsd_args;
820 	int error;
821 
822 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
823 		return (error);
824 
825 	bsd_args.fdes = linux_args.s;
826 	bsd_args.asa = (struct sockaddr *)PTRIN(linux_args.addr);
827 	bsd_args.alen = (int *)PTRIN(linux_args.namelen);
828 	error = getpeername(td, &bsd_args);
829 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
830 	if (error)
831 		return (error);
832 	error = linux_sa_put(PTRIN(linux_args.addr));
833 	if (error)
834 		return (error);
835 	return (0);
836 }
837 
838 struct l_socketpair_args {
839 	int domain;
840 	int type;
841 	int protocol;
842 	l_uintptr_t rsv;
843 };
844 
845 #ifndef __alpha__
846 #define linux_socketpair_args l_socketpair_args
847 #endif
848 
849 STATIC int
850 linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
851 {
852 	struct l_socketpair_args linux_args;
853 	struct socketpair_args /* {
854 		int domain;
855 		int type;
856 		int protocol;
857 		int *rsv;
858 	} */ bsd_args;
859 	int error;
860 
861 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
862 		return (error);
863 
864 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
865 	if (bsd_args.domain == -1)
866 		return (EINVAL);
867 
868 	bsd_args.type = linux_args.type;
869 	bsd_args.protocol = linux_args.protocol;
870 	bsd_args.rsv = (int *)PTRIN(linux_args.rsv);
871 	return (socketpair(td, &bsd_args));
872 }
873 
874 struct l_send_args {
875 	int s;
876 	l_uintptr_t msg;
877 	int len;
878 	int flags;
879 };
880 
881 #ifndef __alpha__
882 #define linux_send_args l_send_args
883 #endif
884 
885 STATIC int
886 linux_send(struct thread *td, struct linux_send_args *args)
887 {
888 	struct l_send_args linux_args;
889 	struct sendto_args /* {
890 		int s;
891 		caddr_t buf;
892 		int len;
893 		int flags;
894 		caddr_t to;
895 		int tolen;
896 	} */ bsd_args;
897 	int error;
898 
899 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
900 		return (error);
901 
902 	bsd_args.s = linux_args.s;
903 	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
904 	bsd_args.len = linux_args.len;
905 	bsd_args.flags = linux_args.flags;
906 	bsd_args.to = NULL;
907 	bsd_args.tolen = 0;
908 	return sendto(td, &bsd_args);
909 }
910 
911 struct l_recv_args {
912 	int s;
913 	l_uintptr_t msg;
914 	int len;
915 	int flags;
916 };
917 
918 #ifndef __alpha__
919 #define linux_recv_args l_recv_args
920 #endif
921 
922 STATIC int
923 linux_recv(struct thread *td, struct linux_recv_args *args)
924 {
925 	struct l_recv_args linux_args;
926 	struct recvfrom_args /* {
927 		int s;
928 		caddr_t buf;
929 		int len;
930 		int flags;
931 		struct sockaddr *from;
932 		socklen_t fromlenaddr;
933 	} */ bsd_args;
934 	int error;
935 
936 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
937 		return (error);
938 
939 	bsd_args.s = linux_args.s;
940 	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
941 	bsd_args.len = linux_args.len;
942 	bsd_args.flags = linux_args.flags;
943 	bsd_args.from = NULL;
944 	bsd_args.fromlenaddr = 0;
945 	return (recvfrom(td, &bsd_args));
946 }
947 
948 #ifndef __alpha__
949 static int
950 linux_sendto(struct thread *td, struct linux_sendto_args *args)
951 {
952 	struct linux_sendto_args linux_args;
953 	struct msghdr msg;
954 	struct iovec aiov;
955 	int error;
956 
957 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
958 		return (error);
959 
960 	if (linux_check_hdrincl(td, linux_args.s) == 0)
961 		/* IP_HDRINCL set, tweak the packet before sending */
962 		return (linux_sendto_hdrincl(td, &linux_args));
963 
964 	msg.msg_name = PTRIN(linux_args.to);
965 	msg.msg_namelen = linux_args.tolen;
966 	msg.msg_iov = &aiov;
967 	msg.msg_iovlen = 1;
968 	msg.msg_control = NULL;
969 	msg.msg_flags = 0;
970 	aiov.iov_base = PTRIN(linux_args.msg);
971 	aiov.iov_len = linux_args.len;
972 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
973 	    UIO_USERSPACE);
974 	return (error);
975 }
976 #endif /* !__alpha__*/
977 
978 struct l_recvfrom_args {
979 	int s;
980 	l_uintptr_t buf;
981 	int len;
982 	int flags;
983 	l_uintptr_t from;
984 	l_uintptr_t fromlen;
985 };
986 
987 #ifndef __alpha__
988 #define linux_recvfrom_args l_recvfrom_args
989 #endif
990 
991 STATIC int
992 linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
993 {
994 	struct l_recvfrom_args linux_args;
995 	struct recvfrom_args /* {
996 		int	s;
997 		caddr_t	buf;
998 		size_t	len;
999 		int	flags;
1000 		struct sockaddr * __restrict from;
1001 		socklen_t * __restrict fromlenaddr;
1002 	} */ bsd_args;
1003 	size_t len;
1004 	int error;
1005 
1006 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1007 		return (error);
1008 
1009 	if ((error = copyin(PTRIN(linux_args.fromlen), &len, sizeof(size_t))))
1010 		return (error);
1011 
1012 	bsd_args.s = linux_args.s;
1013 	bsd_args.buf = PTRIN(linux_args.buf);
1014 	bsd_args.len = linux_args.len;
1015 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
1016 	/* XXX: */
1017 	bsd_args.from = (struct sockaddr * __restrict)PTRIN(linux_args.from);
1018 	bsd_args.fromlenaddr = PTRIN(linux_args.fromlen);/* XXX */
1019 
1020 	linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
1021 	error = recvfrom(td, &bsd_args);
1022 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
1023 
1024 	if (error)
1025 		return (error);
1026 	if (linux_args.from) {
1027 		error = linux_sa_put((struct osockaddr *)
1028 		    PTRIN(linux_args.from));
1029 		if (error)
1030 			return (error);
1031 	}
1032 	return (0);
1033 }
1034 
1035 struct l_sendmsg_args {
1036 	int s;
1037 	l_uintptr_t msg;
1038 	int flags;
1039 };
1040 
1041 #ifndef __alpha__
1042 #define linux_sendmsg_args l_sendmsg_args
1043 #endif
1044 
1045 STATIC int
1046 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1047 {
1048 	struct l_sendmsg_args linux_args;
1049 	struct msghdr msg;
1050 	struct iovec *iov;
1051 	int error;
1052 
1053 	/* XXXTJR sendmsg is broken on amd64 */
1054 
1055 	error = copyin(args, &linux_args, sizeof(linux_args));
1056 	if (error)
1057 		return (error);
1058 	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1059 	if (error)
1060 		return (error);
1061 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1062 	if (error)
1063 		return (error);
1064 	msg.msg_iov = iov;
1065 	msg.msg_flags = 0;
1066 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
1067 	    UIO_USERSPACE);
1068 	free(iov, M_IOV);
1069 	return (error);
1070 }
1071 
1072 struct l_recvmsg_args {
1073 	int s;
1074 	l_uintptr_t msg;
1075 	int flags;
1076 };
1077 
1078 #ifndef __alpha__
1079 #define linux_recvmsg_args l_recvmsg_args
1080 #endif
1081 
1082 STATIC int
1083 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
1084 {
1085 	struct l_recvmsg_args linux_args;
1086 	struct recvmsg_args /* {
1087 		int	s;
1088 		struct	msghdr *msg;
1089 		int	flags;
1090 	} */ bsd_args;
1091 	struct msghdr msg;
1092 	struct cmsghdr *cmsg;
1093 	int error;
1094 
1095 	/* XXXTJR recvmsg is broken on amd64 */
1096 
1097 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1098 		return (error);
1099 
1100 	bsd_args.s = linux_args.s;
1101 	bsd_args.msg = PTRIN(linux_args.msg);
1102 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
1103 	if (msg.msg_name) {
1104 	   	linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
1105 		      msg.msg_namelen);
1106 		error = recvmsg(td, &bsd_args);
1107 		bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name);
1108 	} else
1109 	   	error = recvmsg(td, &bsd_args);
1110 	if (error)
1111 		return (error);
1112 
1113 	if (bsd_args.msg->msg_control != NULL &&
1114 	    bsd_args.msg->msg_controllen > 0) {
1115 		cmsg = (struct cmsghdr*)bsd_args.msg->msg_control;
1116 		cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level);
1117 	}
1118 
1119 	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1120 	if (error)
1121 		return (error);
1122 	if (msg.msg_name && msg.msg_namelen > 2)
1123 		error = linux_sa_put(msg.msg_name);
1124 	return (error);
1125 }
1126 
1127 #ifndef __alpha__
1128 struct linux_shutdown_args {
1129 	int s;
1130 	int how;
1131 };
1132 
1133 static int
1134 linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1135 {
1136 	struct linux_shutdown_args linux_args;
1137 	struct shutdown_args /* {
1138 		int s;
1139 		int how;
1140 	} */ bsd_args;
1141 	int error;
1142 
1143 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1144 		return (error);
1145 
1146 	bsd_args.s = linux_args.s;
1147 	bsd_args.how = linux_args.how;
1148 	return (shutdown(td, &bsd_args));
1149 }
1150 
1151 struct linux_setsockopt_args {
1152 	int s;
1153 	int level;
1154 	int optname;
1155 	l_uintptr_t optval;
1156 	int optlen;
1157 };
1158 
1159 static int
1160 linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1161 {
1162 	struct linux_setsockopt_args linux_args;
1163 	struct setsockopt_args /* {
1164 		int s;
1165 		int level;
1166 		int name;
1167 		caddr_t val;
1168 		int valsize;
1169 	} */ bsd_args;
1170 	int error, name;
1171 
1172 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1173 		return (error);
1174 
1175 	bsd_args.s = linux_args.s;
1176 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1177 	switch (bsd_args.level) {
1178 	case SOL_SOCKET:
1179 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1180 		break;
1181 	case IPPROTO_IP:
1182 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1183 		break;
1184 	case IPPROTO_TCP:
1185 		/* Linux TCP option values match BSD's */
1186 		name = linux_args.optname;
1187 		break;
1188 	default:
1189 		name = -1;
1190 		break;
1191 	}
1192 	if (name == -1)
1193 		return (EINVAL);
1194 
1195 	bsd_args.name = name;
1196 	bsd_args.val = PTRIN(linux_args.optval);
1197 	bsd_args.valsize = linux_args.optlen;
1198 
1199 	if (name == IPV6_NEXTHOP) {
1200 		linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
1201 			bsd_args.valsize);
1202 		error = setsockopt(td, &bsd_args);
1203 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1204 	} else
1205 		error = setsockopt(td, &bsd_args);
1206 
1207 	return (error);
1208 }
1209 
1210 struct linux_getsockopt_args {
1211 	int s;
1212 	int level;
1213 	int optname;
1214 	l_uintptr_t optval;
1215 	l_uintptr_t optlen;
1216 };
1217 
1218 static int
1219 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1220 {
1221 	struct linux_getsockopt_args linux_args;
1222 	struct getsockopt_args /* {
1223 		int s;
1224 		int level;
1225 		int name;
1226 		caddr_t val;
1227 		int *avalsize;
1228 	} */ bsd_args;
1229 	int error, name;
1230 
1231 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
1232 		return (error);
1233 
1234 	bsd_args.s = linux_args.s;
1235 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1236 	switch (bsd_args.level) {
1237 	case SOL_SOCKET:
1238 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1239 		break;
1240 	case IPPROTO_IP:
1241 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1242 		break;
1243 	case IPPROTO_TCP:
1244 		/* Linux TCP option values match BSD's */
1245 		name = linux_args.optname;
1246 		break;
1247 	default:
1248 		name = -1;
1249 		break;
1250 	}
1251 	if (name == -1)
1252 		return (EINVAL);
1253 
1254 	bsd_args.name = name;
1255 	bsd_args.val = PTRIN(linux_args.optval);
1256 	bsd_args.avalsize = PTRIN(linux_args.optlen);
1257 
1258 	if (name == IPV6_NEXTHOP) {
1259 		error = getsockopt(td, &bsd_args);
1260 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1261 	} else
1262 		error = getsockopt(td, &bsd_args);
1263 
1264 	return (error);
1265 }
1266 
1267 int
1268 linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1269 {
1270 	void *arg = (void *)(intptr_t)args->args;
1271 
1272 	switch (args->what) {
1273 	case LINUX_SOCKET:
1274 		return (linux_socket(td, arg));
1275 	case LINUX_BIND:
1276 		return (linux_bind(td, arg));
1277 	case LINUX_CONNECT:
1278 		return (linux_connect(td, arg));
1279 	case LINUX_LISTEN:
1280 		return (linux_listen(td, arg));
1281 	case LINUX_ACCEPT:
1282 		return (linux_accept(td, arg));
1283 	case LINUX_GETSOCKNAME:
1284 		return (linux_getsockname(td, arg));
1285 	case LINUX_GETPEERNAME:
1286 		return (linux_getpeername(td, arg));
1287 	case LINUX_SOCKETPAIR:
1288 		return (linux_socketpair(td, arg));
1289 	case LINUX_SEND:
1290 		return (linux_send(td, arg));
1291 	case LINUX_RECV:
1292 		return (linux_recv(td, arg));
1293 	case LINUX_SENDTO:
1294 		return (linux_sendto(td, arg));
1295 	case LINUX_RECVFROM:
1296 		return (linux_recvfrom(td, arg));
1297 	case LINUX_SHUTDOWN:
1298 		return (linux_shutdown(td, arg));
1299 	case LINUX_SETSOCKOPT:
1300 		return (linux_setsockopt(td, arg));
1301 	case LINUX_GETSOCKOPT:
1302 		return (linux_getsockopt(td, arg));
1303 	case LINUX_SENDMSG:
1304 		return (linux_sendmsg(td, arg));
1305 	case LINUX_RECVMSG:
1306 		return (linux_recvmsg(td, arg));
1307 	}
1308 
1309 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1310 	return (ENOSYS);
1311 }
1312 #endif /*!__alpha__*/
1313