19313Ssos/*-
2230132Suqs * Copyright (c) 1995 S��ren Schmidt
39313Ssos * All rights reserved.
49313Ssos *
59313Ssos * Redistribution and use in source and binary forms, with or without
69313Ssos * modification, are permitted provided that the following conditions
79313Ssos * are met:
89313Ssos * 1. Redistributions of source code must retain the above copyright
9111798Sdes *    notice, this list of conditions and the following disclaimer
109313Ssos *    in this position and unchanged.
119313Ssos * 2. Redistributions in binary form must reproduce the above copyright
129313Ssos *    notice, this list of conditions and the following disclaimer in the
139313Ssos *    documentation and/or other materials provided with the distribution.
149313Ssos * 3. The name of the author may not be used to endorse or promote products
1597748Sschweikh *    derived from this software without specific prior written permission
169313Ssos *
179313Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189313Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199313Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209313Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219313Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229313Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239313Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249313Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259313Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
269313Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279313Ssos */
289313Ssos
29116173Sobrien#include <sys/cdefs.h>
30116173Sobrien__FBSDID("$FreeBSD: stable/10/sys/compat/linux/linux_socket.c 321022 2017-07-15 17:44:29Z dchagin $");
31116173Sobrien
3212458Sbde/* XXX we use functions that might not exist. */
33156874Sru#include "opt_compat.h"
34110295Sume#include "opt_inet6.h"
3512458Sbde
369313Ssos#include <sys/param.h>
3731711Smsmith#include <sys/proc.h>
389313Ssos#include <sys/systm.h>
3912458Sbde#include <sys/sysproto.h>
40280258Srwatson#include <sys/capsicum.h>
4133148Smsmith#include <sys/fcntl.h>
4273288Sjlemon#include <sys/file.h>
43114216Skan#include <sys/limits.h>
44147853Sjhb#include <sys/lock.h>
45110295Sume#include <sys/malloc.h>
46147853Sjhb#include <sys/mutex.h>
47122358Sdwmalone#include <sys/mbuf.h>
489313Ssos#include <sys/socket.h>
4973288Sjlemon#include <sys/socketvar.h>
50110295Sume#include <sys/syscallsubr.h>
5134924Sbde#include <sys/uio.h>
52110295Sume#include <sys/syslog.h>
53166398Skib#include <sys/un.h>
5412458Sbde
55185571Sbz#include <net/if.h>
569313Ssos#include <netinet/in.h>
5731711Smsmith#include <netinet/in_systm.h>
5831711Smsmith#include <netinet/ip.h>
59245849Sjhb#include <netinet/tcp.h>
60110295Sume#ifdef INET6
61110295Sume#include <netinet/ip6.h>
62110295Sume#include <netinet6/ip6_var.h>
63185571Sbz#include <netinet6/in6_var.h>
64110295Sume#endif
659313Ssos
66140214Sobrien#ifdef COMPAT_LINUX32
67140214Sobrien#include <machine/../linux32/linux.h>
68140214Sobrien#include <machine/../linux32/linux32_proto.h>
69140214Sobrien#else
7064913Smarcel#include <machine/../linux/linux.h>
7168583Smarcel#include <machine/../linux/linux_proto.h>
72133816Stjr#endif
73293541Sdchagin#include <compat/linux/linux_file.h>
7470178Sassar#include <compat/linux/linux_socket.h>
75293588Sdchagin#include <compat/linux/linux_timer.h>
7664913Smarcel#include <compat/linux/linux_util.h>
779313Ssos
78110295Sumestatic int linux_to_bsd_domain(int);
79293588Sdchaginstatic int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *,
80293588Sdchagin					l_uint);
81293588Sdchaginstatic int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *,
82293588Sdchagin					l_uint, struct msghdr *);
83293590Sdchaginstatic int linux_set_socket_flags(int, int *);
84110295Sume
8585569Sfenner/*
86110295Sume * Reads a linux sockaddr and does any necessary translation.
87110295Sume * Linux sockaddrs don't have a length field, only a family.
88110295Sume * Copy the osockaddr structure pointed to by osa to kernel, adjust
89110295Sume * family and convert to sockaddr.
90110295Sume */
91110295Sumestatic int
92226078Sjkimlinux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
93110295Sume{
94110295Sume	struct sockaddr *sa;
95110295Sume	struct osockaddr *kosa;
96110295Sume#ifdef INET6
97226074Sjkim	struct sockaddr_in6 *sin6;
98110295Sume	int oldv6size;
99110295Sume#endif
100226073Sjkim	char *name;
101226078Sjkim	int bdom, error, hdrlen, namelen;
102110295Sume
103226078Sjkim	if (salen < 2 || salen > UCHAR_MAX || !osa)
104110295Sume		return (EINVAL);
105110295Sume
106110295Sume#ifdef INET6
107110295Sume	oldv6size = 0;
108110295Sume	/*
109110295Sume	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
110110295Sume	 * if it's a v4-mapped address, so reserve the proper space
111110295Sume	 * for it.
112110295Sume	 */
113226078Sjkim	if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
114226078Sjkim		salen += sizeof(uint32_t);
115110295Sume		oldv6size = 1;
11685569Sfenner	}
117110295Sume#endif
118110295Sume
119226078Sjkim	kosa = malloc(salen, M_SONAME, M_WAITOK);
120110295Sume
121226078Sjkim	if ((error = copyin(osa, kosa, salen)))
122110295Sume		goto out;
123110295Sume
124110295Sume	bdom = linux_to_bsd_domain(kosa->sa_family);
125110295Sume	if (bdom == -1) {
126203728Sdelphij		error = EAFNOSUPPORT;
127110295Sume		goto out;
128110295Sume	}
129110295Sume
130110295Sume#ifdef INET6
131110295Sume	/*
132110295Sume	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
133110295Sume	 * which lacks the scope id compared with RFC2553 one. If we detect
134110295Sume	 * the situation, reject the address and write a message to system log.
135110295Sume	 *
136110295Sume	 * Still accept addresses for which the scope id is not used.
137110295Sume	 */
138226072Sjkim	if (oldv6size) {
139226072Sjkim		if (bdom == AF_INET6) {
140226072Sjkim			sin6 = (struct sockaddr_in6 *)kosa;
141226072Sjkim			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
142226072Sjkim			    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
143226072Sjkim			     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
144226072Sjkim			     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
145226072Sjkim			     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
146226072Sjkim			     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
147226072Sjkim				sin6->sin6_scope_id = 0;
148226072Sjkim			} else {
149226072Sjkim				log(LOG_DEBUG,
150226072Sjkim				    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
151226072Sjkim				error = EINVAL;
152226072Sjkim				goto out;
153226072Sjkim			}
154226072Sjkim		} else
155226078Sjkim			salen -= sizeof(uint32_t);
156226072Sjkim	}
157110295Sume#endif
158203728Sdelphij	if (bdom == AF_INET) {
159226078Sjkim		if (salen < sizeof(struct sockaddr_in)) {
160203728Sdelphij			error = EINVAL;
161203728Sdelphij			goto out;
162203728Sdelphij		}
163226078Sjkim		salen = sizeof(struct sockaddr_in);
164203728Sdelphij	}
165110295Sume
166226078Sjkim	if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
167226068Sjkim		hdrlen = offsetof(struct sockaddr_un, sun_path);
168226073Sjkim		name = ((struct sockaddr_un *)kosa)->sun_path;
169226073Sjkim		if (*name == '\0') {
170226073Sjkim			/*
171226073Sjkim		 	 * Linux abstract namespace starts with a NULL byte.
172226073Sjkim			 * XXX We do not support abstract namespace yet.
173226073Sjkim			 */
174226078Sjkim			namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
175226073Sjkim		} else
176226078Sjkim			namelen = strnlen(name, salen - hdrlen);
177226079Sjkim		salen = hdrlen + namelen;
178226079Sjkim		if (salen > sizeof(struct sockaddr_un)) {
179226071Sjkim			error = ENAMETOOLONG;
180226023Scperciva			goto out;
181226023Scperciva		}
182226023Scperciva	}
183226023Scperciva
184226074Sjkim	sa = (struct sockaddr *)kosa;
185110295Sume	sa->sa_family = bdom;
186226078Sjkim	sa->sa_len = salen;
187110295Sume
188110295Sume	*sap = sa;
189110295Sume	return (0);
190110295Sume
191110295Sumeout:
192226069Sjkim	free(kosa, M_SONAME);
193110295Sume	return (error);
19485569Sfenner}
19585569Sfenner
1969313Ssosstatic int
1979313Ssoslinux_to_bsd_domain(int domain)
1989313Ssos{
19965108Smarcel
20065108Smarcel	switch (domain) {
20165108Smarcel	case LINUX_AF_UNSPEC:
20265108Smarcel		return (AF_UNSPEC);
20365108Smarcel	case LINUX_AF_UNIX:
20465108Smarcel		return (AF_LOCAL);
20565108Smarcel	case LINUX_AF_INET:
20665108Smarcel		return (AF_INET);
207110295Sume	case LINUX_AF_INET6:
208110295Sume		return (AF_INET6);
20965108Smarcel	case LINUX_AF_AX25:
21065108Smarcel		return (AF_CCITT);
21165108Smarcel	case LINUX_AF_IPX:
21265108Smarcel		return (AF_IPX);
21365108Smarcel	case LINUX_AF_APPLETALK:
21465108Smarcel		return (AF_APPLETALK);
21565108Smarcel	}
21665108Smarcel	return (-1);
2179313Ssos}
2189313Ssos
2199313Ssosstatic int
220110295Sumebsd_to_linux_domain(int domain)
221110295Sume{
222110295Sume
223110295Sume	switch (domain) {
224110295Sume	case AF_UNSPEC:
225110295Sume		return (LINUX_AF_UNSPEC);
226110295Sume	case AF_LOCAL:
227110295Sume		return (LINUX_AF_UNIX);
228110295Sume	case AF_INET:
229110295Sume		return (LINUX_AF_INET);
230110295Sume	case AF_INET6:
231110295Sume		return (LINUX_AF_INET6);
232110295Sume	case AF_CCITT:
233110295Sume		return (LINUX_AF_AX25);
234110295Sume	case AF_IPX:
235110295Sume		return (LINUX_AF_IPX);
236110295Sume	case AF_APPLETALK:
237110295Sume		return (LINUX_AF_APPLETALK);
238110295Sume	}
239110295Sume	return (-1);
240110295Sume}
241110295Sume
242110295Sumestatic int
2439313Ssoslinux_to_bsd_sockopt_level(int level)
2449313Ssos{
24565108Smarcel
24665108Smarcel	switch (level) {
24765108Smarcel	case LINUX_SOL_SOCKET:
24865108Smarcel		return (SOL_SOCKET);
24965108Smarcel	}
25065108Smarcel	return (level);
2519313Ssos}
2529313Ssos
25365108Smarcelstatic int
254121008Siwasakibsd_to_linux_sockopt_level(int level)
255121008Siwasaki{
256121008Siwasaki
257121008Siwasaki	switch (level) {
258121008Siwasaki	case SOL_SOCKET:
259121008Siwasaki		return (LINUX_SOL_SOCKET);
260121008Siwasaki	}
261121008Siwasaki	return (level);
262121008Siwasaki}
263121008Siwasaki
264121008Siwasakistatic int
26565108Smarcellinux_to_bsd_ip_sockopt(int opt)
2669313Ssos{
26765108Smarcel
26865108Smarcel	switch (opt) {
26965108Smarcel	case LINUX_IP_TOS:
27065108Smarcel		return (IP_TOS);
27165108Smarcel	case LINUX_IP_TTL:
27265108Smarcel		return (IP_TTL);
27365108Smarcel	case LINUX_IP_OPTIONS:
27465108Smarcel		return (IP_OPTIONS);
27565108Smarcel	case LINUX_IP_MULTICAST_IF:
27665108Smarcel		return (IP_MULTICAST_IF);
27765108Smarcel	case LINUX_IP_MULTICAST_TTL:
27865108Smarcel		return (IP_MULTICAST_TTL);
27965108Smarcel	case LINUX_IP_MULTICAST_LOOP:
28065108Smarcel		return (IP_MULTICAST_LOOP);
28165108Smarcel	case LINUX_IP_ADD_MEMBERSHIP:
28265108Smarcel		return (IP_ADD_MEMBERSHIP);
28365108Smarcel	case LINUX_IP_DROP_MEMBERSHIP:
28465108Smarcel		return (IP_DROP_MEMBERSHIP);
28565108Smarcel	case LINUX_IP_HDRINCL:
28665108Smarcel		return (IP_HDRINCL);
28765108Smarcel	}
28865108Smarcel	return (-1);
2899313Ssos}
2909313Ssos
2919313Ssosstatic int
292297211Saelinux_to_bsd_ip6_sockopt(int opt)
293297211Sae{
294297211Sae
295297211Sae	switch (opt) {
296297211Sae	case LINUX_IPV6_NEXTHOP:
297297211Sae		return (IPV6_NEXTHOP);
298297211Sae	case LINUX_IPV6_UNICAST_HOPS:
299297211Sae		return (IPV6_UNICAST_HOPS);
300297211Sae	case LINUX_IPV6_MULTICAST_IF:
301297211Sae		return (IPV6_MULTICAST_IF);
302297211Sae	case LINUX_IPV6_MULTICAST_HOPS:
303297211Sae		return (IPV6_MULTICAST_HOPS);
304297211Sae	case LINUX_IPV6_MULTICAST_LOOP:
305297211Sae		return (IPV6_MULTICAST_LOOP);
306297211Sae	case LINUX_IPV6_ADD_MEMBERSHIP:
307297211Sae		return (IPV6_JOIN_GROUP);
308297211Sae	case LINUX_IPV6_DROP_MEMBERSHIP:
309297211Sae		return (IPV6_LEAVE_GROUP);
310297211Sae	case LINUX_IPV6_V6ONLY:
311297211Sae		return (IPV6_V6ONLY);
312297211Sae	case LINUX_IPV6_DONTFRAG:
313297211Sae		return (IPV6_DONTFRAG);
314297211Sae#if 0
315297211Sae	case LINUX_IPV6_CHECKSUM:
316297211Sae		return (IPV6_CHECKSUM);
317297211Sae	case LINUX_IPV6_RECVPKTINFO:
318297211Sae		return (IPV6_RECVPKTINFO);
319297211Sae	case LINUX_IPV6_PKTINFO:
320297211Sae		return (IPV6_PKTINFO);
321297211Sae	case LINUX_IPV6_RECVHOPLIMIT:
322297211Sae		return (IPV6_RECVHOPLIMIT);
323297211Sae	case LINUX_IPV6_HOPLIMIT:
324297211Sae		return (IPV6_HOPLIMIT);
325297211Sae	case LINUX_IPV6_RECVHOPOPTS:
326297211Sae		return (IPV6_RECVHOPOPTS);
327297211Sae	case LINUX_IPV6_HOPOPTS:
328297211Sae		return (IPV6_HOPOPTS);
329297211Sae	case LINUX_IPV6_RTHDRDSTOPTS:
330297211Sae		return (IPV6_RTHDRDSTOPTS);
331297211Sae	case LINUX_IPV6_RECVRTHDR:
332297211Sae		return (IPV6_RECVRTHDR);
333297211Sae	case LINUX_IPV6_RTHDR:
334297211Sae		return (IPV6_RTHDR);
335297211Sae	case LINUX_IPV6_RECVDSTOPTS:
336297211Sae		return (IPV6_RECVDSTOPTS);
337297211Sae	case LINUX_IPV6_DSTOPTS:
338297211Sae		return (IPV6_DSTOPTS);
339297211Sae	case LINUX_IPV6_RECVPATHMTU:
340297211Sae		return (IPV6_RECVPATHMTU);
341297211Sae	case LINUX_IPV6_PATHMTU:
342297211Sae		return (IPV6_PATHMTU);
343297211Sae#endif
344297211Sae	}
345297211Sae	return (-1);
346297211Sae}
347297211Sae
348297211Saestatic int
3499313Ssoslinux_to_bsd_so_sockopt(int opt)
3509313Ssos{
35165108Smarcel
35265108Smarcel	switch (opt) {
35365108Smarcel	case LINUX_SO_DEBUG:
35465108Smarcel		return (SO_DEBUG);
35565108Smarcel	case LINUX_SO_REUSEADDR:
35665108Smarcel		return (SO_REUSEADDR);
35765108Smarcel	case LINUX_SO_TYPE:
35865108Smarcel		return (SO_TYPE);
35965108Smarcel	case LINUX_SO_ERROR:
36065108Smarcel		return (SO_ERROR);
36165108Smarcel	case LINUX_SO_DONTROUTE:
36265108Smarcel		return (SO_DONTROUTE);
36365108Smarcel	case LINUX_SO_BROADCAST:
36465108Smarcel		return (SO_BROADCAST);
36565108Smarcel	case LINUX_SO_SNDBUF:
36665108Smarcel		return (SO_SNDBUF);
36765108Smarcel	case LINUX_SO_RCVBUF:
36865108Smarcel		return (SO_RCVBUF);
36965108Smarcel	case LINUX_SO_KEEPALIVE:
37065108Smarcel		return (SO_KEEPALIVE);
37165108Smarcel	case LINUX_SO_OOBINLINE:
37265108Smarcel		return (SO_OOBINLINE);
37365108Smarcel	case LINUX_SO_LINGER:
37465108Smarcel		return (SO_LINGER);
375166398Skib	case LINUX_SO_PEERCRED:
376166398Skib		return (LOCAL_PEERCRED);
377166398Skib	case LINUX_SO_RCVLOWAT:
378166398Skib		return (SO_RCVLOWAT);
379166398Skib	case LINUX_SO_SNDLOWAT:
380166398Skib		return (SO_SNDLOWAT);
381166398Skib	case LINUX_SO_RCVTIMEO:
382166398Skib		return (SO_RCVTIMEO);
383166398Skib	case LINUX_SO_SNDTIMEO:
384166398Skib		return (SO_SNDTIMEO);
385166398Skib	case LINUX_SO_TIMESTAMP:
386166398Skib		return (SO_TIMESTAMP);
387166398Skib	case LINUX_SO_ACCEPTCONN:
388166398Skib		return (SO_ACCEPTCONN);
38965108Smarcel	}
39065108Smarcel	return (-1);
3919313Ssos}
3929313Ssos
39370178Sassarstatic int
394245849Sjhblinux_to_bsd_tcp_sockopt(int opt)
395245849Sjhb{
396245849Sjhb
397245849Sjhb	switch (opt) {
398245849Sjhb	case LINUX_TCP_NODELAY:
399245849Sjhb		return (TCP_NODELAY);
400245849Sjhb	case LINUX_TCP_MAXSEG:
401245849Sjhb		return (TCP_MAXSEG);
402245849Sjhb	case LINUX_TCP_KEEPIDLE:
403245849Sjhb		return (TCP_KEEPIDLE);
404245849Sjhb	case LINUX_TCP_KEEPINTVL:
405245849Sjhb		return (TCP_KEEPINTVL);
406245849Sjhb	case LINUX_TCP_KEEPCNT:
407245849Sjhb		return (TCP_KEEPCNT);
408245849Sjhb	case LINUX_TCP_MD5SIG:
409245849Sjhb		return (TCP_MD5SIG);
410245849Sjhb	}
411245849Sjhb	return (-1);
412245849Sjhb}
413245849Sjhb
414245849Sjhbstatic int
41570178Sassarlinux_to_bsd_msg_flags(int flags)
41670178Sassar{
41770178Sassar	int ret_flags = 0;
41870178Sassar
41970178Sassar	if (flags & LINUX_MSG_OOB)
42070178Sassar		ret_flags |= MSG_OOB;
42170178Sassar	if (flags & LINUX_MSG_PEEK)
42270178Sassar		ret_flags |= MSG_PEEK;
42370178Sassar	if (flags & LINUX_MSG_DONTROUTE)
42470178Sassar		ret_flags |= MSG_DONTROUTE;
42570178Sassar	if (flags & LINUX_MSG_CTRUNC)
42670178Sassar		ret_flags |= MSG_CTRUNC;
42770178Sassar	if (flags & LINUX_MSG_TRUNC)
42870178Sassar		ret_flags |= MSG_TRUNC;
42970178Sassar	if (flags & LINUX_MSG_DONTWAIT)
43070178Sassar		ret_flags |= MSG_DONTWAIT;
43170178Sassar	if (flags & LINUX_MSG_EOR)
43270178Sassar		ret_flags |= MSG_EOR;
43370178Sassar	if (flags & LINUX_MSG_WAITALL)
43470178Sassar		ret_flags |= MSG_WAITALL;
435143295Ssobomax	if (flags & LINUX_MSG_NOSIGNAL)
436143295Ssobomax		ret_flags |= MSG_NOSIGNAL;
43770178Sassar#if 0 /* not handled */
43870178Sassar	if (flags & LINUX_MSG_PROXY)
43970178Sassar		;
44070178Sassar	if (flags & LINUX_MSG_FIN)
44170178Sassar		;
44270178Sassar	if (flags & LINUX_MSG_SYN)
44370178Sassar		;
44470178Sassar	if (flags & LINUX_MSG_CONFIRM)
44570178Sassar		;
44670178Sassar	if (flags & LINUX_MSG_RST)
44770178Sassar		;
44870178Sassar	if (flags & LINUX_MSG_ERRQUEUE)
44970178Sassar		;
45070178Sassar#endif
451297518Sdchagin	return (ret_flags);
45270178Sassar}
45370178Sassar
454156842Snetchild/*
455156842Snetchild* If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
456156842Snetchild* native syscall will fault.  Thus, we don't really need to check the
457156842Snetchild* return values for these functions.
458156842Snetchild*/
459156842Snetchild
460110295Sumestatic int
461156842Snetchildbsd_to_linux_sockaddr(struct sockaddr *arg)
462156842Snetchild{
463156842Snetchild	struct sockaddr sa;
464156842Snetchild	size_t sa_len = sizeof(struct sockaddr);
465301431Sdchagin	int error, bdom;
466297518Sdchagin
467156842Snetchild	if ((error = copyin(arg, &sa, sa_len)))
468156842Snetchild		return (error);
469297518Sdchagin
470301431Sdchagin	bdom = bsd_to_linux_domain(sa.sa_family);
471301431Sdchagin	if (bdom == -1)
472301431Sdchagin		return (EAFNOSUPPORT);
473301431Sdchagin
474301431Sdchagin	*(u_short *)&sa = bdom;
475297518Sdchagin	return (copyout(&sa, arg, sa_len));
476156842Snetchild}
477156842Snetchild
478156842Snetchildstatic int
479156842Snetchildlinux_to_bsd_sockaddr(struct sockaddr *arg, int len)
480156842Snetchild{
481156842Snetchild	struct sockaddr sa;
482156842Snetchild	size_t sa_len = sizeof(struct sockaddr);
483301431Sdchagin	int error, bdom;
484156842Snetchild
485156842Snetchild	if ((error = copyin(arg, &sa, sa_len)))
486156842Snetchild		return (error);
487156842Snetchild
488301431Sdchagin	bdom = linux_to_bsd_domain(*(sa_family_t *)&sa);
489301431Sdchagin	if (bdom == -1)
490301431Sdchagin		return (EAFNOSUPPORT);
491301431Sdchagin
492301431Sdchagin	sa.sa_family = bdom;
493156842Snetchild	sa.sa_len = len;
494297518Sdchagin	return (copyout(&sa, arg, sa_len));
495156842Snetchild}
496156842Snetchild
497156842Snetchildstatic int
498110295Sumelinux_sa_put(struct osockaddr *osa)
499110295Sume{
500110295Sume	struct osockaddr sa;
501110295Sume	int error, bdom;
502110295Sume
503110295Sume	/*
504110295Sume	 * Only read/write the osockaddr family part, the rest is
505110295Sume	 * not changed.
506110295Sume	 */
507111797Sdes	error = copyin(osa, &sa, sizeof(sa.sa_family));
508110295Sume	if (error)
509110295Sume		return (error);
510110295Sume
511110295Sume	bdom = bsd_to_linux_domain(sa.sa_family);
512110295Sume	if (bdom == -1)
513110295Sume		return (EINVAL);
514110295Sume
515110295Sume	sa.sa_family = bdom;
516297518Sdchagin	return (copyout(&sa, osa, sizeof(sa.sa_family)));
517110295Sume}
518110295Sume
519122358Sdwmalonestatic int
520185442Skiblinux_to_bsd_cmsg_type(int cmsg_type)
521185442Skib{
522185442Skib
523185442Skib	switch (cmsg_type) {
524185442Skib	case LINUX_SCM_RIGHTS:
525185442Skib		return (SCM_RIGHTS);
526220031Savg	case LINUX_SCM_CREDENTIALS:
527220031Savg		return (SCM_CREDS);
528185442Skib	}
529185442Skib	return (-1);
530185442Skib}
531185442Skib
532185442Skibstatic int
533185442Skibbsd_to_linux_cmsg_type(int cmsg_type)
534185442Skib{
535185442Skib
536185442Skib	switch (cmsg_type) {
537185442Skib	case SCM_RIGHTS:
538185442Skib		return (LINUX_SCM_RIGHTS);
539220031Savg	case SCM_CREDS:
540220031Savg		return (LINUX_SCM_CREDENTIALS);
541293597Sdchagin	case SCM_TIMESTAMP:
542293597Sdchagin		return (LINUX_SCM_TIMESTAMP);
543185442Skib	}
544185442Skib	return (-1);
545185442Skib}
546185442Skib
547185442Skibstatic int
548185442Skiblinux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
549185442Skib{
550185442Skib	if (lhdr->msg_controllen > INT_MAX)
551185442Skib		return (ENOBUFS);
552185442Skib
553185442Skib	bhdr->msg_name		= PTRIN(lhdr->msg_name);
554185442Skib	bhdr->msg_namelen	= lhdr->msg_namelen;
555185442Skib	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
556185442Skib	bhdr->msg_iovlen	= lhdr->msg_iovlen;
557185442Skib	bhdr->msg_control	= PTRIN(lhdr->msg_control);
558220031Savg
559220031Savg	/*
560220031Savg	 * msg_controllen is skipped since BSD and LINUX control messages
561220031Savg	 * are potentially different sizes (e.g. the cred structure used
562220031Savg	 * by SCM_CREDS is different between the two operating system).
563220031Savg	 *
564220031Savg	 * The caller can set it (if necessary) after converting all the
565220031Savg	 * control messages.
566220031Savg	 */
567220031Savg
568185442Skib	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
569185442Skib	return (0);
570185442Skib}
571185442Skib
572185442Skibstatic int
573185442Skibbsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
574185442Skib{
575185442Skib	lhdr->msg_name		= PTROUT(bhdr->msg_name);
576185442Skib	lhdr->msg_namelen	= bhdr->msg_namelen;
577185442Skib	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
578185442Skib	lhdr->msg_iovlen	= bhdr->msg_iovlen;
579185442Skib	lhdr->msg_control	= PTROUT(bhdr->msg_control);
580220031Savg
581220031Savg	/*
582220031Savg	 * msg_controllen is skipped since BSD and LINUX control messages
583220031Savg	 * are potentially different sizes (e.g. the cred structure used
584220031Savg	 * by SCM_CREDS is different between the two operating system).
585220031Savg	 *
586220031Savg	 * The caller can set it (if necessary) after converting all the
587220031Savg	 * control messages.
588220031Savg	 */
589220031Savg
590185442Skib	/* msg_flags skipped */
591185442Skib	return (0);
592185442Skib}
593185442Skib
594185442Skibstatic int
595293590Sdchaginlinux_set_socket_flags(int lflags, int *flags)
596193165Sdchagin{
597193165Sdchagin
598293590Sdchagin	if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
599293590Sdchagin		return (EINVAL);
600293590Sdchagin	if (lflags & LINUX_SOCK_NONBLOCK)
601293590Sdchagin		*flags |= SOCK_NONBLOCK;
602293590Sdchagin	if (lflags & LINUX_SOCK_CLOEXEC)
603293590Sdchagin		*flags |= SOCK_CLOEXEC;
604193165Sdchagin	return (0);
605193165Sdchagin}
606193165Sdchagin
607193165Sdchaginstatic int
608141029Ssobomaxlinux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
609185442Skib    struct mbuf *control, enum uio_seg segflg)
610122358Sdwmalone{
611122358Sdwmalone	struct sockaddr *to;
612122358Sdwmalone	int error;
613122358Sdwmalone
614122358Sdwmalone	if (mp->msg_name != NULL) {
615122358Sdwmalone		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
616122358Sdwmalone		if (error)
617122358Sdwmalone			return (error);
618122358Sdwmalone		mp->msg_name = to;
619122358Sdwmalone	} else
620122358Sdwmalone		to = NULL;
621122358Sdwmalone
622141029Ssobomax	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
623141029Ssobomax	    segflg);
624122358Sdwmalone
625122358Sdwmalone	if (to)
626184205Sdes		free(to, M_SONAME);
627122358Sdwmalone	return (error);
628122358Sdwmalone}
629122358Sdwmalone
63065108Smarcel/* Return 0 if IP_HDRINCL is set for the given socket. */
63131711Smsmithstatic int
632132313Sdwmalonelinux_check_hdrincl(struct thread *td, int s)
63331711Smsmith{
634276813Sdchagin	int error, optval;
635276813Sdchagin	socklen_t size_val;
63631711Smsmith
637132313Sdwmalone	size_val = sizeof(optval);
638132313Sdwmalone	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
639132313Sdwmalone	    &optval, UIO_SYSSPACE, &size_val);
640132313Sdwmalone	if (error)
64165108Smarcel		return (error);
64265108Smarcel
64365108Smarcel	return (optval == 0);
64431711Smsmith}
64531711Smsmith
64631711Smsmith/*
64731711Smsmith * Updated sendto() when IP_HDRINCL is set:
64831711Smsmith * tweak endian-dependent fields in the IP packet.
64931711Smsmith */
65031711Smsmithstatic int
651132331Srwatsonlinux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
65231711Smsmith{
65331711Smsmith/*
65431711Smsmith * linux_ip_copysize defines how many bytes we should copy
65531711Smsmith * from the beginning of the IP packet before we customize it for BSD.
656141029Ssobomax * It should include all the fields we modify (ip_len and ip_off).
65731711Smsmith */
65831711Smsmith#define linux_ip_copysize	8
65931711Smsmith
66065108Smarcel	struct ip *packet;
661122358Sdwmalone	struct msghdr msg;
662141029Ssobomax	struct iovec aiov[1];
66365108Smarcel	int error;
66431711Smsmith
665144012Sdas	/* Check that the packet isn't too big or too small. */
666144012Sdas	if (linux_args->len < linux_ip_copysize ||
667144012Sdas	    linux_args->len > IP_MAXPACKET)
66865108Smarcel		return (EINVAL);
66931711Smsmith
670293532Sdchagin	packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK);
67131711Smsmith
672141029Ssobomax	/* Make kernel copy of the packet to be sent */
673133816Stjr	if ((error = copyin(PTRIN(linux_args->msg), packet,
674141029Ssobomax	    linux_args->len)))
675141029Ssobomax		goto goout;
67631711Smsmith
67765108Smarcel	/* Convert fields from Linux to BSD raw IP socket format */
678122358Sdwmalone	packet->ip_len = linux_args->len;
67965108Smarcel	packet->ip_off = ntohs(packet->ip_off);
68031711Smsmith
68165108Smarcel	/* Prepare the msghdr and iovec structures describing the new packet */
682133816Stjr	msg.msg_name = PTRIN(linux_args->to);
683122358Sdwmalone	msg.msg_namelen = linux_args->tolen;
684122358Sdwmalone	msg.msg_iov = aiov;
685141029Ssobomax	msg.msg_iovlen = 1;
686122358Sdwmalone	msg.msg_control = NULL;
687122358Sdwmalone	msg.msg_flags = 0;
688122358Sdwmalone	aiov[0].iov_base = (char *)packet;
689141029Ssobomax	aiov[0].iov_len = linux_args->len;
690141029Ssobomax	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
691185442Skib	    NULL, UIO_SYSSPACE);
692141029Ssobomaxgoout:
693293532Sdchagin	free(packet, M_LINUX);
694122358Sdwmalone	return (error);
69531711Smsmith}
69631711Smsmith
697293519Sdchaginint
69883366Sjulianlinux_socket(struct thread *td, struct linux_socket_args *args)
6999313Ssos{
70065108Smarcel	struct socket_args /* {
70165108Smarcel		int domain;
70265108Smarcel		int type;
70365108Smarcel		int protocol;
70465108Smarcel	} */ bsd_args;
705293590Sdchagin	int retval_socket;
7069313Ssos
707182890Skib	bsd_args.protocol = args->protocol;
708192206Sdchagin	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
709192205Sdchagin	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
710192205Sdchagin		return (EINVAL);
711293590Sdchagin	retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
712293590Sdchagin		&bsd_args.type);
713293590Sdchagin	if (retval_socket != 0)
714293590Sdchagin		return (retval_socket);
715182890Skib	bsd_args.domain = linux_to_bsd_domain(args->domain);
71665108Smarcel	if (bsd_args.domain == -1)
717191875Sdchagin		return (EAFNOSUPPORT);
71831711Smsmith
719225617Skmacy	retval_socket = sys_socket(td, &bsd_args);
720192204Sdchagin	if (retval_socket)
721192204Sdchagin		return (retval_socket);
722192204Sdchagin
72365108Smarcel	if (bsd_args.type == SOCK_RAW
72465108Smarcel	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
725192204Sdchagin	    && bsd_args.domain == PF_INET) {
72665108Smarcel		/* It's a raw IP socket: set the IP_HDRINCL option. */
727132313Sdwmalone		int hdrincl;
72865108Smarcel
729132313Sdwmalone		hdrincl = 1;
730132313Sdwmalone		/* We ignore any error returned by kern_setsockopt() */
731132313Sdwmalone		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
732132313Sdwmalone		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
73365108Smarcel	}
734110295Sume#ifdef INET6
735110295Sume	/*
736198467Sbz	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default
737198467Sbz	 * and some apps depend on this. So, set V6ONLY to 0 for Linux apps.
738198467Sbz	 * For simplicity we do this unconditionally of the net.inet6.ip6.v6only
739198467Sbz	 * sysctl value.
740110295Sume	 */
741198467Sbz	if (bsd_args.domain == PF_INET6) {
742132313Sdwmalone		int v6only;
74365108Smarcel
744132313Sdwmalone		v6only = 0;
745110295Sume		/* We ignore any error returned by setsockopt() */
746132313Sdwmalone		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
747132313Sdwmalone		    &v6only, UIO_SYSSPACE, sizeof(v6only));
748110295Sume	}
749110295Sume#endif
750110295Sume
75165108Smarcel	return (retval_socket);
7529313Ssos}
7539313Ssos
754293519Sdchaginint
75583366Sjulianlinux_bind(struct thread *td, struct linux_bind_args *args)
7569313Ssos{
757110295Sume	struct sockaddr *sa;
75865108Smarcel	int error;
7599313Ssos
760182890Skib	error = linux_getsockaddr(&sa, PTRIN(args->name),
761182890Skib	    args->namelen);
762110295Sume	if (error)
763110295Sume		return (error);
764110295Sume
765182890Skib	error = kern_bind(td, args->s, sa);
766160506Sjhb	free(sa, M_SONAME);
767182890Skib	if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
768162585Snetchild	   	return (EINVAL);
769160506Sjhb	return (error);
7709313Ssos}
7719313Ssos
77268803Sgallatinint
77383366Sjulianlinux_connect(struct thread *td, struct linux_connect_args *args)
7749313Ssos{
775255219Spjd	cap_rights_t rights;
77673288Sjlemon	struct socket *so;
777110295Sume	struct sockaddr *sa;
77886504Sdillon	u_int fflag;
77965108Smarcel	int error;
7809313Ssos
781182890Skib	error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
782182890Skib	    args->namelen);
783110295Sume	if (error)
784110295Sume		return (error);
785110295Sume
786182890Skib	error = kern_connect(td, args->s, sa);
787160506Sjhb	free(sa, M_SONAME);
78873288Sjlemon	if (error != EISCONN)
78973288Sjlemon		return (error);
79033148Smsmith
79173288Sjlemon	/*
79273288Sjlemon	 * Linux doesn't return EISCONN the first time it occurs,
79373288Sjlemon	 * when on a non-blocking socket. Instead it returns the
79473288Sjlemon	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
795157369Srwatson	 *
796157369Srwatson	 * XXXRW: Instead of using fgetsock(), check that it is a
797157369Srwatson	 * socket and use the file descriptor reference instead of
798157369Srwatson	 * creating a new one.
79973288Sjlemon	 */
800255219Spjd	error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT),
801255219Spjd	    &so, &fflag);
802147853Sjhb	if (error == 0) {
803147853Sjhb		error = EISCONN;
804147853Sjhb		if (fflag & FNONBLOCK) {
805147853Sjhb			SOCK_LOCK(so);
806147853Sjhb			if (so->so_emuldata == 0)
807147853Sjhb				error = so->so_error;
808147853Sjhb			so->so_emuldata = (void *)1;
809147853Sjhb			SOCK_UNLOCK(so);
810147853Sjhb		}
811147853Sjhb		fputsock(so);
81233148Smsmith	}
81365108Smarcel	return (error);
8149313Ssos}
8159313Ssos
816293519Sdchaginint
81783366Sjulianlinux_listen(struct thread *td, struct linux_listen_args *args)
8189313Ssos{
81965108Smarcel	struct listen_args /* {
82065108Smarcel		int s;
82165108Smarcel		int backlog;
82265108Smarcel	} */ bsd_args;
8239313Ssos
824182890Skib	bsd_args.s = args->s;
825182890Skib	bsd_args.backlog = args->backlog;
826225617Skmacy	return (sys_listen(td, &bsd_args));
8279313Ssos}
8289313Ssos
829158415Snetchildstatic int
830193262Sdchaginlinux_accept_common(struct thread *td, int s, l_uintptr_t addr,
831193265Sdchagin    l_uintptr_t namelen, int flags)
8329313Ssos{
833293590Sdchagin	struct accept4_args /* {
834123828Sbde		int	s;
835123828Sbde		struct sockaddr * __restrict name;
836123828Sbde		socklen_t * __restrict anamelen;
837293590Sdchagin		int	flags;
83865108Smarcel	} */ bsd_args;
839321022Sdchagin	cap_rights_t rights;
840321022Sdchagin	struct socket *so;
841321022Sdchagin	struct file *fp;
842321022Sdchagin	int error, error1;
8439313Ssos
844193262Sdchagin	bsd_args.s = s;
845123828Sbde	/* XXX: */
846193262Sdchagin	bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr);
847193262Sdchagin	bsd_args.anamelen = PTRIN(namelen);/* XXX */
848293605Sdchagin	bsd_args.flags = 0;
849293590Sdchagin	error = linux_set_socket_flags(flags, &bsd_args.flags);
850293590Sdchagin	if (error != 0)
851293590Sdchagin		return (error);
852293590Sdchagin	error = sys_accept4(td, &bsd_args);
853156842Snetchild	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
854162585Snetchild	if (error) {
855193262Sdchagin		if (error == EFAULT && namelen != sizeof(struct sockaddr_in))
856182890Skib			return (EINVAL);
857321022Sdchagin		if (error == EINVAL) {
858321022Sdchagin			error1 = getsock_cap(td, s,
859321022Sdchagin			    cap_rights_init(&rights, CAP_ACCEPT), &fp, NULL);
860321022Sdchagin			if (error1 != 0)
861321022Sdchagin				return (error1);
862321022Sdchagin			so = fp->f_data;
863321022Sdchagin			if (so->so_type == SOCK_DGRAM) {
864321022Sdchagin				fdrop(fp, td);
865321022Sdchagin				return (EOPNOTSUPP);
866321022Sdchagin			}
867321022Sdchagin			fdrop(fp, td);
868321022Sdchagin		}
86965108Smarcel		return (error);
870162585Snetchild	}
871193263Sdchagin	if (addr)
872193263Sdchagin		error = linux_sa_put(PTRIN(addr));
873193263Sdchagin	if (error) {
874193263Sdchagin		(void)kern_close(td, td->td_retval[0]);
875193263Sdchagin		td->td_retval[0] = 0;
876193263Sdchagin	}
877193263Sdchagin	return (error);
8789313Ssos}
8799313Ssos
880293519Sdchaginint
881193262Sdchaginlinux_accept(struct thread *td, struct linux_accept_args *args)
882193262Sdchagin{
883193262Sdchagin
884193262Sdchagin	return (linux_accept_common(td, args->s, args->addr,
885193265Sdchagin	    args->namelen, 0));
886193262Sdchagin}
887193262Sdchagin
888293519Sdchaginint
889193264Sdchaginlinux_accept4(struct thread *td, struct linux_accept4_args *args)
890193264Sdchagin{
891193264Sdchagin
892193264Sdchagin	return (linux_accept_common(td, args->s, args->addr,
893193264Sdchagin	    args->namelen, args->flags));
894193264Sdchagin}
895193264Sdchagin
896293519Sdchaginint
89783366Sjulianlinux_getsockname(struct thread *td, struct linux_getsockname_args *args)
8989313Ssos{
89965108Smarcel	struct getsockname_args /* {
900123828Sbde		int	fdes;
901123828Sbde		struct sockaddr * __restrict asa;
902123828Sbde		socklen_t * __restrict alen;
90365108Smarcel	} */ bsd_args;
90465108Smarcel	int error;
9059313Ssos
906182890Skib	bsd_args.fdes = args->s;
907123828Sbde	/* XXX: */
908182890Skib	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
909182890Skib	bsd_args.alen = PTRIN(args->namelen);	/* XXX */
910225617Skmacy	error = sys_getsockname(td, &bsd_args);
911156842Snetchild	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
912110295Sume	if (error)
913110295Sume		return (error);
914297518Sdchagin	return (linux_sa_put(PTRIN(args->addr)));
9159313Ssos}
9169313Ssos
917293519Sdchaginint
91883366Sjulianlinux_getpeername(struct thread *td, struct linux_getpeername_args *args)
9199313Ssos{
920156842Snetchild	struct getpeername_args /* {
92165108Smarcel		int fdes;
92265108Smarcel		caddr_t asa;
92365108Smarcel		int *alen;
92465108Smarcel	} */ bsd_args;
92565108Smarcel	int error;
9269313Ssos
927182890Skib	bsd_args.fdes = args->s;
928182890Skib	bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
929276813Sdchagin	bsd_args.alen = (socklen_t *)PTRIN(args->namelen);
930225617Skmacy	error = sys_getpeername(td, &bsd_args);
931156842Snetchild	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
932110295Sume	if (error)
933110295Sume		return (error);
934297518Sdchagin	return (linux_sa_put(PTRIN(args->addr)));
9359313Ssos}
9369313Ssos
937293519Sdchaginint
93883366Sjulianlinux_socketpair(struct thread *td, struct linux_socketpair_args *args)
9399313Ssos{
94065108Smarcel	struct socketpair_args /* {
94165108Smarcel		int domain;
94265108Smarcel		int type;
94365108Smarcel		int protocol;
94465108Smarcel		int *rsv;
94565108Smarcel	} */ bsd_args;
946293590Sdchagin	int error;
9479313Ssos
948182890Skib	bsd_args.domain = linux_to_bsd_domain(args->domain);
949191871Sdchagin	if (bsd_args.domain != PF_LOCAL)
950191871Sdchagin		return (EAFNOSUPPORT);
951193168Sdchagin	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
952193168Sdchagin	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
953193168Sdchagin		return (EINVAL);
954293590Sdchagin	error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
955293590Sdchagin		&bsd_args.type);
956293590Sdchagin	if (error != 0)
957293590Sdchagin		return (error);
958191871Sdchagin	if (args->protocol != 0 && args->protocol != PF_UNIX)
959191871Sdchagin
960191871Sdchagin		/*
961191871Sdchagin		 * Use of PF_UNIX as protocol argument is not right,
962191871Sdchagin		 * but Linux does it.
963191871Sdchagin		 * Do not map PF_UNIX as its Linux value is identical
964191871Sdchagin		 * to FreeBSD one.
965191871Sdchagin		 */
966191871Sdchagin		return (EPROTONOSUPPORT);
967191871Sdchagin	else
968191742Sdchagin		bsd_args.protocol = 0;
969182890Skib	bsd_args.rsv = (int *)PTRIN(args->rsv);
970293590Sdchagin	return (sys_socketpair(td, &bsd_args));
9719313Ssos}
9729313Ssos
973293519Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
974158415Snetchildstruct linux_send_args {
97565108Smarcel	int s;
976133816Stjr	l_uintptr_t msg;
97765108Smarcel	int len;
97865108Smarcel	int flags;
9799313Ssos};
9809313Ssos
981158415Snetchildstatic int
98283366Sjulianlinux_send(struct thread *td, struct linux_send_args *args)
9839313Ssos{
984131796Sphk	struct sendto_args /* {
985103886Smini		int s;
98665108Smarcel		caddr_t buf;
987103886Smini		int len;
98865108Smarcel		int flags;
989131796Sphk		caddr_t to;
990131796Sphk		int tolen;
99165108Smarcel	} */ bsd_args;
9929313Ssos
993182890Skib	bsd_args.s = args->s;
994182890Skib	bsd_args.buf = (caddr_t)PTRIN(args->msg);
995182890Skib	bsd_args.len = args->len;
996182890Skib	bsd_args.flags = args->flags;
997131796Sphk	bsd_args.to = NULL;
998131796Sphk	bsd_args.tolen = 0;
999297518Sdchagin	return (sys_sendto(td, &bsd_args));
10009313Ssos}
10019313Ssos
1002158415Snetchildstruct linux_recv_args {
100365108Smarcel	int s;
1004133816Stjr	l_uintptr_t msg;
100565108Smarcel	int len;
100665108Smarcel	int flags;
10079313Ssos};
10089313Ssos
1009158415Snetchildstatic int
101083366Sjulianlinux_recv(struct thread *td, struct linux_recv_args *args)
10119313Ssos{
1012131796Sphk	struct recvfrom_args /* {
101365108Smarcel		int s;
101465108Smarcel		caddr_t buf;
101565108Smarcel		int len;
101665108Smarcel		int flags;
1017131796Sphk		struct sockaddr *from;
1018131796Sphk		socklen_t fromlenaddr;
101965108Smarcel	} */ bsd_args;
10209313Ssos
1021182890Skib	bsd_args.s = args->s;
1022182890Skib	bsd_args.buf = (caddr_t)PTRIN(args->msg);
1023182890Skib	bsd_args.len = args->len;
1024191988Sdchagin	bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
1025131796Sphk	bsd_args.from = NULL;
1026131796Sphk	bsd_args.fromlenaddr = 0;
1027225617Skmacy	return (sys_recvfrom(td, &bsd_args));
10289313Ssos}
1029293519Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
10309313Ssos
1031293519Sdchaginint
103283366Sjulianlinux_sendto(struct thread *td, struct linux_sendto_args *args)
10339313Ssos{
1034122358Sdwmalone	struct msghdr msg;
1035122358Sdwmalone	struct iovec aiov;
10369313Ssos
1037182890Skib	if (linux_check_hdrincl(td, args->s) == 0)
103865108Smarcel		/* IP_HDRINCL set, tweak the packet before sending */
1039182890Skib		return (linux_sendto_hdrincl(td, args));
104065108Smarcel
1041182890Skib	msg.msg_name = PTRIN(args->to);
1042182890Skib	msg.msg_namelen = args->tolen;
1043122358Sdwmalone	msg.msg_iov = &aiov;
1044122358Sdwmalone	msg.msg_iovlen = 1;
1045122358Sdwmalone	msg.msg_control = NULL;
1046122358Sdwmalone	msg.msg_flags = 0;
1047182890Skib	aiov.iov_base = PTRIN(args->msg);
1048182890Skib	aiov.iov_len = args->len;
1049297518Sdchagin	return (linux_sendit(td, args->s, &msg, args->flags, NULL,
1050297518Sdchagin	    UIO_USERSPACE));
10519313Ssos}
10529313Ssos
1053293519Sdchaginint
105483366Sjulianlinux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
10559313Ssos{
1056293537Sdchagin	struct msghdr msg;
1057293537Sdchagin	struct iovec aiov;
1058302259Sdchagin	int error, fromlen;
10599313Ssos
1060293537Sdchagin	if (PTRIN(args->fromlen) != NULL) {
1061302259Sdchagin		error = copyin(PTRIN(args->fromlen), &fromlen,
1062302259Sdchagin		    sizeof(fromlen));
1063293537Sdchagin		if (error != 0)
1064293537Sdchagin			return (error);
1065302259Sdchagin		if (fromlen < 0)
1066302259Sdchagin			return (EINVAL);
1067302259Sdchagin		msg.msg_namelen = fromlen;
1068293537Sdchagin	} else
1069293537Sdchagin		msg.msg_namelen = 0;
1070293537Sdchagin
1071293537Sdchagin	msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from);
1072293537Sdchagin	msg.msg_iov = &aiov;
1073293537Sdchagin	msg.msg_iovlen = 1;
1074293537Sdchagin	aiov.iov_base = PTRIN(args->buf);
1075293537Sdchagin	aiov.iov_len = args->len;
1076293537Sdchagin	msg.msg_control = 0;
1077293537Sdchagin	msg.msg_flags = linux_to_bsd_msg_flags(args->flags);
1078293537Sdchagin
1079293537Sdchagin	error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL);
1080293537Sdchagin	if (error != 0)
108165108Smarcel		return (error);
108265108Smarcel
1083293537Sdchagin	if (PTRIN(args->from) != NULL) {
1084293537Sdchagin		error = bsd_to_linux_sockaddr((struct sockaddr *)
1085293537Sdchagin		    PTRIN(args->from));
1086293537Sdchagin		if (error != 0)
1087293537Sdchagin			return (error);
1088293537Sdchagin
1089133816Stjr		error = linux_sa_put((struct osockaddr *)
1090182890Skib		    PTRIN(args->from));
1091110295Sume	}
1092293537Sdchagin
1093293537Sdchagin	if (PTRIN(args->fromlen) != NULL)
1094293537Sdchagin		error = copyout(&msg.msg_namelen, PTRIN(args->fromlen),
1095293537Sdchagin		    sizeof(msg.msg_namelen));
1096293537Sdchagin
1097293537Sdchagin	return (error);
10989313Ssos}
10999313Ssos
1100293588Sdchaginstatic int
1101293588Sdchaginlinux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
1102293588Sdchagin    l_uint flags)
1103110295Sume{
1104185442Skib	struct cmsghdr *cmsg;
1105220031Savg	struct cmsgcred cmcred;
1106185442Skib	struct mbuf *control;
1107110295Sume	struct msghdr msg;
1108185442Skib	struct l_cmsghdr linux_cmsg;
1109185442Skib	struct l_cmsghdr *ptr_cmsg;
1110185442Skib	struct l_msghdr linux_msg;
1111131897Sphk	struct iovec *iov;
1112185442Skib	socklen_t datalen;
1113220031Savg	struct sockaddr *sa;
1114220031Savg	sa_family_t sa_family;
1115185442Skib	void *data;
1116110295Sume	int error;
1117110295Sume
1118293588Sdchagin	error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
1119293588Sdchagin	if (error != 0)
1120110295Sume		return (error);
1121168711Srwatson
1122168711Srwatson	/*
1123168711Srwatson	 * Some Linux applications (ping) define a non-NULL control data
1124168711Srwatson	 * pointer, but a msg_controllen of 0, which is not allowed in the
1125168711Srwatson	 * FreeBSD system call interface.  NULL the msg_control pointer in
1126168711Srwatson	 * order to handle this case.  This should be checked, but allows the
1127168711Srwatson	 * Linux ping to work.
1128168711Srwatson	 */
1129220031Savg	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
1130220031Savg		linux_msg.msg_control = PTROUT(NULL);
1131185442Skib
1132220031Savg	error = linux_to_bsd_msghdr(&msg, &linux_msg);
1133293588Sdchagin	if (error != 0)
1134220031Savg		return (error);
1135220031Savg
1136185442Skib#ifdef COMPAT_LINUX32
1137185442Skib	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
1138185442Skib	    &iov, EMSGSIZE);
1139185442Skib#else
1140131897Sphk	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1141185442Skib#endif
1142293588Sdchagin	if (error != 0)
1143131897Sphk		return (error);
1144185442Skib
1145220031Savg	control = NULL;
1146220031Savg	cmsg = NULL;
1147220031Savg
1148220031Savg	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
1149293588Sdchagin		error = kern_getsockname(td, s, &sa, &datalen);
1150293588Sdchagin		if (error != 0)
1151220031Savg			goto bad;
1152220031Savg		sa_family = sa->sa_family;
1153220031Savg		free(sa, M_SONAME);
1154220031Savg
1155185442Skib		error = ENOBUFS;
1156293588Sdchagin		cmsg = malloc(CMSG_HDRSZ, M_LINUX, M_WAITOK|M_ZERO);
1157243882Sglebius		control = m_get(M_WAITOK, MT_CONTROL);
1158185442Skib
1159185442Skib		do {
1160185442Skib			error = copyin(ptr_cmsg, &linux_cmsg,
1161185442Skib			    sizeof(struct l_cmsghdr));
1162293588Sdchagin			if (error != 0)
1163185442Skib				goto bad;
1164185442Skib
1165185442Skib			error = EINVAL;
1166185442Skib			if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr))
1167185442Skib				goto bad;
1168185442Skib
1169185442Skib			/*
1170220031Savg			 * Now we support only SCM_RIGHTS and SCM_CRED,
1171220031Savg			 * so return EINVAL in any other cmsg_type
1172185442Skib			 */
1173220031Savg			cmsg->cmsg_type =
1174220031Savg			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
1175185442Skib			cmsg->cmsg_level =
1176185442Skib			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
1177220031Savg			if (cmsg->cmsg_type == -1
1178220031Savg			    || cmsg->cmsg_level != SOL_SOCKET)
1179220031Savg				goto bad;
1180185442Skib
1181220031Savg			/*
1182220031Savg			 * Some applications (e.g. pulseaudio) attempt to
1183220031Savg			 * send ancillary data even if the underlying protocol
1184220031Savg			 * doesn't support it which is not allowed in the
1185220031Savg			 * FreeBSD system call interface.
1186220031Savg			 */
1187220031Savg			if (sa_family != AF_UNIX)
1188220031Savg				continue;
1189220031Savg
1190220031Savg			data = LINUX_CMSG_DATA(ptr_cmsg);
1191185442Skib			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
1192220031Savg
1193220031Savg			switch (cmsg->cmsg_type)
1194220031Savg			{
1195220031Savg			case SCM_RIGHTS:
1196220031Savg				break;
1197220031Savg
1198220031Savg			case SCM_CREDS:
1199220031Savg				data = &cmcred;
1200220031Savg				datalen = sizeof(cmcred);
1201220031Savg
1202220031Savg				/*
1203220031Savg				 * The lower levels will fill in the structure
1204220031Savg				 */
1205220031Savg				bzero(data, datalen);
1206220031Savg				break;
1207220031Savg			}
1208220031Savg
1209185442Skib			cmsg->cmsg_len = CMSG_LEN(datalen);
1210185442Skib
1211185442Skib			error = ENOBUFS;
1212226074Sjkim			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg))
1213185442Skib				goto bad;
1214226074Sjkim			if (!m_append(control, datalen, (c_caddr_t)data))
1215185442Skib				goto bad;
1216220031Savg		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
1217220031Savg
1218220031Savg		if (m_length(control, NULL) == 0) {
1219220031Savg			m_freem(control);
1220220031Savg			control = NULL;
1221220031Savg		}
1222185442Skib	}
1223185442Skib
1224122358Sdwmalone	msg.msg_iov = iov;
1225122358Sdwmalone	msg.msg_flags = 0;
1226293588Sdchagin	error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE);
1227294529Sdchagin	control = NULL;
1228185442Skib
1229185442Skibbad:
1230293594Sdchagin	m_freem(control);
1231131897Sphk	free(iov, M_IOV);
1232185442Skib	if (cmsg)
1233293532Sdchagin		free(cmsg, M_LINUX);
1234122358Sdwmalone	return (error);
1235110295Sume}
1236110295Sume
1237293519Sdchaginint
1238293588Sdchaginlinux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
123970178Sassar{
1240293588Sdchagin
1241293588Sdchagin	return (linux_sendmsg_common(td, args->s, PTRIN(args->msg),
1242293588Sdchagin	    args->flags));
1243293588Sdchagin}
1244293588Sdchagin
1245293588Sdchaginint
1246293588Sdchaginlinux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args)
1247293588Sdchagin{
1248293588Sdchagin	struct l_mmsghdr *msg;
1249293588Sdchagin	l_uint retval;
1250293588Sdchagin	int error, datagrams;
1251293588Sdchagin
1252293588Sdchagin	if (args->vlen > UIO_MAXIOV)
1253293588Sdchagin		args->vlen = UIO_MAXIOV;
1254293588Sdchagin
1255293588Sdchagin	msg = PTRIN(args->msg);
1256293588Sdchagin	datagrams = 0;
1257293588Sdchagin	while (datagrams < args->vlen) {
1258293588Sdchagin		error = linux_sendmsg_common(td, args->s, &msg->msg_hdr,
1259293588Sdchagin		    args->flags);
1260293588Sdchagin		if (error != 0)
1261293588Sdchagin			break;
1262293588Sdchagin
1263293588Sdchagin		retval = td->td_retval[0];
1264293588Sdchagin		error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
1265293588Sdchagin		if (error != 0)
1266293588Sdchagin			break;
1267293588Sdchagin		++msg;
1268293588Sdchagin		++datagrams;
1269293588Sdchagin	}
1270293588Sdchagin	if (error == 0)
1271293588Sdchagin		td->td_retval[0] = datagrams;
1272293588Sdchagin	return (error);
1273293588Sdchagin}
1274293588Sdchagin
1275293588Sdchaginstatic int
1276293588Sdchaginlinux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
1277293588Sdchagin    l_uint flags, struct msghdr *msg)
1278293588Sdchagin{
1279185442Skib	struct cmsghdr *cm;
1280220031Savg	struct cmsgcred *cmcred;
1281185442Skib	struct l_cmsghdr *linux_cmsg = NULL;
1282220031Savg	struct l_ucred linux_ucred;
1283220031Savg	socklen_t datalen, outlen;
1284185442Skib	struct l_msghdr linux_msg;
1285185442Skib	struct iovec *iov, *uiov;
1286185442Skib	struct mbuf *control = NULL;
1287185442Skib	struct mbuf **controlp;
1288293597Sdchagin	struct timeval *ftmvl;
1289293597Sdchagin	l_timeval ltmvl;
1290185442Skib	caddr_t outbuf;
1291185442Skib	void *data;
1292192284Sdchagin	int error, i, fd, fds, *fdp;
129370178Sassar
1294293588Sdchagin	error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
1295293588Sdchagin	if (error != 0)
1296185442Skib		return (error);
1297133816Stjr
1298293588Sdchagin	error = linux_to_bsd_msghdr(msg, &linux_msg);
1299293588Sdchagin	if (error != 0)
1300166398Skib		return (error);
1301166398Skib
1302185442Skib#ifdef COMPAT_LINUX32
1303293588Sdchagin	error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen,
1304185442Skib	    &iov, EMSGSIZE);
1305185442Skib#else
1306293588Sdchagin	error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE);
1307185442Skib#endif
1308293588Sdchagin	if (error != 0)
1309110295Sume		return (error);
1310110295Sume
1311293588Sdchagin	if (msg->msg_name) {
1312293588Sdchagin		error = linux_to_bsd_sockaddr((struct sockaddr *)msg->msg_name,
1313293588Sdchagin		    msg->msg_namelen);
1314293588Sdchagin		if (error != 0)
1315185442Skib			goto bad;
1316121008Siwasaki	}
1317121008Siwasaki
1318293588Sdchagin	uiov = msg->msg_iov;
1319293588Sdchagin	msg->msg_iov = iov;
1320293588Sdchagin	controlp = (msg->msg_control != NULL) ? &control : NULL;
1321293588Sdchagin	error = kern_recvit(td, s, msg, UIO_USERSPACE, controlp);
1322293588Sdchagin	msg->msg_iov = uiov;
1323293588Sdchagin	if (error != 0)
1324185442Skib		goto bad;
1325185442Skib
1326293588Sdchagin	error = bsd_to_linux_msghdr(msg, &linux_msg);
1327293588Sdchagin	if (error != 0)
1328185442Skib		goto bad;
1329185442Skib
1330185442Skib	if (linux_msg.msg_name) {
1331185442Skib		error = bsd_to_linux_sockaddr((struct sockaddr *)
1332185442Skib		    PTRIN(linux_msg.msg_name));
1333293588Sdchagin		if (error != 0)
1334185442Skib			goto bad;
1335185442Skib	}
1336185442Skib	if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
1337185442Skib		error = linux_sa_put(PTRIN(linux_msg.msg_name));
1338293588Sdchagin		if (error != 0)
1339185442Skib			goto bad;
1340185442Skib	}
1341185442Skib
1342220031Savg	outbuf = PTRIN(linux_msg.msg_control);
1343220031Savg	outlen = 0;
1344220031Savg
1345185442Skib	if (control) {
1346293532Sdchagin		linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
1347185442Skib
1348293588Sdchagin		msg->msg_control = mtod(control, struct cmsghdr *);
1349293588Sdchagin		msg->msg_controllen = control->m_len;
1350220031Savg
1351293588Sdchagin		cm = CMSG_FIRSTHDR(msg);
1352220031Savg
1353185442Skib		while (cm != NULL) {
1354220031Savg			linux_cmsg->cmsg_type =
1355220031Savg			    bsd_to_linux_cmsg_type(cm->cmsg_type);
1356220031Savg			linux_cmsg->cmsg_level =
1357220031Savg			    bsd_to_linux_sockopt_level(cm->cmsg_level);
1358220031Savg			if (linux_cmsg->cmsg_type == -1
1359220031Savg			    || cm->cmsg_level != SOL_SOCKET)
1360185442Skib			{
1361185442Skib				error = EINVAL;
1362185442Skib				goto bad;
1363185442Skib			}
1364220031Savg
1365185442Skib			data = CMSG_DATA(cm);
1366185442Skib			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
1367185442Skib
1368220031Savg			switch (cm->cmsg_type)
1369192284Sdchagin			{
1370220031Savg			case SCM_RIGHTS:
1371293588Sdchagin				if (flags & LINUX_MSG_CMSG_CLOEXEC) {
1372192284Sdchagin					fds = datalen / sizeof(int);
1373192284Sdchagin					fdp = data;
1374192284Sdchagin					for (i = 0; i < fds; i++) {
1375192284Sdchagin						fd = *fdp++;
1376192284Sdchagin						(void)kern_fcntl(td, fd,
1377192284Sdchagin						    F_SETFD, FD_CLOEXEC);
1378192284Sdchagin					}
1379192284Sdchagin				}
1380192284Sdchagin				break;
1381220031Savg
1382220031Savg			case SCM_CREDS:
1383220031Savg				/*
1384220031Savg				 * Currently LOCAL_CREDS is never in
1385220031Savg				 * effect for Linux so no need to worry
1386220031Savg				 * about sockcred
1387220031Savg				 */
1388226074Sjkim				if (datalen != sizeof(*cmcred)) {
1389220031Savg					error = EMSGSIZE;
1390220031Savg					goto bad;
1391220031Savg				}
1392220031Savg				cmcred = (struct cmsgcred *)data;
1393220031Savg				bzero(&linux_ucred, sizeof(linux_ucred));
1394220031Savg				linux_ucred.pid = cmcred->cmcred_pid;
1395220031Savg				linux_ucred.uid = cmcred->cmcred_uid;
1396220031Savg				linux_ucred.gid = cmcred->cmcred_gid;
1397220031Savg				data = &linux_ucred;
1398220031Savg				datalen = sizeof(linux_ucred);
1399220031Savg				break;
1400293597Sdchagin
1401293597Sdchagin			case SCM_TIMESTAMP:
1402293597Sdchagin				if (datalen != sizeof(struct timeval)) {
1403293597Sdchagin					error = EMSGSIZE;
1404293597Sdchagin					goto bad;
1405293597Sdchagin				}
1406293597Sdchagin				ftmvl = (struct timeval *)data;
1407293597Sdchagin				ltmvl.tv_sec = ftmvl->tv_sec;
1408293597Sdchagin				ltmvl.tv_usec = ftmvl->tv_usec;
1409293597Sdchagin				data = &ltmvl;
1410293597Sdchagin				datalen = sizeof(ltmvl);
1411293597Sdchagin				break;
1412185442Skib			}
1413185442Skib
1414220031Savg			if (outlen + LINUX_CMSG_LEN(datalen) >
1415220031Savg			    linux_msg.msg_controllen) {
1416220031Savg				if (outlen == 0) {
1417220031Savg					error = EMSGSIZE;
1418220031Savg					goto bad;
1419220031Savg				} else {
1420220031Savg					linux_msg.msg_flags |=
1421220031Savg					    LINUX_MSG_CTRUNC;
1422220031Savg					goto out;
1423220031Savg				}
1424220031Savg			}
1425220031Savg
1426185442Skib			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
1427185442Skib
1428185442Skib			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
1429185442Skib			if (error)
1430185442Skib				goto bad;
1431185442Skib			outbuf += L_CMSG_HDRSZ;
1432185442Skib
1433185442Skib			error = copyout(data, outbuf, datalen);
1434185442Skib			if (error)
1435185442Skib				goto bad;
1436185442Skib
1437185442Skib			outbuf += LINUX_CMSG_ALIGN(datalen);
1438185442Skib			outlen += LINUX_CMSG_LEN(datalen);
1439185442Skib
1440293588Sdchagin			cm = CMSG_NXTHDR(msg, cm);
1441185442Skib		}
1442185442Skib	}
1443185442Skib
1444185442Skibout:
1445220031Savg	linux_msg.msg_controllen = outlen;
1446293588Sdchagin	error = copyout(&linux_msg, msghdr, sizeof(linux_msg));
1447185442Skib
1448185442Skibbad:
1449185442Skib	free(iov, M_IOV);
1450247764Seadler	m_freem(control);
1451293532Sdchagin	free(linux_cmsg, M_LINUX);
1452185442Skib
1453110295Sume	return (error);
145470178Sassar}
145570178Sassar
1456293519Sdchaginint
1457293588Sdchaginlinux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
1458293588Sdchagin{
1459293588Sdchagin	struct msghdr bsd_msg;
1460293588Sdchagin
1461293588Sdchagin	return (linux_recvmsg_common(td, args->s, PTRIN(args->msg),
1462293588Sdchagin	    args->flags, &bsd_msg));
1463293588Sdchagin}
1464293588Sdchagin
1465293588Sdchaginint
1466293588Sdchaginlinux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args)
1467293588Sdchagin{
1468293588Sdchagin	struct l_mmsghdr *msg;
1469293588Sdchagin	struct msghdr bsd_msg;
1470293588Sdchagin	struct l_timespec lts;
1471293588Sdchagin	struct timespec ts, tts;
1472293588Sdchagin	l_uint retval;
1473293588Sdchagin	int error, datagrams;
1474293588Sdchagin
1475293588Sdchagin	if (args->timeout) {
1476293588Sdchagin		error = copyin(args->timeout, &lts, sizeof(struct l_timespec));
1477293588Sdchagin		if (error != 0)
1478293588Sdchagin			return (error);
1479293588Sdchagin		error = linux_to_native_timespec(&ts, &lts);
1480293588Sdchagin		if (error != 0)
1481293588Sdchagin			return (error);
1482293588Sdchagin		getnanotime(&tts);
1483293588Sdchagin		timespecadd(&tts, &ts);
1484293588Sdchagin	}
1485293588Sdchagin
1486293588Sdchagin	msg = PTRIN(args->msg);
1487293588Sdchagin	datagrams = 0;
1488293588Sdchagin	while (datagrams < args->vlen) {
1489293588Sdchagin		error = linux_recvmsg_common(td, args->s, &msg->msg_hdr,
1490293588Sdchagin		    args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg);
1491293588Sdchagin		if (error != 0)
1492293588Sdchagin			break;
1493293588Sdchagin
1494293588Sdchagin		retval = td->td_retval[0];
1495293588Sdchagin		error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
1496293588Sdchagin		if (error != 0)
1497293588Sdchagin			break;
1498293588Sdchagin		++msg;
1499293588Sdchagin		++datagrams;
1500293588Sdchagin
1501293588Sdchagin		/*
1502293588Sdchagin		 * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet.
1503293588Sdchagin		 */
1504293588Sdchagin		if (args->flags & LINUX_MSG_WAITFORONE)
1505293588Sdchagin			args->flags |= LINUX_MSG_DONTWAIT;
1506293588Sdchagin
1507293588Sdchagin		/*
1508293588Sdchagin		 * See BUGS section of recvmmsg(2).
1509293588Sdchagin		 */
1510293588Sdchagin		if (args->timeout) {
1511293588Sdchagin			getnanotime(&ts);
1512293588Sdchagin			timespecsub(&ts, &tts);
1513293588Sdchagin			if (!timespecisset(&ts) || ts.tv_sec > 0)
1514293588Sdchagin				break;
1515293588Sdchagin		}
1516293588Sdchagin		/* Out of band data, return right away. */
1517293588Sdchagin		if (bsd_msg.msg_flags & MSG_OOB)
1518293588Sdchagin			break;
1519293588Sdchagin	}
1520293588Sdchagin	if (error == 0)
1521293588Sdchagin		td->td_retval[0] = datagrams;
1522293588Sdchagin	return (error);
1523293588Sdchagin}
1524293588Sdchagin
1525293588Sdchaginint
152683366Sjulianlinux_shutdown(struct thread *td, struct linux_shutdown_args *args)
15279313Ssos{
152865108Smarcel	struct shutdown_args /* {
152965108Smarcel		int s;
153065108Smarcel		int how;
153165108Smarcel	} */ bsd_args;
15329313Ssos
1533182890Skib	bsd_args.s = args->s;
1534182890Skib	bsd_args.how = args->how;
1535225617Skmacy	return (sys_shutdown(td, &bsd_args));
15369313Ssos}
15379313Ssos
1538293519Sdchaginint
153983366Sjulianlinux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
15409313Ssos{
154165108Smarcel	struct setsockopt_args /* {
154265108Smarcel		int s;
154365108Smarcel		int level;
154465108Smarcel		int name;
154565108Smarcel		caddr_t val;
154665108Smarcel		int valsize;
154765108Smarcel	} */ bsd_args;
1548191989Sdchagin	l_timeval linux_tv;
1549191989Sdchagin	struct timeval tv;
155065108Smarcel	int error, name;
15519313Ssos
1552182890Skib	bsd_args.s = args->s;
1553182890Skib	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
155465108Smarcel	switch (bsd_args.level) {
155565108Smarcel	case SOL_SOCKET:
1556182890Skib		name = linux_to_bsd_so_sockopt(args->optname);
1557191989Sdchagin		switch (name) {
1558191989Sdchagin		case SO_RCVTIMEO:
1559191989Sdchagin			/* FALLTHROUGH */
1560191989Sdchagin		case SO_SNDTIMEO:
1561191989Sdchagin			error = copyin(PTRIN(args->optval), &linux_tv,
1562191989Sdchagin			    sizeof(linux_tv));
1563191989Sdchagin			if (error)
1564191989Sdchagin				return (error);
1565191989Sdchagin			tv.tv_sec = linux_tv.tv_sec;
1566191989Sdchagin			tv.tv_usec = linux_tv.tv_usec;
1567191989Sdchagin			return (kern_setsockopt(td, args->s, bsd_args.level,
1568191989Sdchagin			    name, &tv, UIO_SYSSPACE, sizeof(tv)));
1569191989Sdchagin			/* NOTREACHED */
1570191989Sdchagin			break;
1571191989Sdchagin		default:
1572191989Sdchagin			break;
1573191989Sdchagin		}
157465108Smarcel		break;
157565108Smarcel	case IPPROTO_IP:
1576182890Skib		name = linux_to_bsd_ip_sockopt(args->optname);
157765108Smarcel		break;
1578297211Sae	case IPPROTO_IPV6:
1579297211Sae		name = linux_to_bsd_ip6_sockopt(args->optname);
1580297211Sae		break;
158165108Smarcel	case IPPROTO_TCP:
1582245849Sjhb		name = linux_to_bsd_tcp_sockopt(args->optname);
158365108Smarcel		break;
158465108Smarcel	default:
158565108Smarcel		name = -1;
158665108Smarcel		break;
158765108Smarcel	}
158865108Smarcel	if (name == -1)
1589162585Snetchild		return (ENOPROTOOPT);
159065108Smarcel
159165108Smarcel	bsd_args.name = name;
1592182890Skib	bsd_args.val = PTRIN(args->optval);
1593182890Skib	bsd_args.valsize = args->optlen;
1594156842Snetchild
1595156842Snetchild	if (name == IPV6_NEXTHOP) {
1596156842Snetchild		linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
1597156842Snetchild			bsd_args.valsize);
1598225617Skmacy		error = sys_setsockopt(td, &bsd_args);
1599156842Snetchild		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1600156842Snetchild	} else
1601225617Skmacy		error = sys_setsockopt(td, &bsd_args);
1602156842Snetchild
1603156842Snetchild	return (error);
16049313Ssos}
16059313Ssos
1606293519Sdchaginint
160783366Sjulianlinux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
16089313Ssos{
160965108Smarcel	struct getsockopt_args /* {
161065108Smarcel		int s;
161165108Smarcel		int level;
161265108Smarcel		int name;
161365108Smarcel		caddr_t val;
161465108Smarcel		int *avalsize;
161565108Smarcel	} */ bsd_args;
1616191989Sdchagin	l_timeval linux_tv;
1617191989Sdchagin	struct timeval tv;
1618301429Sdchagin	socklen_t tv_len, xulen, len;
1619192203Sdchagin	struct xucred xu;
1620192203Sdchagin	struct l_ucred lxu;
1621301429Sdchagin	int error, name, newval;
16229313Ssos
1623182890Skib	bsd_args.s = args->s;
1624182890Skib	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
162565108Smarcel	switch (bsd_args.level) {
162665108Smarcel	case SOL_SOCKET:
1627182890Skib		name = linux_to_bsd_so_sockopt(args->optname);
1628191989Sdchagin		switch (name) {
1629191989Sdchagin		case SO_RCVTIMEO:
1630191989Sdchagin			/* FALLTHROUGH */
1631191989Sdchagin		case SO_SNDTIMEO:
1632191989Sdchagin			tv_len = sizeof(tv);
1633191989Sdchagin			error = kern_getsockopt(td, args->s, bsd_args.level,
1634191989Sdchagin			    name, &tv, UIO_SYSSPACE, &tv_len);
1635191989Sdchagin			if (error)
1636191989Sdchagin				return (error);
1637191989Sdchagin			linux_tv.tv_sec = tv.tv_sec;
1638191989Sdchagin			linux_tv.tv_usec = tv.tv_usec;
1639191989Sdchagin			return (copyout(&linux_tv, PTRIN(args->optval),
1640191989Sdchagin			    sizeof(linux_tv)));
1641191989Sdchagin			/* NOTREACHED */
1642191989Sdchagin			break;
1643192203Sdchagin		case LOCAL_PEERCRED:
1644192203Sdchagin			if (args->optlen != sizeof(lxu))
1645192203Sdchagin				return (EINVAL);
1646192203Sdchagin			xulen = sizeof(xu);
1647192203Sdchagin			error = kern_getsockopt(td, args->s, bsd_args.level,
1648192203Sdchagin			    name, &xu, UIO_SYSSPACE, &xulen);
1649192203Sdchagin			if (error)
1650192203Sdchagin				return (error);
1651192203Sdchagin			/*
1652192203Sdchagin			 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1653192203Sdchagin			 */
1654192203Sdchagin			lxu.pid = 0;
1655192203Sdchagin			lxu.uid = xu.cr_uid;
1656192203Sdchagin			lxu.gid = xu.cr_gid;
1657192203Sdchagin			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
1658192203Sdchagin			/* NOTREACHED */
1659192203Sdchagin			break;
1660301429Sdchagin		case SO_ERROR:
1661301429Sdchagin			len = sizeof(newval);
1662301429Sdchagin			error = kern_getsockopt(td, args->s, bsd_args.level,
1663301429Sdchagin			    name, &newval, UIO_SYSSPACE, &len);
1664301429Sdchagin			if (error)
1665301429Sdchagin				return (error);
1666301429Sdchagin			newval = -SV_ABI_ERRNO(td->td_proc, newval);
1667301429Sdchagin			return (copyout(&newval, PTRIN(args->optval), len));
1668301429Sdchagin			/* NOTREACHED */
1669191989Sdchagin		default:
1670191989Sdchagin			break;
1671191989Sdchagin		}
167265108Smarcel		break;
167365108Smarcel	case IPPROTO_IP:
1674182890Skib		name = linux_to_bsd_ip_sockopt(args->optname);
167565108Smarcel		break;
1676297211Sae	case IPPROTO_IPV6:
1677297211Sae		name = linux_to_bsd_ip6_sockopt(args->optname);
1678297211Sae		break;
167965108Smarcel	case IPPROTO_TCP:
1680245849Sjhb		name = linux_to_bsd_tcp_sockopt(args->optname);
168165108Smarcel		break;
168265108Smarcel	default:
168365108Smarcel		name = -1;
168465108Smarcel		break;
168565108Smarcel	}
168665108Smarcel	if (name == -1)
168765108Smarcel		return (EINVAL);
168865108Smarcel
168965108Smarcel	bsd_args.name = name;
1690182890Skib	bsd_args.val = PTRIN(args->optval);
1691182890Skib	bsd_args.avalsize = PTRIN(args->optlen);
1692156842Snetchild
1693156842Snetchild	if (name == IPV6_NEXTHOP) {
1694225617Skmacy		error = sys_getsockopt(td, &bsd_args);
1695156842Snetchild		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1696156842Snetchild	} else
1697225617Skmacy		error = sys_getsockopt(td, &bsd_args);
1698156842Snetchild
1699156842Snetchild	return (error);
17009313Ssos}
17019313Ssos
1702293521Sdchagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1703293521Sdchagin
1704192373Sdchagin/* Argument list sizes for linux_socketcall */
1705192373Sdchagin
1706192373Sdchagin#define LINUX_AL(x) ((x) * sizeof(l_ulong))
1707192373Sdchagin
1708192373Sdchaginstatic const unsigned char lxs_args[] = {
1709192373Sdchagin	LINUX_AL(0) /* unused*/,	LINUX_AL(3) /* socket */,
1710192373Sdchagin	LINUX_AL(3) /* bind */,		LINUX_AL(3) /* connect */,
1711192373Sdchagin	LINUX_AL(2) /* listen */,	LINUX_AL(3) /* accept */,
1712192373Sdchagin	LINUX_AL(3) /* getsockname */,	LINUX_AL(3) /* getpeername */,
1713192373Sdchagin	LINUX_AL(4) /* socketpair */,	LINUX_AL(4) /* send */,
1714192373Sdchagin	LINUX_AL(4) /* recv */,		LINUX_AL(6) /* sendto */,
1715192373Sdchagin	LINUX_AL(6) /* recvfrom */,	LINUX_AL(2) /* shutdown */,
1716192373Sdchagin	LINUX_AL(5) /* setsockopt */,	LINUX_AL(5) /* getsockopt */,
1717193264Sdchagin	LINUX_AL(3) /* sendmsg */,	LINUX_AL(3) /* recvmsg */,
1718293588Sdchagin	LINUX_AL(4) /* accept4 */,	LINUX_AL(5) /* recvmmsg */,
1719293588Sdchagin	LINUX_AL(4) /* sendmmsg */
1720192373Sdchagin};
1721192373Sdchagin
1722192373Sdchagin#define	LINUX_AL_SIZE	sizeof(lxs_args) / sizeof(lxs_args[0]) - 1
1723192373Sdchagin
17249313Ssosint
172583366Sjulianlinux_socketcall(struct thread *td, struct linux_socketcall_args *args)
17269313Ssos{
1727192373Sdchagin	l_ulong a[6];
1728192373Sdchagin	void *arg;
1729192373Sdchagin	int error;
173042509Smsmith
1731192373Sdchagin	if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE)
1732192373Sdchagin		return (EINVAL);
1733192373Sdchagin	error = copyin(PTRIN(args->args), a, lxs_args[args->what]);
1734192373Sdchagin	if (error)
1735192373Sdchagin		return (error);
1736192373Sdchagin
1737192373Sdchagin	arg = a;
173865108Smarcel	switch (args->what) {
173965108Smarcel	case LINUX_SOCKET:
174083366Sjulian		return (linux_socket(td, arg));
174165108Smarcel	case LINUX_BIND:
174283366Sjulian		return (linux_bind(td, arg));
174365108Smarcel	case LINUX_CONNECT:
174483366Sjulian		return (linux_connect(td, arg));
174565108Smarcel	case LINUX_LISTEN:
174683366Sjulian		return (linux_listen(td, arg));
174765108Smarcel	case LINUX_ACCEPT:
174883366Sjulian		return (linux_accept(td, arg));
174965108Smarcel	case LINUX_GETSOCKNAME:
175083366Sjulian		return (linux_getsockname(td, arg));
175165108Smarcel	case LINUX_GETPEERNAME:
175283366Sjulian		return (linux_getpeername(td, arg));
175365108Smarcel	case LINUX_SOCKETPAIR:
175483366Sjulian		return (linux_socketpair(td, arg));
175565108Smarcel	case LINUX_SEND:
175683366Sjulian		return (linux_send(td, arg));
175765108Smarcel	case LINUX_RECV:
175883366Sjulian		return (linux_recv(td, arg));
175965108Smarcel	case LINUX_SENDTO:
176083366Sjulian		return (linux_sendto(td, arg));
176165108Smarcel	case LINUX_RECVFROM:
176283366Sjulian		return (linux_recvfrom(td, arg));
176365108Smarcel	case LINUX_SHUTDOWN:
176483366Sjulian		return (linux_shutdown(td, arg));
176565108Smarcel	case LINUX_SETSOCKOPT:
176683366Sjulian		return (linux_setsockopt(td, arg));
176765108Smarcel	case LINUX_GETSOCKOPT:
176883366Sjulian		return (linux_getsockopt(td, arg));
176965108Smarcel	case LINUX_SENDMSG:
1770110295Sume		return (linux_sendmsg(td, arg));
177165108Smarcel	case LINUX_RECVMSG:
177283366Sjulian		return (linux_recvmsg(td, arg));
1773193264Sdchagin	case LINUX_ACCEPT4:
1774193264Sdchagin		return (linux_accept4(td, arg));
1775293588Sdchagin	case LINUX_RECVMMSG:
1776293588Sdchagin		return (linux_recvmmsg(td, arg));
1777293588Sdchagin	case LINUX_SENDMMSG:
1778293588Sdchagin		return (linux_sendmmsg(td, arg));
177965108Smarcel	}
178065108Smarcel
17819313Ssos	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
178265108Smarcel	return (ENOSYS);
17839313Ssos}
1784293519Sdchagin#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1785