xref: /freebsd/sys/compat/linux/linux_socket.c (revision bbf392d5eff073919385ecab501fdf9277d2ef68)
1c21dee17SSøren Schmidt /*-
29a14aa01SUlrich Spörlein  * Copyright (c) 1995 Søren Schmidt
3c21dee17SSøren Schmidt  * All rights reserved.
4c21dee17SSøren Schmidt  *
5c21dee17SSøren Schmidt  * Redistribution and use in source and binary forms, with or without
6c21dee17SSøren Schmidt  * modification, are permitted provided that the following conditions
7c21dee17SSøren Schmidt  * are met:
8c21dee17SSøren Schmidt  * 1. Redistributions of source code must retain the above copyright
9c21dee17SSøren Schmidt  *    notice, this list of conditions and the following disclaimer
10c21dee17SSøren Schmidt  *    in this position and unchanged.
11c21dee17SSøren Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
12c21dee17SSøren Schmidt  *    notice, this list of conditions and the following disclaimer in the
13c21dee17SSøren Schmidt  *    documentation and/or other materials provided with the distribution.
14c21dee17SSøren Schmidt  * 3. The name of the author may not be used to endorse or promote products
1521dc7d4fSJens Schweikhardt  *    derived from this software without specific prior written permission
16c21dee17SSøren Schmidt  *
17c21dee17SSøren Schmidt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18c21dee17SSøren Schmidt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19c21dee17SSøren Schmidt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20c21dee17SSøren Schmidt  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21c21dee17SSøren Schmidt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22c21dee17SSøren Schmidt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23c21dee17SSøren Schmidt  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24c21dee17SSøren Schmidt  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25c21dee17SSøren Schmidt  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26c21dee17SSøren Schmidt  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27c21dee17SSøren Schmidt  */
28c21dee17SSøren Schmidt 
2916dbc7f2SDavid E. O'Brien #include <sys/cdefs.h>
3016dbc7f2SDavid E. O'Brien __FBSDID("$FreeBSD$");
3116dbc7f2SDavid E. O'Brien 
321f3dad5aSBruce Evans /* XXX we use functions that might not exist. */
33aefce619SRuslan Ermilov #include "opt_compat.h"
34ca26842eSHajimu UMEMOTO #include "opt_inet6.h"
355591b823SEivind Eklund 
36c21dee17SSøren Schmidt #include <sys/param.h>
37f2477ae1SMike Smith #include <sys/proc.h>
38c21dee17SSøren Schmidt #include <sys/systm.h>
391f3dad5aSBruce Evans #include <sys/sysproto.h>
404a144410SRobert Watson #include <sys/capsicum.h>
41dad3b88aSMike Smith #include <sys/fcntl.h>
420bf301c0SJonathan Lemon #include <sys/file.h>
43104a9b7eSAlexander Kabaev #include <sys/limits.h>
444641373fSJohn Baldwin #include <sys/lock.h>
45ca26842eSHajimu UMEMOTO #include <sys/malloc.h>
464641373fSJohn Baldwin #include <sys/mutex.h>
475a8a13e0SDavid Malone #include <sys/mbuf.h>
48c21dee17SSøren Schmidt #include <sys/socket.h>
490bf301c0SJonathan Lemon #include <sys/socketvar.h>
50ca26842eSHajimu UMEMOTO #include <sys/syscallsubr.h>
5108637435SBruce Evans #include <sys/uio.h>
52ca26842eSHajimu UMEMOTO #include <sys/syslog.h>
53d0b2365eSKonstantin Belousov #include <sys/un.h>
541f3dad5aSBruce Evans 
554b79449eSBjoern A. Zeeb #include <net/if.h>
56eedc7fd9SGleb Smirnoff #include <net/vnet.h>
57c21dee17SSøren Schmidt #include <netinet/in.h>
58f2477ae1SMike Smith #include <netinet/in_systm.h>
59f2477ae1SMike Smith #include <netinet/ip.h>
60fb709557SJohn Baldwin #include <netinet/tcp.h>
61ca26842eSHajimu UMEMOTO #ifdef INET6
62ca26842eSHajimu UMEMOTO #include <netinet/ip6.h>
63ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h>
64ca26842eSHajimu UMEMOTO #endif
65c21dee17SSøren Schmidt 
661997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
674af27623STim J. Robbins #include <machine/../linux32/linux.h>
684af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
691997c537SDavid E. O'Brien #else
701997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
711997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
724af27623STim J. Robbins #endif
734d0f380dSDmitry Chagin #include <compat/linux/linux_file.h>
7440dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
75e1ff74c0SDmitry Chagin #include <compat/linux/linux_timer.h>
76ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
77c21dee17SSøren Schmidt 
78ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int);
79e1ff74c0SDmitry Chagin static int linux_sendmsg_common(struct thread *, l_int, struct l_msghdr *,
80e1ff74c0SDmitry Chagin 					l_uint);
81e1ff74c0SDmitry Chagin static int linux_recvmsg_common(struct thread *, l_int, struct l_msghdr *,
82e1ff74c0SDmitry Chagin 					l_uint, struct msghdr *);
834cf10e29SDmitry Chagin static int linux_set_socket_flags(int, int *);
84ca26842eSHajimu UMEMOTO 
854730796cSBill Fenner /*
86ca26842eSHajimu UMEMOTO  * Reads a linux sockaddr and does any necessary translation.
87ca26842eSHajimu UMEMOTO  * Linux sockaddrs don't have a length field, only a family.
88ca26842eSHajimu UMEMOTO  * Copy the osockaddr structure pointed to by osa to kernel, adjust
89ca26842eSHajimu UMEMOTO  * family and convert to sockaddr.
90ca26842eSHajimu UMEMOTO  */
91ca26842eSHajimu UMEMOTO static int
92b6f96462SJung-uk Kim linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
93ca26842eSHajimu UMEMOTO {
94ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
95ca26842eSHajimu UMEMOTO 	struct osockaddr *kosa;
96ca26842eSHajimu UMEMOTO #ifdef INET6
97ca26842eSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
983106d670SJung-uk Kim 	int oldv6size;
99ca26842eSHajimu UMEMOTO #endif
100c02637c7SJung-uk Kim 	char *name;
101b6f96462SJung-uk Kim 	int bdom, error, hdrlen, namelen;
102ca26842eSHajimu UMEMOTO 
103b6f96462SJung-uk Kim 	if (salen < 2 || salen > UCHAR_MAX || !osa)
104ca26842eSHajimu UMEMOTO 		return (EINVAL);
105ca26842eSHajimu UMEMOTO 
106ca26842eSHajimu UMEMOTO #ifdef INET6
107ca26842eSHajimu UMEMOTO 	oldv6size = 0;
108ca26842eSHajimu UMEMOTO 	/*
109ca26842eSHajimu UMEMOTO 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
110ca26842eSHajimu UMEMOTO 	 * if it's a v4-mapped address, so reserve the proper space
111ca26842eSHajimu UMEMOTO 	 * for it.
112ca26842eSHajimu UMEMOTO 	 */
113b6f96462SJung-uk Kim 	if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
114b6f96462SJung-uk Kim 		salen += sizeof(uint32_t);
115ca26842eSHajimu UMEMOTO 		oldv6size = 1;
116ca26842eSHajimu UMEMOTO 	}
117ca26842eSHajimu UMEMOTO #endif
118ca26842eSHajimu UMEMOTO 
119b6f96462SJung-uk Kim 	kosa = malloc(salen, M_SONAME, M_WAITOK);
120ca26842eSHajimu UMEMOTO 
121b6f96462SJung-uk Kim 	if ((error = copyin(osa, kosa, salen)))
122ca26842eSHajimu UMEMOTO 		goto out;
123ca26842eSHajimu UMEMOTO 
124ca26842eSHajimu UMEMOTO 	bdom = linux_to_bsd_domain(kosa->sa_family);
125ca26842eSHajimu UMEMOTO 	if (bdom == -1) {
1265cb9c68cSXin LI 		error = EAFNOSUPPORT;
127ca26842eSHajimu UMEMOTO 		goto out;
128ca26842eSHajimu UMEMOTO 	}
129ca26842eSHajimu UMEMOTO 
130ca26842eSHajimu UMEMOTO #ifdef INET6
131ca26842eSHajimu UMEMOTO 	/*
132ca26842eSHajimu UMEMOTO 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
133ca26842eSHajimu UMEMOTO 	 * which lacks the scope id compared with RFC2553 one. If we detect
134ca26842eSHajimu UMEMOTO 	 * the situation, reject the address and write a message to system log.
135ca26842eSHajimu UMEMOTO 	 *
136ca26842eSHajimu UMEMOTO 	 * Still accept addresses for which the scope id is not used.
137ca26842eSHajimu UMEMOTO 	 */
138f05531a3SJung-uk Kim 	if (oldv6size) {
139f05531a3SJung-uk Kim 		if (bdom == AF_INET6) {
140ca26842eSHajimu UMEMOTO 			sin6 = (struct sockaddr_in6 *)kosa;
141ca26842eSHajimu UMEMOTO 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
142ca26842eSHajimu UMEMOTO 			    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
143ca26842eSHajimu UMEMOTO 			     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
144ca26842eSHajimu UMEMOTO 			     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
145ca26842eSHajimu UMEMOTO 			     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
146ca26842eSHajimu UMEMOTO 			     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
147ca26842eSHajimu UMEMOTO 				sin6->sin6_scope_id = 0;
148ca26842eSHajimu UMEMOTO 			} else {
149ca26842eSHajimu UMEMOTO 				log(LOG_DEBUG,
1503c616032SGleb Smirnoff 				    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
151ca26842eSHajimu UMEMOTO 				error = EINVAL;
152ca26842eSHajimu UMEMOTO 				goto out;
153ca26842eSHajimu UMEMOTO 			}
154ca26842eSHajimu UMEMOTO 		} else
155b6f96462SJung-uk Kim 			salen -= sizeof(uint32_t);
156f05531a3SJung-uk Kim 	}
157ca26842eSHajimu UMEMOTO #endif
1585cb9c68cSXin LI 	if (bdom == AF_INET) {
159b6f96462SJung-uk Kim 		if (salen < sizeof(struct sockaddr_in)) {
1605cb9c68cSXin LI 			error = EINVAL;
1615cb9c68cSXin LI 			goto out;
1625cb9c68cSXin LI 		}
163b6f96462SJung-uk Kim 		salen = sizeof(struct sockaddr_in);
1645cb9c68cSXin LI 	}
165ca26842eSHajimu UMEMOTO 
166b6f96462SJung-uk Kim 	if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
167c15cdbf2SJung-uk Kim 		hdrlen = offsetof(struct sockaddr_un, sun_path);
168c02637c7SJung-uk Kim 		name = ((struct sockaddr_un *)kosa)->sun_path;
169c02637c7SJung-uk Kim 		if (*name == '\0') {
170c02637c7SJung-uk Kim 			/*
171c02637c7SJung-uk Kim 		 	 * Linux abstract namespace starts with a NULL byte.
172c02637c7SJung-uk Kim 			 * XXX We do not support abstract namespace yet.
173c02637c7SJung-uk Kim 			 */
174b6f96462SJung-uk Kim 			namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
175c02637c7SJung-uk Kim 		} else
176b6f96462SJung-uk Kim 			namelen = strnlen(name, salen - hdrlen);
177bf3a36ccSJung-uk Kim 		salen = hdrlen + namelen;
178bf3a36ccSJung-uk Kim 		if (salen > sizeof(struct sockaddr_un)) {
17943399111SJung-uk Kim 			error = ENAMETOOLONG;
1805da3eb94SColin Percival 			goto out;
1815da3eb94SColin Percival 		}
1825da3eb94SColin Percival 	}
1835da3eb94SColin Percival 
184ca26842eSHajimu UMEMOTO 	sa = (struct sockaddr *)kosa;
185ca26842eSHajimu UMEMOTO 	sa->sa_family = bdom;
186b6f96462SJung-uk Kim 	sa->sa_len = salen;
187ca26842eSHajimu UMEMOTO 
188ca26842eSHajimu UMEMOTO 	*sap = sa;
189ca26842eSHajimu UMEMOTO 	return (0);
190ca26842eSHajimu UMEMOTO 
191ca26842eSHajimu UMEMOTO out:
1920007f669SJung-uk Kim 	free(kosa, M_SONAME);
193ca26842eSHajimu UMEMOTO 	return (error);
194ca26842eSHajimu UMEMOTO }
195ca26842eSHajimu UMEMOTO 
196c21dee17SSøren Schmidt static int
197c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
198c21dee17SSøren Schmidt {
1993f3a4815SMarcel Moolenaar 
200c21dee17SSøren Schmidt 	switch (domain) {
201c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
2023f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
203c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
2043f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
205c21dee17SSøren Schmidt 	case LINUX_AF_INET:
2063f3a4815SMarcel Moolenaar 		return (AF_INET);
207ca26842eSHajimu UMEMOTO 	case LINUX_AF_INET6:
208ca26842eSHajimu UMEMOTO 		return (AF_INET6);
209c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
2103f3a4815SMarcel Moolenaar 		return (AF_CCITT);
211c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
2123f3a4815SMarcel Moolenaar 		return (AF_IPX);
213c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
2143f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
215c21dee17SSøren Schmidt 	}
2163f3a4815SMarcel Moolenaar 	return (-1);
217c21dee17SSøren Schmidt }
218c21dee17SSøren Schmidt 
219ca26842eSHajimu UMEMOTO static int
220ca26842eSHajimu UMEMOTO bsd_to_linux_domain(int domain)
221ca26842eSHajimu UMEMOTO {
222ca26842eSHajimu UMEMOTO 
223ca26842eSHajimu UMEMOTO 	switch (domain) {
224ca26842eSHajimu UMEMOTO 	case AF_UNSPEC:
225ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNSPEC);
226ca26842eSHajimu UMEMOTO 	case AF_LOCAL:
227ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNIX);
228ca26842eSHajimu UMEMOTO 	case AF_INET:
229ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET);
230ca26842eSHajimu UMEMOTO 	case AF_INET6:
231ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET6);
232ca26842eSHajimu UMEMOTO 	case AF_CCITT:
233ca26842eSHajimu UMEMOTO 		return (LINUX_AF_AX25);
234ca26842eSHajimu UMEMOTO 	case AF_IPX:
235ca26842eSHajimu UMEMOTO 		return (LINUX_AF_IPX);
236ca26842eSHajimu UMEMOTO 	case AF_APPLETALK:
237ca26842eSHajimu UMEMOTO 		return (LINUX_AF_APPLETALK);
238ca26842eSHajimu UMEMOTO 	}
239ca26842eSHajimu UMEMOTO 	return (-1);
240ca26842eSHajimu UMEMOTO }
241ca26842eSHajimu UMEMOTO 
242c21dee17SSøren Schmidt static int
243c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
244c21dee17SSøren Schmidt {
2453f3a4815SMarcel Moolenaar 
246c21dee17SSøren Schmidt 	switch (level) {
247c21dee17SSøren Schmidt 	case LINUX_SOL_SOCKET:
2483f3a4815SMarcel Moolenaar 		return (SOL_SOCKET);
249c21dee17SSøren Schmidt 	}
2503f3a4815SMarcel Moolenaar 	return (level);
251c21dee17SSøren Schmidt }
252c21dee17SSøren Schmidt 
2533f3a4815SMarcel Moolenaar static int
25484b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level)
25584b11cd8SMitsuru IWASAKI {
25684b11cd8SMitsuru IWASAKI 
25784b11cd8SMitsuru IWASAKI 	switch (level) {
25884b11cd8SMitsuru IWASAKI 	case SOL_SOCKET:
25984b11cd8SMitsuru IWASAKI 		return (LINUX_SOL_SOCKET);
26084b11cd8SMitsuru IWASAKI 	}
26184b11cd8SMitsuru IWASAKI 	return (level);
26284b11cd8SMitsuru IWASAKI }
26384b11cd8SMitsuru IWASAKI 
26484b11cd8SMitsuru IWASAKI static int
2653f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
266c21dee17SSøren Schmidt {
2673f3a4815SMarcel Moolenaar 
268c21dee17SSøren Schmidt 	switch (opt) {
269c21dee17SSøren Schmidt 	case LINUX_IP_TOS:
2703f3a4815SMarcel Moolenaar 		return (IP_TOS);
271c21dee17SSøren Schmidt 	case LINUX_IP_TTL:
2723f3a4815SMarcel Moolenaar 		return (IP_TTL);
27366ff6a3cSBill Fenner 	case LINUX_IP_OPTIONS:
2743f3a4815SMarcel Moolenaar 		return (IP_OPTIONS);
27566ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_IF:
2763f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_IF);
27766ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_TTL:
2783f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_TTL);
27966ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_LOOP:
2803f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_LOOP);
28166ff6a3cSBill Fenner 	case LINUX_IP_ADD_MEMBERSHIP:
2823f3a4815SMarcel Moolenaar 		return (IP_ADD_MEMBERSHIP);
28366ff6a3cSBill Fenner 	case LINUX_IP_DROP_MEMBERSHIP:
2843f3a4815SMarcel Moolenaar 		return (IP_DROP_MEMBERSHIP);
28566ff6a3cSBill Fenner 	case LINUX_IP_HDRINCL:
2863f3a4815SMarcel Moolenaar 		return (IP_HDRINCL);
287c21dee17SSøren Schmidt 	}
2883f3a4815SMarcel Moolenaar 	return (-1);
289c21dee17SSøren Schmidt }
290c21dee17SSøren Schmidt 
291c21dee17SSøren Schmidt static int
292c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
293c21dee17SSøren Schmidt {
2943f3a4815SMarcel Moolenaar 
295c21dee17SSøren Schmidt 	switch (opt) {
296c21dee17SSøren Schmidt 	case LINUX_SO_DEBUG:
2973f3a4815SMarcel Moolenaar 		return (SO_DEBUG);
298c21dee17SSøren Schmidt 	case LINUX_SO_REUSEADDR:
2993f3a4815SMarcel Moolenaar 		return (SO_REUSEADDR);
300c21dee17SSøren Schmidt 	case LINUX_SO_TYPE:
3013f3a4815SMarcel Moolenaar 		return (SO_TYPE);
302c21dee17SSøren Schmidt 	case LINUX_SO_ERROR:
3033f3a4815SMarcel Moolenaar 		return (SO_ERROR);
304c21dee17SSøren Schmidt 	case LINUX_SO_DONTROUTE:
3053f3a4815SMarcel Moolenaar 		return (SO_DONTROUTE);
306c21dee17SSøren Schmidt 	case LINUX_SO_BROADCAST:
3073f3a4815SMarcel Moolenaar 		return (SO_BROADCAST);
308c21dee17SSøren Schmidt 	case LINUX_SO_SNDBUF:
3093f3a4815SMarcel Moolenaar 		return (SO_SNDBUF);
310c21dee17SSøren Schmidt 	case LINUX_SO_RCVBUF:
3113f3a4815SMarcel Moolenaar 		return (SO_RCVBUF);
312c21dee17SSøren Schmidt 	case LINUX_SO_KEEPALIVE:
3133f3a4815SMarcel Moolenaar 		return (SO_KEEPALIVE);
314c21dee17SSøren Schmidt 	case LINUX_SO_OOBINLINE:
3153f3a4815SMarcel Moolenaar 		return (SO_OOBINLINE);
316c21dee17SSøren Schmidt 	case LINUX_SO_LINGER:
3173f3a4815SMarcel Moolenaar 		return (SO_LINGER);
318d0b2365eSKonstantin Belousov 	case LINUX_SO_PEERCRED:
319d0b2365eSKonstantin Belousov 		return (LOCAL_PEERCRED);
320d0b2365eSKonstantin Belousov 	case LINUX_SO_RCVLOWAT:
321d0b2365eSKonstantin Belousov 		return (SO_RCVLOWAT);
322d0b2365eSKonstantin Belousov 	case LINUX_SO_SNDLOWAT:
323d0b2365eSKonstantin Belousov 		return (SO_SNDLOWAT);
324d0b2365eSKonstantin Belousov 	case LINUX_SO_RCVTIMEO:
325d0b2365eSKonstantin Belousov 		return (SO_RCVTIMEO);
326d0b2365eSKonstantin Belousov 	case LINUX_SO_SNDTIMEO:
327d0b2365eSKonstantin Belousov 		return (SO_SNDTIMEO);
328d0b2365eSKonstantin Belousov 	case LINUX_SO_TIMESTAMP:
329d0b2365eSKonstantin Belousov 		return (SO_TIMESTAMP);
330d0b2365eSKonstantin Belousov 	case LINUX_SO_ACCEPTCONN:
331d0b2365eSKonstantin Belousov 		return (SO_ACCEPTCONN);
332c21dee17SSøren Schmidt 	}
3333f3a4815SMarcel Moolenaar 	return (-1);
334c21dee17SSøren Schmidt }
335c21dee17SSøren Schmidt 
33640dbba57SAssar Westerlund static int
337fb709557SJohn Baldwin linux_to_bsd_tcp_sockopt(int opt)
338fb709557SJohn Baldwin {
339fb709557SJohn Baldwin 
340fb709557SJohn Baldwin 	switch (opt) {
341fb709557SJohn Baldwin 	case LINUX_TCP_NODELAY:
342fb709557SJohn Baldwin 		return (TCP_NODELAY);
343fb709557SJohn Baldwin 	case LINUX_TCP_MAXSEG:
344fb709557SJohn Baldwin 		return (TCP_MAXSEG);
345fb709557SJohn Baldwin 	case LINUX_TCP_KEEPIDLE:
346fb709557SJohn Baldwin 		return (TCP_KEEPIDLE);
347fb709557SJohn Baldwin 	case LINUX_TCP_KEEPINTVL:
348fb709557SJohn Baldwin 		return (TCP_KEEPINTVL);
349fb709557SJohn Baldwin 	case LINUX_TCP_KEEPCNT:
350fb709557SJohn Baldwin 		return (TCP_KEEPCNT);
351fb709557SJohn Baldwin 	case LINUX_TCP_MD5SIG:
352fb709557SJohn Baldwin 		return (TCP_MD5SIG);
353fb709557SJohn Baldwin 	}
354fb709557SJohn Baldwin 	return (-1);
355fb709557SJohn Baldwin }
356fb709557SJohn Baldwin 
357fb709557SJohn Baldwin static int
35840dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
35940dbba57SAssar Westerlund {
36040dbba57SAssar Westerlund 	int ret_flags = 0;
36140dbba57SAssar Westerlund 
36240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
36340dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
36440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
36540dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
36640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
36740dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
36840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
36940dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
37040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
37140dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
37240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
37340dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
37440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
37540dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
37640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
37740dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
3788d6e40c3SMaxim Sobolev 	if (flags & LINUX_MSG_NOSIGNAL)
3798d6e40c3SMaxim Sobolev 		ret_flags |= MSG_NOSIGNAL;
38040dbba57SAssar Westerlund #if 0 /* not handled */
38140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
38240dbba57SAssar Westerlund 		;
38340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
38440dbba57SAssar Westerlund 		;
38540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
38640dbba57SAssar Westerlund 		;
38740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
38840dbba57SAssar Westerlund 		;
38940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
39040dbba57SAssar Westerlund 		;
39140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
39240dbba57SAssar Westerlund 		;
39340dbba57SAssar Westerlund #endif
39440dbba57SAssar Westerlund 	return ret_flags;
39540dbba57SAssar Westerlund }
39640dbba57SAssar Westerlund 
3975c8919adSAlexander Leidinger /*
3985c8919adSAlexander Leidinger * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
3995c8919adSAlexander Leidinger * native syscall will fault.  Thus, we don't really need to check the
4005c8919adSAlexander Leidinger * return values for these functions.
4015c8919adSAlexander Leidinger */
4025c8919adSAlexander Leidinger 
4035c8919adSAlexander Leidinger static int
4045c8919adSAlexander Leidinger bsd_to_linux_sockaddr(struct sockaddr *arg)
4055c8919adSAlexander Leidinger {
4065c8919adSAlexander Leidinger 	struct sockaddr sa;
4075c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
4085c8919adSAlexander Leidinger 	int error;
4095c8919adSAlexander Leidinger 
4105c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
4115c8919adSAlexander Leidinger 		return (error);
4125c8919adSAlexander Leidinger 
4135c8919adSAlexander Leidinger 	*(u_short *)&sa = sa.sa_family;
4145c8919adSAlexander Leidinger 
4155c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
4165c8919adSAlexander Leidinger 
4175c8919adSAlexander Leidinger 	return (error);
4185c8919adSAlexander Leidinger }
4195c8919adSAlexander Leidinger 
4205c8919adSAlexander Leidinger static int
4215c8919adSAlexander Leidinger linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
4225c8919adSAlexander Leidinger {
4235c8919adSAlexander Leidinger 	struct sockaddr sa;
4245c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
4255c8919adSAlexander Leidinger 	int error;
4265c8919adSAlexander Leidinger 
4275c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
4285c8919adSAlexander Leidinger 		return (error);
4295c8919adSAlexander Leidinger 
4305c8919adSAlexander Leidinger 	sa.sa_family = *(sa_family_t *)&sa;
4315c8919adSAlexander Leidinger 	sa.sa_len = len;
4325c8919adSAlexander Leidinger 
4335c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
4345c8919adSAlexander Leidinger 
4355c8919adSAlexander Leidinger 	return (error);
4365c8919adSAlexander Leidinger }
4375c8919adSAlexander Leidinger 
438ca26842eSHajimu UMEMOTO static int
439ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa)
440ca26842eSHajimu UMEMOTO {
441ca26842eSHajimu UMEMOTO 	struct osockaddr sa;
442ca26842eSHajimu UMEMOTO 	int error, bdom;
443ca26842eSHajimu UMEMOTO 
444ca26842eSHajimu UMEMOTO 	/*
445ca26842eSHajimu UMEMOTO 	 * Only read/write the osockaddr family part, the rest is
446ca26842eSHajimu UMEMOTO 	 * not changed.
447ca26842eSHajimu UMEMOTO 	 */
4484b7ef73dSDag-Erling Smørgrav 	error = copyin(osa, &sa, sizeof(sa.sa_family));
449ca26842eSHajimu UMEMOTO 	if (error)
450ca26842eSHajimu UMEMOTO 		return (error);
451ca26842eSHajimu UMEMOTO 
452ca26842eSHajimu UMEMOTO 	bdom = bsd_to_linux_domain(sa.sa_family);
453ca26842eSHajimu UMEMOTO 	if (bdom == -1)
454ca26842eSHajimu UMEMOTO 		return (EINVAL);
455ca26842eSHajimu UMEMOTO 
456ca26842eSHajimu UMEMOTO 	sa.sa_family = bdom;
457ca26842eSHajimu UMEMOTO 	error = copyout(&sa, osa, sizeof(sa.sa_family));
458ca26842eSHajimu UMEMOTO 	if (error)
459ca26842eSHajimu UMEMOTO 		return (error);
460ca26842eSHajimu UMEMOTO 
461ca26842eSHajimu UMEMOTO 	return (0);
462ca26842eSHajimu UMEMOTO }
463ca26842eSHajimu UMEMOTO 
4645a8a13e0SDavid Malone static int
46574f5d680SKonstantin Belousov linux_to_bsd_cmsg_type(int cmsg_type)
4665a8a13e0SDavid Malone {
46774f5d680SKonstantin Belousov 
46874f5d680SKonstantin Belousov 	switch (cmsg_type) {
46974f5d680SKonstantin Belousov 	case LINUX_SCM_RIGHTS:
47074f5d680SKonstantin Belousov 		return (SCM_RIGHTS);
471605da56bSAndriy Gapon 	case LINUX_SCM_CREDENTIALS:
472605da56bSAndriy Gapon 		return (SCM_CREDS);
47374f5d680SKonstantin Belousov 	}
47474f5d680SKonstantin Belousov 	return (-1);
47574f5d680SKonstantin Belousov }
47674f5d680SKonstantin Belousov 
47774f5d680SKonstantin Belousov static int
47874f5d680SKonstantin Belousov bsd_to_linux_cmsg_type(int cmsg_type)
47974f5d680SKonstantin Belousov {
48074f5d680SKonstantin Belousov 
48174f5d680SKonstantin Belousov 	switch (cmsg_type) {
48274f5d680SKonstantin Belousov 	case SCM_RIGHTS:
48374f5d680SKonstantin Belousov 		return (LINUX_SCM_RIGHTS);
484605da56bSAndriy Gapon 	case SCM_CREDS:
485605da56bSAndriy Gapon 		return (LINUX_SCM_CREDENTIALS);
486*bbf392d5SDmitry Chagin 	case SCM_TIMESTAMP:
487*bbf392d5SDmitry Chagin 		return (LINUX_SCM_TIMESTAMP);
48874f5d680SKonstantin Belousov 	}
48974f5d680SKonstantin Belousov 	return (-1);
49074f5d680SKonstantin Belousov }
49174f5d680SKonstantin Belousov 
49274f5d680SKonstantin Belousov static int
49374f5d680SKonstantin Belousov linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
49474f5d680SKonstantin Belousov {
49574f5d680SKonstantin Belousov 	if (lhdr->msg_controllen > INT_MAX)
49674f5d680SKonstantin Belousov 		return (ENOBUFS);
49774f5d680SKonstantin Belousov 
49874f5d680SKonstantin Belousov 	bhdr->msg_name		= PTRIN(lhdr->msg_name);
49974f5d680SKonstantin Belousov 	bhdr->msg_namelen	= lhdr->msg_namelen;
50074f5d680SKonstantin Belousov 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
50174f5d680SKonstantin Belousov 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
50274f5d680SKonstantin Belousov 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
503605da56bSAndriy Gapon 
504605da56bSAndriy Gapon 	/*
505605da56bSAndriy Gapon 	 * msg_controllen is skipped since BSD and LINUX control messages
506605da56bSAndriy Gapon 	 * are potentially different sizes (e.g. the cred structure used
507605da56bSAndriy Gapon 	 * by SCM_CREDS is different between the two operating system).
508605da56bSAndriy Gapon 	 *
509605da56bSAndriy Gapon 	 * The caller can set it (if necessary) after converting all the
510605da56bSAndriy Gapon 	 * control messages.
511605da56bSAndriy Gapon 	 */
512605da56bSAndriy Gapon 
51374f5d680SKonstantin Belousov 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
51474f5d680SKonstantin Belousov 	return (0);
51574f5d680SKonstantin Belousov }
51674f5d680SKonstantin Belousov 
51774f5d680SKonstantin Belousov static int
51874f5d680SKonstantin Belousov bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
51974f5d680SKonstantin Belousov {
52074f5d680SKonstantin Belousov 	lhdr->msg_name		= PTROUT(bhdr->msg_name);
52174f5d680SKonstantin Belousov 	lhdr->msg_namelen	= bhdr->msg_namelen;
52274f5d680SKonstantin Belousov 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
52374f5d680SKonstantin Belousov 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
52474f5d680SKonstantin Belousov 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
525605da56bSAndriy Gapon 
526605da56bSAndriy Gapon 	/*
527605da56bSAndriy Gapon 	 * msg_controllen is skipped since BSD and LINUX control messages
528605da56bSAndriy Gapon 	 * are potentially different sizes (e.g. the cred structure used
529605da56bSAndriy Gapon 	 * by SCM_CREDS is different between the two operating system).
530605da56bSAndriy Gapon 	 *
531605da56bSAndriy Gapon 	 * The caller can set it (if necessary) after converting all the
532605da56bSAndriy Gapon 	 * control messages.
533605da56bSAndriy Gapon 	 */
534605da56bSAndriy Gapon 
53574f5d680SKonstantin Belousov 	/* msg_flags skipped */
53674f5d680SKonstantin Belousov 	return (0);
53774f5d680SKonstantin Belousov }
53874f5d680SKonstantin Belousov 
53974f5d680SKonstantin Belousov static int
5404cf10e29SDmitry Chagin linux_set_socket_flags(int lflags, int *flags)
54138a18e97SDmitry Chagin {
54238a18e97SDmitry Chagin 
5434cf10e29SDmitry Chagin 	if (lflags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
5444cf10e29SDmitry Chagin 		return (EINVAL);
5454cf10e29SDmitry Chagin 	if (lflags & LINUX_SOCK_NONBLOCK)
5464cf10e29SDmitry Chagin 		*flags |= SOCK_NONBLOCK;
5474cf10e29SDmitry Chagin 	if (lflags & LINUX_SOCK_CLOEXEC)
5484cf10e29SDmitry Chagin 		*flags |= SOCK_CLOEXEC;
54938a18e97SDmitry Chagin 	return (0);
55038a18e97SDmitry Chagin }
55138a18e97SDmitry Chagin 
55238a18e97SDmitry Chagin static int
55374f5d680SKonstantin Belousov linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
55474f5d680SKonstantin Belousov     struct mbuf *control, enum uio_seg segflg)
55574f5d680SKonstantin Belousov {
5565a8a13e0SDavid Malone 	struct sockaddr *to;
5575a8a13e0SDavid Malone 	int error;
5585a8a13e0SDavid Malone 
5595a8a13e0SDavid Malone 	if (mp->msg_name != NULL) {
5605a8a13e0SDavid Malone 		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
5615a8a13e0SDavid Malone 		if (error)
5625a8a13e0SDavid Malone 			return (error);
5635a8a13e0SDavid Malone 		mp->msg_name = to;
5645a8a13e0SDavid Malone 	} else
5655a8a13e0SDavid Malone 		to = NULL;
5665a8a13e0SDavid Malone 
567a6886ef1SMaxim Sobolev 	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
568a6886ef1SMaxim Sobolev 	    segflg);
5695a8a13e0SDavid Malone 
5705a8a13e0SDavid Malone 	if (to)
5711ede983cSDag-Erling Smørgrav 		free(to, M_SONAME);
5725a8a13e0SDavid Malone 	return (error);
5735a8a13e0SDavid Malone }
5745a8a13e0SDavid Malone 
5753f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
576f2477ae1SMike Smith static int
577e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s)
578f2477ae1SMike Smith {
579857ad5a3SDmitry Chagin 	int error, optval;
580857ad5a3SDmitry Chagin 	socklen_t size_val;
581f2477ae1SMike Smith 
582e140eb43SDavid Malone 	size_val = sizeof(optval);
583e140eb43SDavid Malone 	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
584e140eb43SDavid Malone 	    &optval, UIO_SYSSPACE, &size_val);
585e140eb43SDavid Malone 	if (error)
5863f3a4815SMarcel Moolenaar 		return (error);
5873f3a4815SMarcel Moolenaar 
5883f3a4815SMarcel Moolenaar 	return (optval == 0);
589f2477ae1SMike Smith }
590f2477ae1SMike Smith 
591f2477ae1SMike Smith /*
592f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
593f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
594f2477ae1SMike Smith  */
595f2477ae1SMike Smith static int
59638da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
597f2477ae1SMike Smith {
598f2477ae1SMike Smith /*
599f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
600f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
601a6886ef1SMaxim Sobolev  * It should include all the fields we modify (ip_len and ip_off).
602f2477ae1SMike Smith  */
603f2477ae1SMike Smith #define linux_ip_copysize	8
604f2477ae1SMike Smith 
605f2477ae1SMike Smith 	struct ip *packet;
6065a8a13e0SDavid Malone 	struct msghdr msg;
607a6886ef1SMaxim Sobolev 	struct iovec aiov[1];
608f2477ae1SMike Smith 	int error;
609f2477ae1SMike Smith 
610aa675b57SDavid Schultz 	/* Check that the packet isn't too big or too small. */
611aa675b57SDavid Schultz 	if (linux_args->len < linux_ip_copysize ||
612aa675b57SDavid Schultz 	    linux_args->len > IP_MAXPACKET)
6133f3a4815SMarcel Moolenaar 		return (EINVAL);
614f2477ae1SMike Smith 
615e0d3ea8cSDmitry Chagin 	packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK);
616f2477ae1SMike Smith 
617a6886ef1SMaxim Sobolev 	/* Make kernel copy of the packet to be sent */
6184af27623STim J. Robbins 	if ((error = copyin(PTRIN(linux_args->msg), packet,
619a6886ef1SMaxim Sobolev 	    linux_args->len)))
620a6886ef1SMaxim Sobolev 		goto goout;
621f2477ae1SMike Smith 
622f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
6235a8a13e0SDavid Malone 	packet->ip_len = linux_args->len;
624f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
625f2477ae1SMike Smith 
626f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
6274af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args->to);
6285a8a13e0SDavid Malone 	msg.msg_namelen = linux_args->tolen;
6295a8a13e0SDavid Malone 	msg.msg_iov = aiov;
630a6886ef1SMaxim Sobolev 	msg.msg_iovlen = 1;
6315a8a13e0SDavid Malone 	msg.msg_control = NULL;
6325a8a13e0SDavid Malone 	msg.msg_flags = 0;
6335a8a13e0SDavid Malone 	aiov[0].iov_base = (char *)packet;
634a6886ef1SMaxim Sobolev 	aiov[0].iov_len = linux_args->len;
635a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
63674f5d680SKonstantin Belousov 	    NULL, UIO_SYSSPACE);
637a6886ef1SMaxim Sobolev goout:
638e0d3ea8cSDmitry Chagin 	free(packet, M_LINUX);
6395a8a13e0SDavid Malone 	return (error);
640f2477ae1SMike Smith }
641f2477ae1SMike Smith 
642a12b9b3dSDmitry Chagin int
643b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
644c21dee17SSøren Schmidt {
645ef04503dSPeter Wemm 	struct socket_args /* {
646c21dee17SSøren Schmidt 		int domain;
647c21dee17SSøren Schmidt 		int type;
648c21dee17SSøren Schmidt 		int protocol;
649ef04503dSPeter Wemm 	} */ bsd_args;
6504cf10e29SDmitry Chagin 	int retval_socket;
651c21dee17SSøren Schmidt 
652745aaef5SKonstantin Belousov 	bsd_args.protocol = args->protocol;
6533933bde2SDmitry Chagin 	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
654eeb63e51SDmitry Chagin 	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
655eeb63e51SDmitry Chagin 		return (EINVAL);
6564cf10e29SDmitry Chagin 	retval_socket = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
6574cf10e29SDmitry Chagin 		&bsd_args.type);
6584cf10e29SDmitry Chagin 	if (retval_socket != 0)
6594cf10e29SDmitry Chagin 		return (retval_socket);
660745aaef5SKonstantin Belousov 	bsd_args.domain = linux_to_bsd_domain(args->domain);
661c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
662d9b063ccSDmitry Chagin 		return (EAFNOSUPPORT);
663f2477ae1SMike Smith 
6648451d0ddSKip Macy 	retval_socket = sys_socket(td, &bsd_args);
6656994ea54SDmitry Chagin 	if (retval_socket)
6666994ea54SDmitry Chagin 		return (retval_socket);
6676994ea54SDmitry Chagin 
668f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
669f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
6706994ea54SDmitry Chagin 	    && bsd_args.domain == PF_INET) {
671f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
672e140eb43SDavid Malone 		int hdrincl;
673f2477ae1SMike Smith 
674e140eb43SDavid Malone 		hdrincl = 1;
675e140eb43SDavid Malone 		/* We ignore any error returned by kern_setsockopt() */
676e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
677e140eb43SDavid Malone 		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
678f2477ae1SMike Smith 	}
679ca26842eSHajimu UMEMOTO #ifdef INET6
680ca26842eSHajimu UMEMOTO 	/*
681d97bee3eSBjoern A. Zeeb 	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default
682d97bee3eSBjoern A. Zeeb 	 * and some apps depend on this. So, set V6ONLY to 0 for Linux apps.
683d97bee3eSBjoern A. Zeeb 	 * For simplicity we do this unconditionally of the net.inet6.ip6.v6only
684d97bee3eSBjoern A. Zeeb 	 * sysctl value.
685ca26842eSHajimu UMEMOTO 	 */
686d97bee3eSBjoern A. Zeeb 	if (bsd_args.domain == PF_INET6) {
687e140eb43SDavid Malone 		int v6only;
688ca26842eSHajimu UMEMOTO 
689e140eb43SDavid Malone 		v6only = 0;
690ca26842eSHajimu UMEMOTO 		/* We ignore any error returned by setsockopt() */
691e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
692e140eb43SDavid Malone 		    &v6only, UIO_SYSSPACE, sizeof(v6only));
693ca26842eSHajimu UMEMOTO 	}
694ca26842eSHajimu UMEMOTO #endif
6953f3a4815SMarcel Moolenaar 
6963f3a4815SMarcel Moolenaar 	return (retval_socket);
697c21dee17SSøren Schmidt }
698c21dee17SSøren Schmidt 
699a12b9b3dSDmitry Chagin int
700b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
701c21dee17SSøren Schmidt {
702ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
703c21dee17SSøren Schmidt 	int error;
704c21dee17SSøren Schmidt 
705745aaef5SKonstantin Belousov 	error = linux_getsockaddr(&sa, PTRIN(args->name),
706745aaef5SKonstantin Belousov 	    args->namelen);
707ca26842eSHajimu UMEMOTO 	if (error)
708ca26842eSHajimu UMEMOTO 		return (error);
709ca26842eSHajimu UMEMOTO 
7106e646651SKonstantin Belousov 	error = kern_bindat(td, AT_FDCWD, args->s, sa);
711b33887eaSJohn Baldwin 	free(sa, M_SONAME);
712745aaef5SKonstantin Belousov 	if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
713d4b7423fSAlexander Leidinger 	   	return (EINVAL);
714b33887eaSJohn Baldwin 	return (error);
715c21dee17SSøren Schmidt }
716c21dee17SSøren Schmidt 
717930a65feSAndrew Gallatin int
718b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
719c21dee17SSøren Schmidt {
7207008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
7210bf301c0SJonathan Lemon 	struct socket *so;
722ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
72339c95b83SMatthew Dillon 	u_int fflag;
724c21dee17SSøren Schmidt 	int error;
725c21dee17SSøren Schmidt 
726745aaef5SKonstantin Belousov 	error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
727745aaef5SKonstantin Belousov 	    args->namelen);
728ca26842eSHajimu UMEMOTO 	if (error)
729ca26842eSHajimu UMEMOTO 		return (error);
730ca26842eSHajimu UMEMOTO 
7316e646651SKonstantin Belousov 	error = kern_connectat(td, AT_FDCWD, args->s, sa);
732b33887eaSJohn Baldwin 	free(sa, M_SONAME);
7330bf301c0SJonathan Lemon 	if (error != EISCONN)
7340bf301c0SJonathan Lemon 		return (error);
7350bf301c0SJonathan Lemon 
736dad3b88aSMike Smith 	/*
737dad3b88aSMike Smith 	 * Linux doesn't return EISCONN the first time it occurs,
738dad3b88aSMike Smith 	 * when on a non-blocking socket. Instead it returns the
739dad3b88aSMike Smith 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
740f7f45ac8SRobert Watson 	 *
741f7f45ac8SRobert Watson 	 * XXXRW: Instead of using fgetsock(), check that it is a
742f7f45ac8SRobert Watson 	 * socket and use the file descriptor reference instead of
743f7f45ac8SRobert Watson 	 * creating a new one.
744dad3b88aSMike Smith 	 */
7457008be5bSPawel Jakub Dawidek 	error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT),
7467008be5bSPawel Jakub Dawidek 	    &so, &fflag);
7474641373fSJohn Baldwin 	if (error == 0) {
7480bf301c0SJonathan Lemon 		error = EISCONN;
74939c95b83SMatthew Dillon 		if (fflag & FNONBLOCK) {
7504641373fSJohn Baldwin 			SOCK_LOCK(so);
7515002a60fSMarcel Moolenaar 			if (so->so_emuldata == 0)
7520bf301c0SJonathan Lemon 				error = so->so_error;
7530bf301c0SJonathan Lemon 			so->so_emuldata = (void *)1;
7544641373fSJohn Baldwin 			SOCK_UNLOCK(so);
755dad3b88aSMike Smith 		}
75639c95b83SMatthew Dillon 		fputsock(so);
7574641373fSJohn Baldwin 	}
7583f3a4815SMarcel Moolenaar 	return (error);
759c21dee17SSøren Schmidt }
760c21dee17SSøren Schmidt 
761a12b9b3dSDmitry Chagin int
762b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
763c21dee17SSøren Schmidt {
764ef04503dSPeter Wemm 	struct listen_args /* {
765c21dee17SSøren Schmidt 		int s;
766c21dee17SSøren Schmidt 		int backlog;
767ef04503dSPeter Wemm 	} */ bsd_args;
768c21dee17SSøren Schmidt 
769745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
770745aaef5SKonstantin Belousov 	bsd_args.backlog = args->backlog;
7718451d0ddSKip Macy 	return (sys_listen(td, &bsd_args));
772c21dee17SSøren Schmidt }
773c21dee17SSøren Schmidt 
77401e0ffbaSAlexander Leidinger static int
775c8f37d61SDmitry Chagin linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
776f83427b8SDmitry Chagin     l_uintptr_t namelen, int flags)
777c21dee17SSøren Schmidt {
7784cf10e29SDmitry Chagin 	struct accept4_args /* {
779c21dee17SSøren Schmidt 		int	s;
7803db2a843SBruce Evans 		struct sockaddr * __restrict name;
7813db2a843SBruce Evans 		socklen_t * __restrict anamelen;
7824cf10e29SDmitry Chagin 		int	flags;
783ef04503dSPeter Wemm 	} */ bsd_args;
78493e694c9SDmitry Chagin 	int error;
78593e694c9SDmitry Chagin 
786c8f37d61SDmitry Chagin 	bsd_args.s = s;
7873db2a843SBruce Evans 	/* XXX: */
788c8f37d61SDmitry Chagin 	bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr);
789c8f37d61SDmitry Chagin 	bsd_args.anamelen = PTRIN(namelen);/* XXX */
7904cf10e29SDmitry Chagin 	error = linux_set_socket_flags(flags, &bsd_args.flags);
7914cf10e29SDmitry Chagin 	if (error != 0)
7924cf10e29SDmitry Chagin 		return (error);
7934cf10e29SDmitry Chagin 	error = sys_accept4(td, &bsd_args);
7945c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
795d4b7423fSAlexander Leidinger 	if (error) {
796c8f37d61SDmitry Chagin 		if (error == EFAULT && namelen != sizeof(struct sockaddr_in))
797d4b7423fSAlexander Leidinger 			return (EINVAL);
798dba5ab66SMarcel Moolenaar 		return (error);
799d4b7423fSAlexander Leidinger 	}
80093e694c9SDmitry Chagin 	if (addr)
80193e694c9SDmitry Chagin 		error = linux_sa_put(PTRIN(addr));
80293e694c9SDmitry Chagin 	if (error) {
80393e694c9SDmitry Chagin 		(void)kern_close(td, td->td_retval[0]);
80493e694c9SDmitry Chagin 		td->td_retval[0] = 0;
80593e694c9SDmitry Chagin 	}
80693e694c9SDmitry Chagin 	return (error);
807c21dee17SSøren Schmidt }
808c21dee17SSøren Schmidt 
809a12b9b3dSDmitry Chagin int
810c8f37d61SDmitry Chagin linux_accept(struct thread *td, struct linux_accept_args *args)
811c8f37d61SDmitry Chagin {
812c8f37d61SDmitry Chagin 
813c8f37d61SDmitry Chagin 	return (linux_accept_common(td, args->s, args->addr,
814f83427b8SDmitry Chagin 	    args->namelen, 0));
815c8f37d61SDmitry Chagin }
816c8f37d61SDmitry Chagin 
817a12b9b3dSDmitry Chagin int
818f8cd0af2SDmitry Chagin linux_accept4(struct thread *td, struct linux_accept4_args *args)
819f8cd0af2SDmitry Chagin {
820f8cd0af2SDmitry Chagin 
821f8cd0af2SDmitry Chagin 	return (linux_accept_common(td, args->s, args->addr,
822f8cd0af2SDmitry Chagin 	    args->namelen, args->flags));
823f8cd0af2SDmitry Chagin }
824f8cd0af2SDmitry Chagin 
825a12b9b3dSDmitry Chagin int
826b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
827c21dee17SSøren Schmidt {
828ef04503dSPeter Wemm 	struct getsockname_args /* {
829c21dee17SSøren Schmidt 		int	fdes;
8303db2a843SBruce Evans 		struct sockaddr * __restrict asa;
8313db2a843SBruce Evans 		socklen_t * __restrict alen;
832ef04503dSPeter Wemm 	} */ bsd_args;
833c21dee17SSøren Schmidt 	int error;
834c21dee17SSøren Schmidt 
835745aaef5SKonstantin Belousov 	bsd_args.fdes = args->s;
8363db2a843SBruce Evans 	/* XXX: */
837745aaef5SKonstantin Belousov 	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
838745aaef5SKonstantin Belousov 	bsd_args.alen = PTRIN(args->namelen);	/* XXX */
8398451d0ddSKip Macy 	error = sys_getsockname(td, &bsd_args);
8405c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
841ca26842eSHajimu UMEMOTO 	if (error)
842ca26842eSHajimu UMEMOTO 		return (error);
843745aaef5SKonstantin Belousov 	error = linux_sa_put(PTRIN(args->addr));
844ca26842eSHajimu UMEMOTO 	if (error)
845ca26842eSHajimu UMEMOTO 		return (error);
846ca26842eSHajimu UMEMOTO 	return (0);
847c21dee17SSøren Schmidt }
848c21dee17SSøren Schmidt 
849a12b9b3dSDmitry Chagin int
850b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
851c21dee17SSøren Schmidt {
8525c8919adSAlexander Leidinger 	struct getpeername_args /* {
853c21dee17SSøren Schmidt 		int fdes;
854c21dee17SSøren Schmidt 		caddr_t asa;
855c21dee17SSøren Schmidt 		int *alen;
856ef04503dSPeter Wemm 	} */ bsd_args;
857c21dee17SSøren Schmidt 	int error;
858c21dee17SSøren Schmidt 
859745aaef5SKonstantin Belousov 	bsd_args.fdes = args->s;
860745aaef5SKonstantin Belousov 	bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
861857ad5a3SDmitry Chagin 	bsd_args.alen = (socklen_t *)PTRIN(args->namelen);
8628451d0ddSKip Macy 	error = sys_getpeername(td, &bsd_args);
8635c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
864ca26842eSHajimu UMEMOTO 	if (error)
865ca26842eSHajimu UMEMOTO 		return (error);
866745aaef5SKonstantin Belousov 	error = linux_sa_put(PTRIN(args->addr));
867ca26842eSHajimu UMEMOTO 	if (error)
868ca26842eSHajimu UMEMOTO 		return (error);
869ca26842eSHajimu UMEMOTO 	return (0);
870c21dee17SSøren Schmidt }
871c21dee17SSøren Schmidt 
872a12b9b3dSDmitry Chagin int
873b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
874c21dee17SSøren Schmidt {
875ef04503dSPeter Wemm 	struct socketpair_args /* {
876c21dee17SSøren Schmidt 		int domain;
877c21dee17SSøren Schmidt 		int type;
878c21dee17SSøren Schmidt 		int protocol;
879c21dee17SSøren Schmidt 		int *rsv;
880ef04503dSPeter Wemm 	} */ bsd_args;
8814cf10e29SDmitry Chagin 	int error;
882c21dee17SSøren Schmidt 
883745aaef5SKonstantin Belousov 	bsd_args.domain = linux_to_bsd_domain(args->domain);
8841a52a4abSDmitry Chagin 	if (bsd_args.domain != PF_LOCAL)
8851a52a4abSDmitry Chagin 		return (EAFNOSUPPORT);
88639253cf9SDmitry Chagin 	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
88739253cf9SDmitry Chagin 	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
88839253cf9SDmitry Chagin 		return (EINVAL);
8894cf10e29SDmitry Chagin 	error = linux_set_socket_flags(args->type & ~LINUX_SOCK_TYPE_MASK,
8904cf10e29SDmitry Chagin 		&bsd_args.type);
8914cf10e29SDmitry Chagin 	if (error != 0)
8924cf10e29SDmitry Chagin 		return (error);
8931a52a4abSDmitry Chagin 	if (args->protocol != 0 && args->protocol != PF_UNIX)
8941a52a4abSDmitry Chagin 
8951a52a4abSDmitry Chagin 		/*
8961a52a4abSDmitry Chagin 		 * Use of PF_UNIX as protocol argument is not right,
8971a52a4abSDmitry Chagin 		 * but Linux does it.
8981a52a4abSDmitry Chagin 		 * Do not map PF_UNIX as its Linux value is identical
8991a52a4abSDmitry Chagin 		 * to FreeBSD one.
9001a52a4abSDmitry Chagin 		 */
9011a52a4abSDmitry Chagin 		return (EPROTONOSUPPORT);
90240092d93SDmitry Chagin 	else
9031a52a4abSDmitry Chagin 		bsd_args.protocol = 0;
904745aaef5SKonstantin Belousov 	bsd_args.rsv = (int *)PTRIN(args->rsv);
9054cf10e29SDmitry Chagin 	return (sys_socketpair(td, &bsd_args));
906c21dee17SSøren Schmidt }
907c21dee17SSøren Schmidt 
908a12b9b3dSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
90901e0ffbaSAlexander Leidinger struct linux_send_args {
910c21dee17SSøren Schmidt 	int s;
9114af27623STim J. Robbins 	l_uintptr_t msg;
912c21dee17SSøren Schmidt 	int len;
913c21dee17SSøren Schmidt 	int flags;
914c21dee17SSøren Schmidt };
915c21dee17SSøren Schmidt 
91601e0ffbaSAlexander Leidinger static int
917b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
918c21dee17SSøren Schmidt {
91987d72a8fSPoul-Henning Kamp 	struct sendto_args /* {
920c21dee17SSøren Schmidt 		int s;
921c21dee17SSøren Schmidt 		caddr_t buf;
922044af7c3SJonathan Mini 		int len;
923c21dee17SSøren Schmidt 		int flags;
92487d72a8fSPoul-Henning Kamp 		caddr_t to;
92587d72a8fSPoul-Henning Kamp 		int tolen;
926ef04503dSPeter Wemm 	} */ bsd_args;
927c21dee17SSøren Schmidt 
928745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
929745aaef5SKonstantin Belousov 	bsd_args.buf = (caddr_t)PTRIN(args->msg);
930745aaef5SKonstantin Belousov 	bsd_args.len = args->len;
931745aaef5SKonstantin Belousov 	bsd_args.flags = args->flags;
93287d72a8fSPoul-Henning Kamp 	bsd_args.to = NULL;
93387d72a8fSPoul-Henning Kamp 	bsd_args.tolen = 0;
9348451d0ddSKip Macy 	return sys_sendto(td, &bsd_args);
935c21dee17SSøren Schmidt }
936c21dee17SSøren Schmidt 
93701e0ffbaSAlexander Leidinger struct linux_recv_args {
938c21dee17SSøren Schmidt 	int s;
9394af27623STim J. Robbins 	l_uintptr_t msg;
940c21dee17SSøren Schmidt 	int len;
941c21dee17SSøren Schmidt 	int flags;
942c21dee17SSøren Schmidt };
943c21dee17SSøren Schmidt 
94401e0ffbaSAlexander Leidinger static int
945b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
946c21dee17SSøren Schmidt {
94787d72a8fSPoul-Henning Kamp 	struct recvfrom_args /* {
948c21dee17SSøren Schmidt 		int s;
949c21dee17SSøren Schmidt 		caddr_t buf;
950c21dee17SSøren Schmidt 		int len;
951c21dee17SSøren Schmidt 		int flags;
95287d72a8fSPoul-Henning Kamp 		struct sockaddr *from;
95387d72a8fSPoul-Henning Kamp 		socklen_t fromlenaddr;
954ef04503dSPeter Wemm 	} */ bsd_args;
955c21dee17SSøren Schmidt 
956745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
957745aaef5SKonstantin Belousov 	bsd_args.buf = (caddr_t)PTRIN(args->msg);
958745aaef5SKonstantin Belousov 	bsd_args.len = args->len;
9593980a435SDmitry Chagin 	bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
96087d72a8fSPoul-Henning Kamp 	bsd_args.from = NULL;
96187d72a8fSPoul-Henning Kamp 	bsd_args.fromlenaddr = 0;
9628451d0ddSKip Macy 	return (sys_recvfrom(td, &bsd_args));
963c21dee17SSøren Schmidt }
964a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
965c21dee17SSøren Schmidt 
966a12b9b3dSDmitry Chagin int
967b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
968c21dee17SSøren Schmidt {
9695a8a13e0SDavid Malone 	struct msghdr msg;
9705a8a13e0SDavid Malone 	struct iovec aiov;
9715a8a13e0SDavid Malone 	int error;
972c21dee17SSøren Schmidt 
973745aaef5SKonstantin Belousov 	if (linux_check_hdrincl(td, args->s) == 0)
974f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
975745aaef5SKonstantin Belousov 		return (linux_sendto_hdrincl(td, args));
976f2477ae1SMike Smith 
977745aaef5SKonstantin Belousov 	msg.msg_name = PTRIN(args->to);
978745aaef5SKonstantin Belousov 	msg.msg_namelen = args->tolen;
9795a8a13e0SDavid Malone 	msg.msg_iov = &aiov;
9805a8a13e0SDavid Malone 	msg.msg_iovlen = 1;
9815a8a13e0SDavid Malone 	msg.msg_control = NULL;
9825a8a13e0SDavid Malone 	msg.msg_flags = 0;
983745aaef5SKonstantin Belousov 	aiov.iov_base = PTRIN(args->msg);
984745aaef5SKonstantin Belousov 	aiov.iov_len = args->len;
98574f5d680SKonstantin Belousov 	error = linux_sendit(td, args->s, &msg, args->flags, NULL,
98674f5d680SKonstantin Belousov 	    UIO_USERSPACE);
9875a8a13e0SDavid Malone 	return (error);
988c21dee17SSøren Schmidt }
989c21dee17SSøren Schmidt 
990a12b9b3dSDmitry Chagin int
991b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
992c21dee17SSøren Schmidt {
9939599b0ecSDmitry Chagin 	struct msghdr msg;
9949599b0ecSDmitry Chagin 	struct iovec aiov;
995c21dee17SSøren Schmidt 	int error;
996c21dee17SSøren Schmidt 
9979599b0ecSDmitry Chagin 	if (PTRIN(args->fromlen) != NULL) {
9989599b0ecSDmitry Chagin 		error = copyin(PTRIN(args->fromlen), &msg.msg_namelen,
9999599b0ecSDmitry Chagin 		    sizeof(msg.msg_namelen));
10009599b0ecSDmitry Chagin 		if (error != 0)
10013f3a4815SMarcel Moolenaar 			return (error);
10023f3a4815SMarcel Moolenaar 
10039599b0ecSDmitry Chagin 		error = linux_to_bsd_sockaddr((struct sockaddr *)PTRIN(args->from),
10049599b0ecSDmitry Chagin 		    msg.msg_namelen);
10059599b0ecSDmitry Chagin 		if (error != 0)
1006ca26842eSHajimu UMEMOTO 			return (error);
10079599b0ecSDmitry Chagin 	} else
10089599b0ecSDmitry Chagin 		msg.msg_namelen = 0;
10099599b0ecSDmitry Chagin 
10109599b0ecSDmitry Chagin 	msg.msg_name = (struct sockaddr * __restrict)PTRIN(args->from);
10119599b0ecSDmitry Chagin 	msg.msg_iov = &aiov;
10129599b0ecSDmitry Chagin 	msg.msg_iovlen = 1;
10139599b0ecSDmitry Chagin 	aiov.iov_base = PTRIN(args->buf);
10149599b0ecSDmitry Chagin 	aiov.iov_len = args->len;
10159599b0ecSDmitry Chagin 	msg.msg_control = 0;
10169599b0ecSDmitry Chagin 	msg.msg_flags = linux_to_bsd_msg_flags(args->flags);
10179599b0ecSDmitry Chagin 
10189599b0ecSDmitry Chagin 	error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, NULL);
10199599b0ecSDmitry Chagin 	if (error != 0)
10209599b0ecSDmitry Chagin 		return (error);
10219599b0ecSDmitry Chagin 
10229599b0ecSDmitry Chagin 	if (PTRIN(args->from) != NULL) {
10239599b0ecSDmitry Chagin 		error = bsd_to_linux_sockaddr((struct sockaddr *)
10249599b0ecSDmitry Chagin 		    PTRIN(args->from));
10259599b0ecSDmitry Chagin 		if (error != 0)
10269599b0ecSDmitry Chagin 			return (error);
10279599b0ecSDmitry Chagin 
10284af27623STim J. Robbins 		error = linux_sa_put((struct osockaddr *)
1029745aaef5SKonstantin Belousov 		    PTRIN(args->from));
1030ca26842eSHajimu UMEMOTO 	}
10319599b0ecSDmitry Chagin 
10329599b0ecSDmitry Chagin 	if (PTRIN(args->fromlen) != NULL)
10339599b0ecSDmitry Chagin 		error = copyout(&msg.msg_namelen, PTRIN(args->fromlen),
10349599b0ecSDmitry Chagin 		    sizeof(msg.msg_namelen));
10359599b0ecSDmitry Chagin 
10369599b0ecSDmitry Chagin 	return (error);
1037ca26842eSHajimu UMEMOTO }
1038ca26842eSHajimu UMEMOTO 
1039e1ff74c0SDmitry Chagin static int
1040e1ff74c0SDmitry Chagin linux_sendmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
1041e1ff74c0SDmitry Chagin     l_uint flags)
1042ca26842eSHajimu UMEMOTO {
104374f5d680SKonstantin Belousov 	struct cmsghdr *cmsg;
1044605da56bSAndriy Gapon 	struct cmsgcred cmcred;
104574f5d680SKonstantin Belousov 	struct mbuf *control;
1046ca26842eSHajimu UMEMOTO 	struct msghdr msg;
104774f5d680SKonstantin Belousov 	struct l_cmsghdr linux_cmsg;
104874f5d680SKonstantin Belousov 	struct l_cmsghdr *ptr_cmsg;
104974f5d680SKonstantin Belousov 	struct l_msghdr linux_msg;
1050552afd9cSPoul-Henning Kamp 	struct iovec *iov;
105174f5d680SKonstantin Belousov 	socklen_t datalen;
1052605da56bSAndriy Gapon 	struct sockaddr *sa;
1053605da56bSAndriy Gapon 	sa_family_t sa_family;
105474f5d680SKonstantin Belousov 	void *data;
1055ca26842eSHajimu UMEMOTO 	int error;
1056ca26842eSHajimu UMEMOTO 
1057e1ff74c0SDmitry Chagin 	error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
1058e1ff74c0SDmitry Chagin 	if (error != 0)
105974f5d680SKonstantin Belousov 		return (error);
1060d72a6158SRobert Watson 
1061d72a6158SRobert Watson 	/*
1062d72a6158SRobert Watson 	 * Some Linux applications (ping) define a non-NULL control data
1063d72a6158SRobert Watson 	 * pointer, but a msg_controllen of 0, which is not allowed in the
1064d72a6158SRobert Watson 	 * FreeBSD system call interface.  NULL the msg_control pointer in
1065d72a6158SRobert Watson 	 * order to handle this case.  This should be checked, but allows the
1066d72a6158SRobert Watson 	 * Linux ping to work.
1067d72a6158SRobert Watson 	 */
1068605da56bSAndriy Gapon 	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
1069605da56bSAndriy Gapon 		linux_msg.msg_control = PTROUT(NULL);
1070605da56bSAndriy Gapon 
1071605da56bSAndriy Gapon 	error = linux_to_bsd_msghdr(&msg, &linux_msg);
1072e1ff74c0SDmitry Chagin 	if (error != 0)
1073605da56bSAndriy Gapon 		return (error);
107474f5d680SKonstantin Belousov 
107574f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32
107674f5d680SKonstantin Belousov 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
107774f5d680SKonstantin Belousov 	    &iov, EMSGSIZE);
107874f5d680SKonstantin Belousov #else
1079552afd9cSPoul-Henning Kamp 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
108074f5d680SKonstantin Belousov #endif
1081e1ff74c0SDmitry Chagin 	if (error != 0)
1082552afd9cSPoul-Henning Kamp 		return (error);
108374f5d680SKonstantin Belousov 
1084605da56bSAndriy Gapon 	control = NULL;
1085605da56bSAndriy Gapon 	cmsg = NULL;
1086605da56bSAndriy Gapon 
1087605da56bSAndriy Gapon 	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
1088e1ff74c0SDmitry Chagin 		error = kern_getsockname(td, s, &sa, &datalen);
1089e1ff74c0SDmitry Chagin 		if (error != 0)
1090605da56bSAndriy Gapon 			goto bad;
1091605da56bSAndriy Gapon 		sa_family = sa->sa_family;
1092605da56bSAndriy Gapon 		free(sa, M_SONAME);
1093605da56bSAndriy Gapon 
109474f5d680SKonstantin Belousov 		error = ENOBUFS;
1095e0d3ea8cSDmitry Chagin 		cmsg = malloc(CMSG_HDRSZ, M_LINUX, M_WAITOK|M_ZERO);
1096eb1b1807SGleb Smirnoff 		control = m_get(M_WAITOK, MT_CONTROL);
109774f5d680SKonstantin Belousov 
109874f5d680SKonstantin Belousov 		do {
109974f5d680SKonstantin Belousov 			error = copyin(ptr_cmsg, &linux_cmsg,
110074f5d680SKonstantin Belousov 			    sizeof(struct l_cmsghdr));
1101e1ff74c0SDmitry Chagin 			if (error != 0)
110274f5d680SKonstantin Belousov 				goto bad;
110374f5d680SKonstantin Belousov 
110474f5d680SKonstantin Belousov 			error = EINVAL;
110574f5d680SKonstantin Belousov 			if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr))
110674f5d680SKonstantin Belousov 				goto bad;
110774f5d680SKonstantin Belousov 
110874f5d680SKonstantin Belousov 			/*
1109605da56bSAndriy Gapon 			 * Now we support only SCM_RIGHTS and SCM_CRED,
1110605da56bSAndriy Gapon 			 * so return EINVAL in any other cmsg_type
111174f5d680SKonstantin Belousov 			 */
1112605da56bSAndriy Gapon 			cmsg->cmsg_type =
1113605da56bSAndriy Gapon 			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
111474f5d680SKonstantin Belousov 			cmsg->cmsg_level =
111574f5d680SKonstantin Belousov 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
1116605da56bSAndriy Gapon 			if (cmsg->cmsg_type == -1
1117605da56bSAndriy Gapon 			    || cmsg->cmsg_level != SOL_SOCKET)
1118605da56bSAndriy Gapon 				goto bad;
111974f5d680SKonstantin Belousov 
1120605da56bSAndriy Gapon 			/*
1121605da56bSAndriy Gapon 			 * Some applications (e.g. pulseaudio) attempt to
1122605da56bSAndriy Gapon 			 * send ancillary data even if the underlying protocol
1123605da56bSAndriy Gapon 			 * doesn't support it which is not allowed in the
1124605da56bSAndriy Gapon 			 * FreeBSD system call interface.
1125605da56bSAndriy Gapon 			 */
1126605da56bSAndriy Gapon 			if (sa_family != AF_UNIX)
1127605da56bSAndriy Gapon 				continue;
1128605da56bSAndriy Gapon 
112974f5d680SKonstantin Belousov 			data = LINUX_CMSG_DATA(ptr_cmsg);
1130605da56bSAndriy Gapon 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
1131605da56bSAndriy Gapon 
1132605da56bSAndriy Gapon 			switch (cmsg->cmsg_type)
1133605da56bSAndriy Gapon 			{
1134605da56bSAndriy Gapon 			case SCM_RIGHTS:
1135605da56bSAndriy Gapon 				break;
1136605da56bSAndriy Gapon 
1137605da56bSAndriy Gapon 			case SCM_CREDS:
1138605da56bSAndriy Gapon 				data = &cmcred;
1139605da56bSAndriy Gapon 				datalen = sizeof(cmcred);
1140605da56bSAndriy Gapon 
1141605da56bSAndriy Gapon 				/*
1142605da56bSAndriy Gapon 				 * The lower levels will fill in the structure
1143605da56bSAndriy Gapon 				 */
1144605da56bSAndriy Gapon 				bzero(data, datalen);
1145605da56bSAndriy Gapon 				break;
1146605da56bSAndriy Gapon 			}
1147605da56bSAndriy Gapon 
1148605da56bSAndriy Gapon 			cmsg->cmsg_len = CMSG_LEN(datalen);
114974f5d680SKonstantin Belousov 
115074f5d680SKonstantin Belousov 			error = ENOBUFS;
115174f5d680SKonstantin Belousov 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg))
115274f5d680SKonstantin Belousov 				goto bad;
115374f5d680SKonstantin Belousov 			if (!m_append(control, datalen, (c_caddr_t)data))
115474f5d680SKonstantin Belousov 				goto bad;
1155605da56bSAndriy Gapon 		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
1156605da56bSAndriy Gapon 
1157605da56bSAndriy Gapon 		if (m_length(control, NULL) == 0) {
1158605da56bSAndriy Gapon 			m_freem(control);
115974f5d680SKonstantin Belousov 			control = NULL;
1160605da56bSAndriy Gapon 		}
116174f5d680SKonstantin Belousov 	}
116274f5d680SKonstantin Belousov 
11635a8a13e0SDavid Malone 	msg.msg_iov = iov;
11645a8a13e0SDavid Malone 	msg.msg_flags = 0;
1165e1ff74c0SDmitry Chagin 	error = linux_sendit(td, s, &msg, flags, control, UIO_USERSPACE);
116674f5d680SKonstantin Belousov 
116774f5d680SKonstantin Belousov bad:
11684f65e9cfSDmitry Chagin 	m_freem(control);
1169552afd9cSPoul-Henning Kamp 	free(iov, M_IOV);
117074f5d680SKonstantin Belousov 	if (cmsg)
1171e0d3ea8cSDmitry Chagin 		free(cmsg, M_LINUX);
1172ca26842eSHajimu UMEMOTO 	return (error);
1173c21dee17SSøren Schmidt }
1174c21dee17SSøren Schmidt 
1175a12b9b3dSDmitry Chagin int
1176e1ff74c0SDmitry Chagin linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1177e1ff74c0SDmitry Chagin {
1178e1ff74c0SDmitry Chagin 
1179e1ff74c0SDmitry Chagin 	return (linux_sendmsg_common(td, args->s, PTRIN(args->msg),
1180e1ff74c0SDmitry Chagin 	    args->flags));
1181e1ff74c0SDmitry Chagin }
1182e1ff74c0SDmitry Chagin 
1183e1ff74c0SDmitry Chagin int
1184e1ff74c0SDmitry Chagin linux_sendmmsg(struct thread *td, struct linux_sendmmsg_args *args)
1185e1ff74c0SDmitry Chagin {
1186e1ff74c0SDmitry Chagin 	struct l_mmsghdr *msg;
1187e1ff74c0SDmitry Chagin 	l_uint retval;
1188e1ff74c0SDmitry Chagin 	int error, datagrams;
1189e1ff74c0SDmitry Chagin 
1190e1ff74c0SDmitry Chagin 	if (args->vlen > UIO_MAXIOV)
1191e1ff74c0SDmitry Chagin 		args->vlen = UIO_MAXIOV;
1192e1ff74c0SDmitry Chagin 
1193e1ff74c0SDmitry Chagin 	msg = PTRIN(args->msg);
1194e1ff74c0SDmitry Chagin 	datagrams = 0;
1195e1ff74c0SDmitry Chagin 	while (datagrams < args->vlen) {
1196e1ff74c0SDmitry Chagin 		error = linux_sendmsg_common(td, args->s, &msg->msg_hdr,
1197e1ff74c0SDmitry Chagin 		    args->flags);
1198e1ff74c0SDmitry Chagin 		if (error != 0)
1199e1ff74c0SDmitry Chagin 			break;
1200e1ff74c0SDmitry Chagin 
1201e1ff74c0SDmitry Chagin 		retval = td->td_retval[0];
1202e1ff74c0SDmitry Chagin 		error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
1203e1ff74c0SDmitry Chagin 		if (error != 0)
1204e1ff74c0SDmitry Chagin 			break;
1205e1ff74c0SDmitry Chagin 		++msg;
1206e1ff74c0SDmitry Chagin 		++datagrams;
1207e1ff74c0SDmitry Chagin 	}
1208e1ff74c0SDmitry Chagin 	if (error == 0)
1209e1ff74c0SDmitry Chagin 		td->td_retval[0] = datagrams;
1210e1ff74c0SDmitry Chagin 	return (error);
1211e1ff74c0SDmitry Chagin }
1212e1ff74c0SDmitry Chagin 
1213e1ff74c0SDmitry Chagin static int
1214e1ff74c0SDmitry Chagin linux_recvmsg_common(struct thread *td, l_int s, struct l_msghdr *msghdr,
1215e1ff74c0SDmitry Chagin     l_uint flags, struct msghdr *msg)
121640dbba57SAssar Westerlund {
121774f5d680SKonstantin Belousov 	struct cmsghdr *cm;
1218605da56bSAndriy Gapon 	struct cmsgcred *cmcred;
121974f5d680SKonstantin Belousov 	struct l_cmsghdr *linux_cmsg = NULL;
1220605da56bSAndriy Gapon 	struct l_ucred linux_ucred;
1221605da56bSAndriy Gapon 	socklen_t datalen, outlen;
122274f5d680SKonstantin Belousov 	struct l_msghdr linux_msg;
122374f5d680SKonstantin Belousov 	struct iovec *iov, *uiov;
122474f5d680SKonstantin Belousov 	struct mbuf *control = NULL;
122574f5d680SKonstantin Belousov 	struct mbuf **controlp;
1226*bbf392d5SDmitry Chagin 	struct timeval *ftmvl;
1227*bbf392d5SDmitry Chagin 	l_timeval ltmvl;
122874f5d680SKonstantin Belousov 	caddr_t outbuf;
122974f5d680SKonstantin Belousov 	void *data;
12303a72bf04SDmitry Chagin 	int error, i, fd, fds, *fdp;
123140dbba57SAssar Westerlund 
1232e1ff74c0SDmitry Chagin 	error = copyin(msghdr, &linux_msg, sizeof(linux_msg));
1233e1ff74c0SDmitry Chagin 	if (error != 0)
1234ca26842eSHajimu UMEMOTO 		return (error);
1235ca26842eSHajimu UMEMOTO 
1236e1ff74c0SDmitry Chagin 	error = linux_to_bsd_msghdr(msg, &linux_msg);
1237e1ff74c0SDmitry Chagin 	if (error != 0)
123874f5d680SKonstantin Belousov 		return (error);
123974f5d680SKonstantin Belousov 
124074f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32
1241e1ff74c0SDmitry Chagin 	error = linux32_copyiniov(PTRIN(msg->msg_iov), msg->msg_iovlen,
124274f5d680SKonstantin Belousov 	    &iov, EMSGSIZE);
124374f5d680SKonstantin Belousov #else
1244e1ff74c0SDmitry Chagin 	error = copyiniov(msg->msg_iov, msg->msg_iovlen, &iov, EMSGSIZE);
124574f5d680SKonstantin Belousov #endif
1246e1ff74c0SDmitry Chagin 	if (error != 0)
124774f5d680SKonstantin Belousov 		return (error);
124874f5d680SKonstantin Belousov 
1249e1ff74c0SDmitry Chagin 	if (msg->msg_name) {
1250e1ff74c0SDmitry Chagin 		error = linux_to_bsd_sockaddr((struct sockaddr *)msg->msg_name,
1251e1ff74c0SDmitry Chagin 		    msg->msg_namelen);
1252e1ff74c0SDmitry Chagin 		if (error != 0)
125374f5d680SKonstantin Belousov 			goto bad;
125484b11cd8SMitsuru IWASAKI 	}
125584b11cd8SMitsuru IWASAKI 
1256e1ff74c0SDmitry Chagin 	uiov = msg->msg_iov;
1257e1ff74c0SDmitry Chagin 	msg->msg_iov = iov;
1258e1ff74c0SDmitry Chagin 	controlp = (msg->msg_control != NULL) ? &control : NULL;
1259e1ff74c0SDmitry Chagin 	error = kern_recvit(td, s, msg, UIO_USERSPACE, controlp);
1260e1ff74c0SDmitry Chagin 	msg->msg_iov = uiov;
1261e1ff74c0SDmitry Chagin 	if (error != 0)
126274f5d680SKonstantin Belousov 		goto bad;
126374f5d680SKonstantin Belousov 
1264e1ff74c0SDmitry Chagin 	error = bsd_to_linux_msghdr(msg, &linux_msg);
1265e1ff74c0SDmitry Chagin 	if (error != 0)
126674f5d680SKonstantin Belousov 		goto bad;
126774f5d680SKonstantin Belousov 
126874f5d680SKonstantin Belousov 	if (linux_msg.msg_name) {
126974f5d680SKonstantin Belousov 		error = bsd_to_linux_sockaddr((struct sockaddr *)
127074f5d680SKonstantin Belousov 		    PTRIN(linux_msg.msg_name));
1271e1ff74c0SDmitry Chagin 		if (error != 0)
127274f5d680SKonstantin Belousov 			goto bad;
127374f5d680SKonstantin Belousov 	}
127474f5d680SKonstantin Belousov 	if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
127574f5d680SKonstantin Belousov 		error = linux_sa_put(PTRIN(linux_msg.msg_name));
1276e1ff74c0SDmitry Chagin 		if (error != 0)
127774f5d680SKonstantin Belousov 			goto bad;
127874f5d680SKonstantin Belousov 	}
127974f5d680SKonstantin Belousov 
128074f5d680SKonstantin Belousov 	outbuf = PTRIN(linux_msg.msg_control);
128174f5d680SKonstantin Belousov 	outlen = 0;
1282605da56bSAndriy Gapon 
1283605da56bSAndriy Gapon 	if (control) {
1284e0d3ea8cSDmitry Chagin 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
1285605da56bSAndriy Gapon 
1286e1ff74c0SDmitry Chagin 		msg->msg_control = mtod(control, struct cmsghdr *);
1287e1ff74c0SDmitry Chagin 		msg->msg_controllen = control->m_len;
1288605da56bSAndriy Gapon 
1289e1ff74c0SDmitry Chagin 		cm = CMSG_FIRSTHDR(msg);
129074f5d680SKonstantin Belousov 
129174f5d680SKonstantin Belousov 		while (cm != NULL) {
1292605da56bSAndriy Gapon 			linux_cmsg->cmsg_type =
1293605da56bSAndriy Gapon 			    bsd_to_linux_cmsg_type(cm->cmsg_type);
1294605da56bSAndriy Gapon 			linux_cmsg->cmsg_level =
1295605da56bSAndriy Gapon 			    bsd_to_linux_sockopt_level(cm->cmsg_level);
1296605da56bSAndriy Gapon 			if (linux_cmsg->cmsg_type == -1
1297605da56bSAndriy Gapon 			    || cm->cmsg_level != SOL_SOCKET)
129874f5d680SKonstantin Belousov 			{
129974f5d680SKonstantin Belousov 				error = EINVAL;
130074f5d680SKonstantin Belousov 				goto bad;
130174f5d680SKonstantin Belousov 			}
1302605da56bSAndriy Gapon 
130374f5d680SKonstantin Belousov 			data = CMSG_DATA(cm);
130474f5d680SKonstantin Belousov 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
130574f5d680SKonstantin Belousov 
1306605da56bSAndriy Gapon 			switch (cm->cmsg_type)
13073a72bf04SDmitry Chagin 			{
1308605da56bSAndriy Gapon 			case SCM_RIGHTS:
1309e1ff74c0SDmitry Chagin 				if (flags & LINUX_MSG_CMSG_CLOEXEC) {
1310605da56bSAndriy Gapon 					fds = datalen / sizeof(int);
1311605da56bSAndriy Gapon 					fdp = data;
1312605da56bSAndriy Gapon 					for (i = 0; i < fds; i++) {
1313605da56bSAndriy Gapon 						fd = *fdp++;
1314605da56bSAndriy Gapon 						(void)kern_fcntl(td, fd,
1315605da56bSAndriy Gapon 						    F_SETFD, FD_CLOEXEC);
1316605da56bSAndriy Gapon 					}
1317605da56bSAndriy Gapon 				}
1318605da56bSAndriy Gapon 				break;
1319605da56bSAndriy Gapon 
1320605da56bSAndriy Gapon 			case SCM_CREDS:
1321605da56bSAndriy Gapon 				/*
1322605da56bSAndriy Gapon 				 * Currently LOCAL_CREDS is never in
1323605da56bSAndriy Gapon 				 * effect for Linux so no need to worry
1324605da56bSAndriy Gapon 				 * about sockcred
1325605da56bSAndriy Gapon 				 */
1326605da56bSAndriy Gapon 				if (datalen != sizeof(*cmcred)) {
1327605da56bSAndriy Gapon 					error = EMSGSIZE;
1328605da56bSAndriy Gapon 					goto bad;
1329605da56bSAndriy Gapon 				}
1330605da56bSAndriy Gapon 				cmcred = (struct cmsgcred *)data;
1331605da56bSAndriy Gapon 				bzero(&linux_ucred, sizeof(linux_ucred));
1332605da56bSAndriy Gapon 				linux_ucred.pid = cmcred->cmcred_pid;
1333605da56bSAndriy Gapon 				linux_ucred.uid = cmcred->cmcred_uid;
1334605da56bSAndriy Gapon 				linux_ucred.gid = cmcred->cmcred_gid;
1335605da56bSAndriy Gapon 				data = &linux_ucred;
1336605da56bSAndriy Gapon 				datalen = sizeof(linux_ucred);
1337605da56bSAndriy Gapon 				break;
1338*bbf392d5SDmitry Chagin 
1339*bbf392d5SDmitry Chagin 			case SCM_TIMESTAMP:
1340*bbf392d5SDmitry Chagin 				if (datalen != sizeof(struct timeval)) {
1341*bbf392d5SDmitry Chagin 					error = EMSGSIZE;
1342*bbf392d5SDmitry Chagin 					goto bad;
1343*bbf392d5SDmitry Chagin 				}
1344*bbf392d5SDmitry Chagin 				ftmvl = (struct timeval *)data;
1345*bbf392d5SDmitry Chagin 				ltmvl.tv_sec = ftmvl->tv_sec;
1346*bbf392d5SDmitry Chagin 				ltmvl.tv_usec = ftmvl->tv_usec;
1347*bbf392d5SDmitry Chagin 				data = &ltmvl;
1348*bbf392d5SDmitry Chagin 				datalen = sizeof(ltmvl);
1349*bbf392d5SDmitry Chagin 				break;
1350605da56bSAndriy Gapon 			}
1351605da56bSAndriy Gapon 
135274f5d680SKonstantin Belousov 			if (outlen + LINUX_CMSG_LEN(datalen) >
135374f5d680SKonstantin Belousov 			    linux_msg.msg_controllen) {
135474f5d680SKonstantin Belousov 				if (outlen == 0) {
135574f5d680SKonstantin Belousov 					error = EMSGSIZE;
135674f5d680SKonstantin Belousov 					goto bad;
135774f5d680SKonstantin Belousov 				} else {
13583a72bf04SDmitry Chagin 					linux_msg.msg_flags |=
13593a72bf04SDmitry Chagin 					    LINUX_MSG_CTRUNC;
136074f5d680SKonstantin Belousov 					goto out;
136174f5d680SKonstantin Belousov 				}
136274f5d680SKonstantin Belousov 			}
136374f5d680SKonstantin Belousov 
136474f5d680SKonstantin Belousov 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
136574f5d680SKonstantin Belousov 
136674f5d680SKonstantin Belousov 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
136774f5d680SKonstantin Belousov 			if (error)
136874f5d680SKonstantin Belousov 				goto bad;
136974f5d680SKonstantin Belousov 			outbuf += L_CMSG_HDRSZ;
137074f5d680SKonstantin Belousov 
137174f5d680SKonstantin Belousov 			error = copyout(data, outbuf, datalen);
137274f5d680SKonstantin Belousov 			if (error)
137374f5d680SKonstantin Belousov 				goto bad;
137474f5d680SKonstantin Belousov 
137574f5d680SKonstantin Belousov 			outbuf += LINUX_CMSG_ALIGN(datalen);
137674f5d680SKonstantin Belousov 			outlen += LINUX_CMSG_LEN(datalen);
137774f5d680SKonstantin Belousov 
1378e1ff74c0SDmitry Chagin 			cm = CMSG_NXTHDR(msg, cm);
137974f5d680SKonstantin Belousov 		}
138074f5d680SKonstantin Belousov 	}
138174f5d680SKonstantin Belousov 
138274f5d680SKonstantin Belousov out:
1383605da56bSAndriy Gapon 	linux_msg.msg_controllen = outlen;
1384e1ff74c0SDmitry Chagin 	error = copyout(&linux_msg, msghdr, sizeof(linux_msg));
138574f5d680SKonstantin Belousov 
138674f5d680SKonstantin Belousov bad:
138774f5d680SKonstantin Belousov 	free(iov, M_IOV);
138874f5d680SKonstantin Belousov 	m_freem(control);
1389e0d3ea8cSDmitry Chagin 	free(linux_cmsg, M_LINUX);
139074f5d680SKonstantin Belousov 
1391ca26842eSHajimu UMEMOTO 	return (error);
139240dbba57SAssar Westerlund }
139340dbba57SAssar Westerlund 
1394a12b9b3dSDmitry Chagin int
1395e1ff74c0SDmitry Chagin linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
1396e1ff74c0SDmitry Chagin {
1397e1ff74c0SDmitry Chagin 	struct msghdr bsd_msg;
1398e1ff74c0SDmitry Chagin 
1399e1ff74c0SDmitry Chagin 	return (linux_recvmsg_common(td, args->s, PTRIN(args->msg),
1400e1ff74c0SDmitry Chagin 	    args->flags, &bsd_msg));
1401e1ff74c0SDmitry Chagin }
1402e1ff74c0SDmitry Chagin 
1403e1ff74c0SDmitry Chagin int
1404e1ff74c0SDmitry Chagin linux_recvmmsg(struct thread *td, struct linux_recvmmsg_args *args)
1405e1ff74c0SDmitry Chagin {
1406e1ff74c0SDmitry Chagin 	struct l_mmsghdr *msg;
1407e1ff74c0SDmitry Chagin 	struct msghdr bsd_msg;
1408e1ff74c0SDmitry Chagin 	struct l_timespec lts;
1409e1ff74c0SDmitry Chagin 	struct timespec ts, tts;
1410e1ff74c0SDmitry Chagin 	l_uint retval;
1411e1ff74c0SDmitry Chagin 	int error, datagrams;
1412e1ff74c0SDmitry Chagin 
1413e1ff74c0SDmitry Chagin 	if (args->timeout) {
1414e1ff74c0SDmitry Chagin 		error = copyin(args->timeout, &lts, sizeof(struct l_timespec));
1415e1ff74c0SDmitry Chagin 		if (error != 0)
1416e1ff74c0SDmitry Chagin 			return (error);
1417e1ff74c0SDmitry Chagin 		error = linux_to_native_timespec(&ts, &lts);
1418e1ff74c0SDmitry Chagin 		if (error != 0)
1419e1ff74c0SDmitry Chagin 			return (error);
1420e1ff74c0SDmitry Chagin 		getnanotime(&tts);
1421e1ff74c0SDmitry Chagin 		timespecadd(&tts, &ts);
1422e1ff74c0SDmitry Chagin 	}
1423e1ff74c0SDmitry Chagin 
1424e1ff74c0SDmitry Chagin 	msg = PTRIN(args->msg);
1425e1ff74c0SDmitry Chagin 	datagrams = 0;
1426e1ff74c0SDmitry Chagin 	while (datagrams < args->vlen) {
1427e1ff74c0SDmitry Chagin 		error = linux_recvmsg_common(td, args->s, &msg->msg_hdr,
1428e1ff74c0SDmitry Chagin 		    args->flags & ~LINUX_MSG_WAITFORONE, &bsd_msg);
1429e1ff74c0SDmitry Chagin 		if (error != 0)
1430e1ff74c0SDmitry Chagin 			break;
1431e1ff74c0SDmitry Chagin 
1432e1ff74c0SDmitry Chagin 		retval = td->td_retval[0];
1433e1ff74c0SDmitry Chagin 		error = copyout(&retval, &msg->msg_len, sizeof(msg->msg_len));
1434e1ff74c0SDmitry Chagin 		if (error != 0)
1435e1ff74c0SDmitry Chagin 			break;
1436e1ff74c0SDmitry Chagin 		++msg;
1437e1ff74c0SDmitry Chagin 		++datagrams;
1438e1ff74c0SDmitry Chagin 
1439e1ff74c0SDmitry Chagin 		/*
1440e1ff74c0SDmitry Chagin 		 * MSG_WAITFORONE turns on MSG_DONTWAIT after one packet.
1441e1ff74c0SDmitry Chagin 		 */
1442e1ff74c0SDmitry Chagin 		if (args->flags & LINUX_MSG_WAITFORONE)
1443e1ff74c0SDmitry Chagin 			args->flags |= LINUX_MSG_DONTWAIT;
1444e1ff74c0SDmitry Chagin 
1445e1ff74c0SDmitry Chagin 		/*
1446e1ff74c0SDmitry Chagin 		 * See BUGS section of recvmmsg(2).
1447e1ff74c0SDmitry Chagin 		 */
1448e1ff74c0SDmitry Chagin 		if (args->timeout) {
1449e1ff74c0SDmitry Chagin 			getnanotime(&ts);
1450e1ff74c0SDmitry Chagin 			timespecsub(&ts, &tts);
1451e1ff74c0SDmitry Chagin 			if (!timespecisset(&ts) || ts.tv_sec > 0)
1452e1ff74c0SDmitry Chagin 				break;
1453e1ff74c0SDmitry Chagin 		}
1454e1ff74c0SDmitry Chagin 		/* Out of band data, return right away. */
1455e1ff74c0SDmitry Chagin 		if (bsd_msg.msg_flags & MSG_OOB)
1456e1ff74c0SDmitry Chagin 			break;
1457e1ff74c0SDmitry Chagin 	}
1458e1ff74c0SDmitry Chagin 	if (error == 0)
1459e1ff74c0SDmitry Chagin 		td->td_retval[0] = datagrams;
1460e1ff74c0SDmitry Chagin 	return (error);
1461e1ff74c0SDmitry Chagin }
1462e1ff74c0SDmitry Chagin 
1463e1ff74c0SDmitry Chagin int
1464b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1465c21dee17SSøren Schmidt {
1466ef04503dSPeter Wemm 	struct shutdown_args /* {
1467c21dee17SSøren Schmidt 		int s;
1468c21dee17SSøren Schmidt 		int how;
1469ef04503dSPeter Wemm 	} */ bsd_args;
1470c21dee17SSøren Schmidt 
1471745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1472745aaef5SKonstantin Belousov 	bsd_args.how = args->how;
14738451d0ddSKip Macy 	return (sys_shutdown(td, &bsd_args));
1474c21dee17SSøren Schmidt }
1475c21dee17SSøren Schmidt 
1476a12b9b3dSDmitry Chagin int
1477b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1478c21dee17SSøren Schmidt {
1479ef04503dSPeter Wemm 	struct setsockopt_args /* {
1480c21dee17SSøren Schmidt 		int s;
1481c21dee17SSøren Schmidt 		int level;
1482c21dee17SSøren Schmidt 		int name;
1483c21dee17SSøren Schmidt 		caddr_t val;
1484c21dee17SSøren Schmidt 		int valsize;
1485ef04503dSPeter Wemm 	} */ bsd_args;
148603cc95d2SDmitry Chagin 	l_timeval linux_tv;
148703cc95d2SDmitry Chagin 	struct timeval tv;
1488c21dee17SSøren Schmidt 	int error, name;
1489c21dee17SSøren Schmidt 
1490745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1491745aaef5SKonstantin Belousov 	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1492c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1493c21dee17SSøren Schmidt 	case SOL_SOCKET:
1494745aaef5SKonstantin Belousov 		name = linux_to_bsd_so_sockopt(args->optname);
149503cc95d2SDmitry Chagin 		switch (name) {
149603cc95d2SDmitry Chagin 		case SO_RCVTIMEO:
149703cc95d2SDmitry Chagin 			/* FALLTHROUGH */
149803cc95d2SDmitry Chagin 		case SO_SNDTIMEO:
149903cc95d2SDmitry Chagin 			error = copyin(PTRIN(args->optval), &linux_tv,
150003cc95d2SDmitry Chagin 			    sizeof(linux_tv));
150103cc95d2SDmitry Chagin 			if (error)
150203cc95d2SDmitry Chagin 				return (error);
150303cc95d2SDmitry Chagin 			tv.tv_sec = linux_tv.tv_sec;
150403cc95d2SDmitry Chagin 			tv.tv_usec = linux_tv.tv_usec;
150503cc95d2SDmitry Chagin 			return (kern_setsockopt(td, args->s, bsd_args.level,
150603cc95d2SDmitry Chagin 			    name, &tv, UIO_SYSSPACE, sizeof(tv)));
150703cc95d2SDmitry Chagin 			/* NOTREACHED */
150803cc95d2SDmitry Chagin 			break;
150903cc95d2SDmitry Chagin 		default:
151003cc95d2SDmitry Chagin 			break;
151103cc95d2SDmitry Chagin 		}
1512c21dee17SSøren Schmidt 		break;
1513c21dee17SSøren Schmidt 	case IPPROTO_IP:
1514745aaef5SKonstantin Belousov 		name = linux_to_bsd_ip_sockopt(args->optname);
1515c21dee17SSøren Schmidt 		break;
1516dad3b88aSMike Smith 	case IPPROTO_TCP:
1517fb709557SJohn Baldwin 		name = linux_to_bsd_tcp_sockopt(args->optname);
1518dad3b88aSMike Smith 		break;
1519c21dee17SSøren Schmidt 	default:
15203f3a4815SMarcel Moolenaar 		name = -1;
15213f3a4815SMarcel Moolenaar 		break;
1522c21dee17SSøren Schmidt 	}
1523c21dee17SSøren Schmidt 	if (name == -1)
1524d4b7423fSAlexander Leidinger 		return (ENOPROTOOPT);
15253f3a4815SMarcel Moolenaar 
1526c21dee17SSøren Schmidt 	bsd_args.name = name;
1527745aaef5SKonstantin Belousov 	bsd_args.val = PTRIN(args->optval);
1528745aaef5SKonstantin Belousov 	bsd_args.valsize = args->optlen;
15295c8919adSAlexander Leidinger 
15305c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
15315c8919adSAlexander Leidinger 		linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
15325c8919adSAlexander Leidinger 			bsd_args.valsize);
15338451d0ddSKip Macy 		error = sys_setsockopt(td, &bsd_args);
15345c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
15355c8919adSAlexander Leidinger 	} else
15368451d0ddSKip Macy 		error = sys_setsockopt(td, &bsd_args);
15375c8919adSAlexander Leidinger 
15385c8919adSAlexander Leidinger 	return (error);
1539c21dee17SSøren Schmidt }
1540c21dee17SSøren Schmidt 
1541a12b9b3dSDmitry Chagin int
1542b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1543c21dee17SSøren Schmidt {
1544ef04503dSPeter Wemm 	struct getsockopt_args /* {
1545c21dee17SSøren Schmidt 		int s;
1546c21dee17SSøren Schmidt 		int level;
1547c21dee17SSøren Schmidt 		int name;
1548c21dee17SSøren Schmidt 		caddr_t val;
1549c21dee17SSøren Schmidt 		int *avalsize;
1550ef04503dSPeter Wemm 	} */ bsd_args;
155103cc95d2SDmitry Chagin 	l_timeval linux_tv;
155203cc95d2SDmitry Chagin 	struct timeval tv;
1553d4dd69c4SDmitry Chagin 	socklen_t tv_len, xulen;
1554d4dd69c4SDmitry Chagin 	struct xucred xu;
1555d4dd69c4SDmitry Chagin 	struct l_ucred lxu;
1556c21dee17SSøren Schmidt 	int error, name;
1557c21dee17SSøren Schmidt 
1558745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1559745aaef5SKonstantin Belousov 	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1560c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1561c21dee17SSøren Schmidt 	case SOL_SOCKET:
1562745aaef5SKonstantin Belousov 		name = linux_to_bsd_so_sockopt(args->optname);
156303cc95d2SDmitry Chagin 		switch (name) {
156403cc95d2SDmitry Chagin 		case SO_RCVTIMEO:
156503cc95d2SDmitry Chagin 			/* FALLTHROUGH */
156603cc95d2SDmitry Chagin 		case SO_SNDTIMEO:
156703cc95d2SDmitry Chagin 			tv_len = sizeof(tv);
156803cc95d2SDmitry Chagin 			error = kern_getsockopt(td, args->s, bsd_args.level,
156903cc95d2SDmitry Chagin 			    name, &tv, UIO_SYSSPACE, &tv_len);
157003cc95d2SDmitry Chagin 			if (error)
157103cc95d2SDmitry Chagin 				return (error);
157203cc95d2SDmitry Chagin 			linux_tv.tv_sec = tv.tv_sec;
157303cc95d2SDmitry Chagin 			linux_tv.tv_usec = tv.tv_usec;
157403cc95d2SDmitry Chagin 			return (copyout(&linux_tv, PTRIN(args->optval),
157503cc95d2SDmitry Chagin 			    sizeof(linux_tv)));
157603cc95d2SDmitry Chagin 			/* NOTREACHED */
157703cc95d2SDmitry Chagin 			break;
1578d4dd69c4SDmitry Chagin 		case LOCAL_PEERCRED:
1579d4dd69c4SDmitry Chagin 			if (args->optlen != sizeof(lxu))
1580d4dd69c4SDmitry Chagin 				return (EINVAL);
1581d4dd69c4SDmitry Chagin 			xulen = sizeof(xu);
1582d4dd69c4SDmitry Chagin 			error = kern_getsockopt(td, args->s, bsd_args.level,
1583d4dd69c4SDmitry Chagin 			    name, &xu, UIO_SYSSPACE, &xulen);
1584d4dd69c4SDmitry Chagin 			if (error)
1585d4dd69c4SDmitry Chagin 				return (error);
1586d4dd69c4SDmitry Chagin 			/*
1587d4dd69c4SDmitry Chagin 			 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1588d4dd69c4SDmitry Chagin 			 */
1589d4dd69c4SDmitry Chagin 			lxu.pid = 0;
1590d4dd69c4SDmitry Chagin 			lxu.uid = xu.cr_uid;
1591d4dd69c4SDmitry Chagin 			lxu.gid = xu.cr_gid;
1592d4dd69c4SDmitry Chagin 			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
1593d4dd69c4SDmitry Chagin 			/* NOTREACHED */
1594d4dd69c4SDmitry Chagin 			break;
159503cc95d2SDmitry Chagin 		default:
159603cc95d2SDmitry Chagin 			break;
159703cc95d2SDmitry Chagin 		}
1598c21dee17SSøren Schmidt 		break;
1599c21dee17SSøren Schmidt 	case IPPROTO_IP:
1600745aaef5SKonstantin Belousov 		name = linux_to_bsd_ip_sockopt(args->optname);
1601c21dee17SSøren Schmidt 		break;
1602dad3b88aSMike Smith 	case IPPROTO_TCP:
1603fb709557SJohn Baldwin 		name = linux_to_bsd_tcp_sockopt(args->optname);
1604dad3b88aSMike Smith 		break;
1605c21dee17SSøren Schmidt 	default:
16063f3a4815SMarcel Moolenaar 		name = -1;
16073f3a4815SMarcel Moolenaar 		break;
1608c21dee17SSøren Schmidt 	}
1609c21dee17SSøren Schmidt 	if (name == -1)
16103f3a4815SMarcel Moolenaar 		return (EINVAL);
16113f3a4815SMarcel Moolenaar 
1612f2477ae1SMike Smith 	bsd_args.name = name;
1613745aaef5SKonstantin Belousov 	bsd_args.val = PTRIN(args->optval);
1614745aaef5SKonstantin Belousov 	bsd_args.avalsize = PTRIN(args->optlen);
16155c8919adSAlexander Leidinger 
16165c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
16178451d0ddSKip Macy 		error = sys_getsockopt(td, &bsd_args);
16185c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
16195c8919adSAlexander Leidinger 	} else
16208451d0ddSKip Macy 		error = sys_getsockopt(td, &bsd_args);
16215c8919adSAlexander Leidinger 
16225c8919adSAlexander Leidinger 	return (error);
1623c21dee17SSøren Schmidt }
1624c21dee17SSøren Schmidt 
16257f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
16267f8f1d7fSDmitry Chagin 
1627ea7b81d2SDmitry Chagin /* Argument list sizes for linux_socketcall */
1628ea7b81d2SDmitry Chagin 
1629ea7b81d2SDmitry Chagin #define LINUX_AL(x) ((x) * sizeof(l_ulong))
1630ea7b81d2SDmitry Chagin 
1631ea7b81d2SDmitry Chagin static const unsigned char lxs_args[] = {
1632ea7b81d2SDmitry Chagin 	LINUX_AL(0) /* unused*/,	LINUX_AL(3) /* socket */,
1633ea7b81d2SDmitry Chagin 	LINUX_AL(3) /* bind */,		LINUX_AL(3) /* connect */,
1634ea7b81d2SDmitry Chagin 	LINUX_AL(2) /* listen */,	LINUX_AL(3) /* accept */,
1635ea7b81d2SDmitry Chagin 	LINUX_AL(3) /* getsockname */,	LINUX_AL(3) /* getpeername */,
1636ea7b81d2SDmitry Chagin 	LINUX_AL(4) /* socketpair */,	LINUX_AL(4) /* send */,
1637ea7b81d2SDmitry Chagin 	LINUX_AL(4) /* recv */,		LINUX_AL(6) /* sendto */,
1638ea7b81d2SDmitry Chagin 	LINUX_AL(6) /* recvfrom */,	LINUX_AL(2) /* shutdown */,
1639ea7b81d2SDmitry Chagin 	LINUX_AL(5) /* setsockopt */,	LINUX_AL(5) /* getsockopt */,
1640f8cd0af2SDmitry Chagin 	LINUX_AL(3) /* sendmsg */,	LINUX_AL(3) /* recvmsg */,
1641e1ff74c0SDmitry Chagin 	LINUX_AL(4) /* accept4 */,	LINUX_AL(5) /* recvmmsg */,
1642e1ff74c0SDmitry Chagin 	LINUX_AL(4) /* sendmmsg */
1643ea7b81d2SDmitry Chagin };
1644ea7b81d2SDmitry Chagin 
1645ea7b81d2SDmitry Chagin #define	LINUX_AL_SIZE	sizeof(lxs_args) / sizeof(lxs_args[0]) - 1
1646ea7b81d2SDmitry Chagin 
1647c21dee17SSøren Schmidt int
1648b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1649c21dee17SSøren Schmidt {
1650ea7b81d2SDmitry Chagin 	l_ulong a[6];
1651ea7b81d2SDmitry Chagin 	void *arg;
1652ea7b81d2SDmitry Chagin 	int error;
16533f3a4815SMarcel Moolenaar 
1654ea7b81d2SDmitry Chagin 	if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE)
1655ea7b81d2SDmitry Chagin 		return (EINVAL);
1656ea7b81d2SDmitry Chagin 	error = copyin(PTRIN(args->args), a, lxs_args[args->what]);
1657ea7b81d2SDmitry Chagin 	if (error)
1658ea7b81d2SDmitry Chagin 		return (error);
1659ea7b81d2SDmitry Chagin 
1660ea7b81d2SDmitry Chagin 	arg = a;
1661c21dee17SSøren Schmidt 	switch (args->what) {
1662c21dee17SSøren Schmidt 	case LINUX_SOCKET:
1663b40ce416SJulian Elischer 		return (linux_socket(td, arg));
1664c21dee17SSøren Schmidt 	case LINUX_BIND:
1665b40ce416SJulian Elischer 		return (linux_bind(td, arg));
1666c21dee17SSøren Schmidt 	case LINUX_CONNECT:
1667b40ce416SJulian Elischer 		return (linux_connect(td, arg));
1668c21dee17SSøren Schmidt 	case LINUX_LISTEN:
1669b40ce416SJulian Elischer 		return (linux_listen(td, arg));
1670c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
1671b40ce416SJulian Elischer 		return (linux_accept(td, arg));
1672c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
1673b40ce416SJulian Elischer 		return (linux_getsockname(td, arg));
1674c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
1675b40ce416SJulian Elischer 		return (linux_getpeername(td, arg));
1676c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
1677b40ce416SJulian Elischer 		return (linux_socketpair(td, arg));
1678c21dee17SSøren Schmidt 	case LINUX_SEND:
1679b40ce416SJulian Elischer 		return (linux_send(td, arg));
1680c21dee17SSøren Schmidt 	case LINUX_RECV:
1681b40ce416SJulian Elischer 		return (linux_recv(td, arg));
1682c21dee17SSøren Schmidt 	case LINUX_SENDTO:
1683b40ce416SJulian Elischer 		return (linux_sendto(td, arg));
1684c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
1685b40ce416SJulian Elischer 		return (linux_recvfrom(td, arg));
1686c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
1687b40ce416SJulian Elischer 		return (linux_shutdown(td, arg));
1688c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
1689b40ce416SJulian Elischer 		return (linux_setsockopt(td, arg));
1690c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
1691b40ce416SJulian Elischer 		return (linux_getsockopt(td, arg));
1692e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
1693ca26842eSHajimu UMEMOTO 		return (linux_sendmsg(td, arg));
1694e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
1695b40ce416SJulian Elischer 		return (linux_recvmsg(td, arg));
1696f8cd0af2SDmitry Chagin 	case LINUX_ACCEPT4:
1697f8cd0af2SDmitry Chagin 		return (linux_accept4(td, arg));
1698e1ff74c0SDmitry Chagin 	case LINUX_RECVMMSG:
1699e1ff74c0SDmitry Chagin 		return (linux_recvmmsg(td, arg));
1700e1ff74c0SDmitry Chagin 	case LINUX_SENDMMSG:
1701e1ff74c0SDmitry Chagin 		return (linux_sendmmsg(td, arg));
1702c21dee17SSøren Schmidt 	}
17033f3a4815SMarcel Moolenaar 
17043f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
17053f3a4815SMarcel Moolenaar 	return (ENOSYS);
1706c21dee17SSøren Schmidt }
1707a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1708