xref: /freebsd/sys/compat/linux/linux_socket.c (revision e0d3ea8c655d56fd364dba6d91dec8d3e443cb80)
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
7340dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
74ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
75c21dee17SSøren Schmidt 
76ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int);
77ca26842eSHajimu UMEMOTO 
784730796cSBill Fenner /*
79ca26842eSHajimu UMEMOTO  * Reads a linux sockaddr and does any necessary translation.
80ca26842eSHajimu UMEMOTO  * Linux sockaddrs don't have a length field, only a family.
81ca26842eSHajimu UMEMOTO  * Copy the osockaddr structure pointed to by osa to kernel, adjust
82ca26842eSHajimu UMEMOTO  * family and convert to sockaddr.
83ca26842eSHajimu UMEMOTO  */
84ca26842eSHajimu UMEMOTO static int
85b6f96462SJung-uk Kim linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int salen)
86ca26842eSHajimu UMEMOTO {
87ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
88ca26842eSHajimu UMEMOTO 	struct osockaddr *kosa;
89ca26842eSHajimu UMEMOTO #ifdef INET6
90ca26842eSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
913106d670SJung-uk Kim 	int oldv6size;
92ca26842eSHajimu UMEMOTO #endif
93c02637c7SJung-uk Kim 	char *name;
94b6f96462SJung-uk Kim 	int bdom, error, hdrlen, namelen;
95ca26842eSHajimu UMEMOTO 
96b6f96462SJung-uk Kim 	if (salen < 2 || salen > UCHAR_MAX || !osa)
97ca26842eSHajimu UMEMOTO 		return (EINVAL);
98ca26842eSHajimu UMEMOTO 
99ca26842eSHajimu UMEMOTO #ifdef INET6
100ca26842eSHajimu UMEMOTO 	oldv6size = 0;
101ca26842eSHajimu UMEMOTO 	/*
102ca26842eSHajimu UMEMOTO 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
103ca26842eSHajimu UMEMOTO 	 * if it's a v4-mapped address, so reserve the proper space
104ca26842eSHajimu UMEMOTO 	 * for it.
105ca26842eSHajimu UMEMOTO 	 */
106b6f96462SJung-uk Kim 	if (salen == sizeof(struct sockaddr_in6) - sizeof(uint32_t)) {
107b6f96462SJung-uk Kim 		salen += sizeof(uint32_t);
108ca26842eSHajimu UMEMOTO 		oldv6size = 1;
109ca26842eSHajimu UMEMOTO 	}
110ca26842eSHajimu UMEMOTO #endif
111ca26842eSHajimu UMEMOTO 
112b6f96462SJung-uk Kim 	kosa = malloc(salen, M_SONAME, M_WAITOK);
113ca26842eSHajimu UMEMOTO 
114b6f96462SJung-uk Kim 	if ((error = copyin(osa, kosa, salen)))
115ca26842eSHajimu UMEMOTO 		goto out;
116ca26842eSHajimu UMEMOTO 
117ca26842eSHajimu UMEMOTO 	bdom = linux_to_bsd_domain(kosa->sa_family);
118ca26842eSHajimu UMEMOTO 	if (bdom == -1) {
1195cb9c68cSXin LI 		error = EAFNOSUPPORT;
120ca26842eSHajimu UMEMOTO 		goto out;
121ca26842eSHajimu UMEMOTO 	}
122ca26842eSHajimu UMEMOTO 
123ca26842eSHajimu UMEMOTO #ifdef INET6
124ca26842eSHajimu UMEMOTO 	/*
125ca26842eSHajimu UMEMOTO 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
126ca26842eSHajimu UMEMOTO 	 * which lacks the scope id compared with RFC2553 one. If we detect
127ca26842eSHajimu UMEMOTO 	 * the situation, reject the address and write a message to system log.
128ca26842eSHajimu UMEMOTO 	 *
129ca26842eSHajimu UMEMOTO 	 * Still accept addresses for which the scope id is not used.
130ca26842eSHajimu UMEMOTO 	 */
131f05531a3SJung-uk Kim 	if (oldv6size) {
132f05531a3SJung-uk Kim 		if (bdom == AF_INET6) {
133ca26842eSHajimu UMEMOTO 			sin6 = (struct sockaddr_in6 *)kosa;
134ca26842eSHajimu UMEMOTO 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
135ca26842eSHajimu UMEMOTO 			    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
136ca26842eSHajimu UMEMOTO 			     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
137ca26842eSHajimu UMEMOTO 			     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
138ca26842eSHajimu UMEMOTO 			     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
139ca26842eSHajimu UMEMOTO 			     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
140ca26842eSHajimu UMEMOTO 				sin6->sin6_scope_id = 0;
141ca26842eSHajimu UMEMOTO 			} else {
142ca26842eSHajimu UMEMOTO 				log(LOG_DEBUG,
1433c616032SGleb Smirnoff 				    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
144ca26842eSHajimu UMEMOTO 				error = EINVAL;
145ca26842eSHajimu UMEMOTO 				goto out;
146ca26842eSHajimu UMEMOTO 			}
147ca26842eSHajimu UMEMOTO 		} else
148b6f96462SJung-uk Kim 			salen -= sizeof(uint32_t);
149f05531a3SJung-uk Kim 	}
150ca26842eSHajimu UMEMOTO #endif
1515cb9c68cSXin LI 	if (bdom == AF_INET) {
152b6f96462SJung-uk Kim 		if (salen < sizeof(struct sockaddr_in)) {
1535cb9c68cSXin LI 			error = EINVAL;
1545cb9c68cSXin LI 			goto out;
1555cb9c68cSXin LI 		}
156b6f96462SJung-uk Kim 		salen = sizeof(struct sockaddr_in);
1575cb9c68cSXin LI 	}
158ca26842eSHajimu UMEMOTO 
159b6f96462SJung-uk Kim 	if (bdom == AF_LOCAL && salen > sizeof(struct sockaddr_un)) {
160c15cdbf2SJung-uk Kim 		hdrlen = offsetof(struct sockaddr_un, sun_path);
161c02637c7SJung-uk Kim 		name = ((struct sockaddr_un *)kosa)->sun_path;
162c02637c7SJung-uk Kim 		if (*name == '\0') {
163c02637c7SJung-uk Kim 			/*
164c02637c7SJung-uk Kim 		 	 * Linux abstract namespace starts with a NULL byte.
165c02637c7SJung-uk Kim 			 * XXX We do not support abstract namespace yet.
166c02637c7SJung-uk Kim 			 */
167b6f96462SJung-uk Kim 			namelen = strnlen(name + 1, salen - hdrlen - 1) + 1;
168c02637c7SJung-uk Kim 		} else
169b6f96462SJung-uk Kim 			namelen = strnlen(name, salen - hdrlen);
170bf3a36ccSJung-uk Kim 		salen = hdrlen + namelen;
171bf3a36ccSJung-uk Kim 		if (salen > sizeof(struct sockaddr_un)) {
17243399111SJung-uk Kim 			error = ENAMETOOLONG;
1735da3eb94SColin Percival 			goto out;
1745da3eb94SColin Percival 		}
1755da3eb94SColin Percival 	}
1765da3eb94SColin Percival 
177ca26842eSHajimu UMEMOTO 	sa = (struct sockaddr *)kosa;
178ca26842eSHajimu UMEMOTO 	sa->sa_family = bdom;
179b6f96462SJung-uk Kim 	sa->sa_len = salen;
180ca26842eSHajimu UMEMOTO 
181ca26842eSHajimu UMEMOTO 	*sap = sa;
182ca26842eSHajimu UMEMOTO 	return (0);
183ca26842eSHajimu UMEMOTO 
184ca26842eSHajimu UMEMOTO out:
1850007f669SJung-uk Kim 	free(kosa, M_SONAME);
186ca26842eSHajimu UMEMOTO 	return (error);
187ca26842eSHajimu UMEMOTO }
188ca26842eSHajimu UMEMOTO 
189c21dee17SSøren Schmidt static int
190c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
191c21dee17SSøren Schmidt {
1923f3a4815SMarcel Moolenaar 
193c21dee17SSøren Schmidt 	switch (domain) {
194c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
1953f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
196c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
1973f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
198c21dee17SSøren Schmidt 	case LINUX_AF_INET:
1993f3a4815SMarcel Moolenaar 		return (AF_INET);
200ca26842eSHajimu UMEMOTO 	case LINUX_AF_INET6:
201ca26842eSHajimu UMEMOTO 		return (AF_INET6);
202c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
2033f3a4815SMarcel Moolenaar 		return (AF_CCITT);
204c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
2053f3a4815SMarcel Moolenaar 		return (AF_IPX);
206c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
2073f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
208c21dee17SSøren Schmidt 	}
2093f3a4815SMarcel Moolenaar 	return (-1);
210c21dee17SSøren Schmidt }
211c21dee17SSøren Schmidt 
212ca26842eSHajimu UMEMOTO static int
213ca26842eSHajimu UMEMOTO bsd_to_linux_domain(int domain)
214ca26842eSHajimu UMEMOTO {
215ca26842eSHajimu UMEMOTO 
216ca26842eSHajimu UMEMOTO 	switch (domain) {
217ca26842eSHajimu UMEMOTO 	case AF_UNSPEC:
218ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNSPEC);
219ca26842eSHajimu UMEMOTO 	case AF_LOCAL:
220ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNIX);
221ca26842eSHajimu UMEMOTO 	case AF_INET:
222ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET);
223ca26842eSHajimu UMEMOTO 	case AF_INET6:
224ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET6);
225ca26842eSHajimu UMEMOTO 	case AF_CCITT:
226ca26842eSHajimu UMEMOTO 		return (LINUX_AF_AX25);
227ca26842eSHajimu UMEMOTO 	case AF_IPX:
228ca26842eSHajimu UMEMOTO 		return (LINUX_AF_IPX);
229ca26842eSHajimu UMEMOTO 	case AF_APPLETALK:
230ca26842eSHajimu UMEMOTO 		return (LINUX_AF_APPLETALK);
231ca26842eSHajimu UMEMOTO 	}
232ca26842eSHajimu UMEMOTO 	return (-1);
233ca26842eSHajimu UMEMOTO }
234ca26842eSHajimu UMEMOTO 
235c21dee17SSøren Schmidt static int
236c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
237c21dee17SSøren Schmidt {
2383f3a4815SMarcel Moolenaar 
239c21dee17SSøren Schmidt 	switch (level) {
240c21dee17SSøren Schmidt 	case LINUX_SOL_SOCKET:
2413f3a4815SMarcel Moolenaar 		return (SOL_SOCKET);
242c21dee17SSøren Schmidt 	}
2433f3a4815SMarcel Moolenaar 	return (level);
244c21dee17SSøren Schmidt }
245c21dee17SSøren Schmidt 
2463f3a4815SMarcel Moolenaar static int
24784b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level)
24884b11cd8SMitsuru IWASAKI {
24984b11cd8SMitsuru IWASAKI 
25084b11cd8SMitsuru IWASAKI 	switch (level) {
25184b11cd8SMitsuru IWASAKI 	case SOL_SOCKET:
25284b11cd8SMitsuru IWASAKI 		return (LINUX_SOL_SOCKET);
25384b11cd8SMitsuru IWASAKI 	}
25484b11cd8SMitsuru IWASAKI 	return (level);
25584b11cd8SMitsuru IWASAKI }
25684b11cd8SMitsuru IWASAKI 
25784b11cd8SMitsuru IWASAKI static int
2583f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
259c21dee17SSøren Schmidt {
2603f3a4815SMarcel Moolenaar 
261c21dee17SSøren Schmidt 	switch (opt) {
262c21dee17SSøren Schmidt 	case LINUX_IP_TOS:
2633f3a4815SMarcel Moolenaar 		return (IP_TOS);
264c21dee17SSøren Schmidt 	case LINUX_IP_TTL:
2653f3a4815SMarcel Moolenaar 		return (IP_TTL);
26666ff6a3cSBill Fenner 	case LINUX_IP_OPTIONS:
2673f3a4815SMarcel Moolenaar 		return (IP_OPTIONS);
26866ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_IF:
2693f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_IF);
27066ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_TTL:
2713f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_TTL);
27266ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_LOOP:
2733f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_LOOP);
27466ff6a3cSBill Fenner 	case LINUX_IP_ADD_MEMBERSHIP:
2753f3a4815SMarcel Moolenaar 		return (IP_ADD_MEMBERSHIP);
27666ff6a3cSBill Fenner 	case LINUX_IP_DROP_MEMBERSHIP:
2773f3a4815SMarcel Moolenaar 		return (IP_DROP_MEMBERSHIP);
27866ff6a3cSBill Fenner 	case LINUX_IP_HDRINCL:
2793f3a4815SMarcel Moolenaar 		return (IP_HDRINCL);
280c21dee17SSøren Schmidt 	}
2813f3a4815SMarcel Moolenaar 	return (-1);
282c21dee17SSøren Schmidt }
283c21dee17SSøren Schmidt 
284c21dee17SSøren Schmidt static int
285c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
286c21dee17SSøren Schmidt {
2873f3a4815SMarcel Moolenaar 
288c21dee17SSøren Schmidt 	switch (opt) {
289c21dee17SSøren Schmidt 	case LINUX_SO_DEBUG:
2903f3a4815SMarcel Moolenaar 		return (SO_DEBUG);
291c21dee17SSøren Schmidt 	case LINUX_SO_REUSEADDR:
2923f3a4815SMarcel Moolenaar 		return (SO_REUSEADDR);
293c21dee17SSøren Schmidt 	case LINUX_SO_TYPE:
2943f3a4815SMarcel Moolenaar 		return (SO_TYPE);
295c21dee17SSøren Schmidt 	case LINUX_SO_ERROR:
2963f3a4815SMarcel Moolenaar 		return (SO_ERROR);
297c21dee17SSøren Schmidt 	case LINUX_SO_DONTROUTE:
2983f3a4815SMarcel Moolenaar 		return (SO_DONTROUTE);
299c21dee17SSøren Schmidt 	case LINUX_SO_BROADCAST:
3003f3a4815SMarcel Moolenaar 		return (SO_BROADCAST);
301c21dee17SSøren Schmidt 	case LINUX_SO_SNDBUF:
3023f3a4815SMarcel Moolenaar 		return (SO_SNDBUF);
303c21dee17SSøren Schmidt 	case LINUX_SO_RCVBUF:
3043f3a4815SMarcel Moolenaar 		return (SO_RCVBUF);
305c21dee17SSøren Schmidt 	case LINUX_SO_KEEPALIVE:
3063f3a4815SMarcel Moolenaar 		return (SO_KEEPALIVE);
307c21dee17SSøren Schmidt 	case LINUX_SO_OOBINLINE:
3083f3a4815SMarcel Moolenaar 		return (SO_OOBINLINE);
309c21dee17SSøren Schmidt 	case LINUX_SO_LINGER:
3103f3a4815SMarcel Moolenaar 		return (SO_LINGER);
311d0b2365eSKonstantin Belousov 	case LINUX_SO_PEERCRED:
312d0b2365eSKonstantin Belousov 		return (LOCAL_PEERCRED);
313d0b2365eSKonstantin Belousov 	case LINUX_SO_RCVLOWAT:
314d0b2365eSKonstantin Belousov 		return (SO_RCVLOWAT);
315d0b2365eSKonstantin Belousov 	case LINUX_SO_SNDLOWAT:
316d0b2365eSKonstantin Belousov 		return (SO_SNDLOWAT);
317d0b2365eSKonstantin Belousov 	case LINUX_SO_RCVTIMEO:
318d0b2365eSKonstantin Belousov 		return (SO_RCVTIMEO);
319d0b2365eSKonstantin Belousov 	case LINUX_SO_SNDTIMEO:
320d0b2365eSKonstantin Belousov 		return (SO_SNDTIMEO);
321d0b2365eSKonstantin Belousov 	case LINUX_SO_TIMESTAMP:
322d0b2365eSKonstantin Belousov 		return (SO_TIMESTAMP);
323d0b2365eSKonstantin Belousov 	case LINUX_SO_ACCEPTCONN:
324d0b2365eSKonstantin Belousov 		return (SO_ACCEPTCONN);
325c21dee17SSøren Schmidt 	}
3263f3a4815SMarcel Moolenaar 	return (-1);
327c21dee17SSøren Schmidt }
328c21dee17SSøren Schmidt 
32940dbba57SAssar Westerlund static int
330fb709557SJohn Baldwin linux_to_bsd_tcp_sockopt(int opt)
331fb709557SJohn Baldwin {
332fb709557SJohn Baldwin 
333fb709557SJohn Baldwin 	switch (opt) {
334fb709557SJohn Baldwin 	case LINUX_TCP_NODELAY:
335fb709557SJohn Baldwin 		return (TCP_NODELAY);
336fb709557SJohn Baldwin 	case LINUX_TCP_MAXSEG:
337fb709557SJohn Baldwin 		return (TCP_MAXSEG);
338fb709557SJohn Baldwin 	case LINUX_TCP_KEEPIDLE:
339fb709557SJohn Baldwin 		return (TCP_KEEPIDLE);
340fb709557SJohn Baldwin 	case LINUX_TCP_KEEPINTVL:
341fb709557SJohn Baldwin 		return (TCP_KEEPINTVL);
342fb709557SJohn Baldwin 	case LINUX_TCP_KEEPCNT:
343fb709557SJohn Baldwin 		return (TCP_KEEPCNT);
344fb709557SJohn Baldwin 	case LINUX_TCP_MD5SIG:
345fb709557SJohn Baldwin 		return (TCP_MD5SIG);
346fb709557SJohn Baldwin 	}
347fb709557SJohn Baldwin 	return (-1);
348fb709557SJohn Baldwin }
349fb709557SJohn Baldwin 
350fb709557SJohn Baldwin static int
35140dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
35240dbba57SAssar Westerlund {
35340dbba57SAssar Westerlund 	int ret_flags = 0;
35440dbba57SAssar Westerlund 
35540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
35640dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
35740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
35840dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
35940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
36040dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
36140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
36240dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
36340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
36440dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
36540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
36640dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
36740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
36840dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
36940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
37040dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
3718d6e40c3SMaxim Sobolev 	if (flags & LINUX_MSG_NOSIGNAL)
3728d6e40c3SMaxim Sobolev 		ret_flags |= MSG_NOSIGNAL;
37340dbba57SAssar Westerlund #if 0 /* not handled */
37440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
37540dbba57SAssar Westerlund 		;
37640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
37740dbba57SAssar Westerlund 		;
37840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
37940dbba57SAssar Westerlund 		;
38040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
38140dbba57SAssar Westerlund 		;
38240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
38340dbba57SAssar Westerlund 		;
38440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
38540dbba57SAssar Westerlund 		;
38640dbba57SAssar Westerlund #endif
38740dbba57SAssar Westerlund 	return ret_flags;
38840dbba57SAssar Westerlund }
38940dbba57SAssar Westerlund 
3905c8919adSAlexander Leidinger /*
3915c8919adSAlexander Leidinger * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
3925c8919adSAlexander Leidinger * native syscall will fault.  Thus, we don't really need to check the
3935c8919adSAlexander Leidinger * return values for these functions.
3945c8919adSAlexander Leidinger */
3955c8919adSAlexander Leidinger 
3965c8919adSAlexander Leidinger static int
3975c8919adSAlexander Leidinger bsd_to_linux_sockaddr(struct sockaddr *arg)
3985c8919adSAlexander Leidinger {
3995c8919adSAlexander Leidinger 	struct sockaddr sa;
4005c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
4015c8919adSAlexander Leidinger 	int error;
4025c8919adSAlexander Leidinger 
4035c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
4045c8919adSAlexander Leidinger 		return (error);
4055c8919adSAlexander Leidinger 
4065c8919adSAlexander Leidinger 	*(u_short *)&sa = sa.sa_family;
4075c8919adSAlexander Leidinger 
4085c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
4095c8919adSAlexander Leidinger 
4105c8919adSAlexander Leidinger 	return (error);
4115c8919adSAlexander Leidinger }
4125c8919adSAlexander Leidinger 
4135c8919adSAlexander Leidinger static int
4145c8919adSAlexander Leidinger linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
4155c8919adSAlexander Leidinger {
4165c8919adSAlexander Leidinger 	struct sockaddr sa;
4175c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
4185c8919adSAlexander Leidinger 	int error;
4195c8919adSAlexander Leidinger 
4205c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
4215c8919adSAlexander Leidinger 		return (error);
4225c8919adSAlexander Leidinger 
4235c8919adSAlexander Leidinger 	sa.sa_family = *(sa_family_t *)&sa;
4245c8919adSAlexander Leidinger 	sa.sa_len = len;
4255c8919adSAlexander Leidinger 
4265c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
4275c8919adSAlexander Leidinger 
4285c8919adSAlexander Leidinger 	return (error);
4295c8919adSAlexander Leidinger }
4305c8919adSAlexander Leidinger 
4315c8919adSAlexander Leidinger 
432ca26842eSHajimu UMEMOTO static int
433ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa)
434ca26842eSHajimu UMEMOTO {
435ca26842eSHajimu UMEMOTO 	struct osockaddr sa;
436ca26842eSHajimu UMEMOTO 	int error, bdom;
437ca26842eSHajimu UMEMOTO 
438ca26842eSHajimu UMEMOTO 	/*
439ca26842eSHajimu UMEMOTO 	 * Only read/write the osockaddr family part, the rest is
440ca26842eSHajimu UMEMOTO 	 * not changed.
441ca26842eSHajimu UMEMOTO 	 */
4424b7ef73dSDag-Erling Smørgrav 	error = copyin(osa, &sa, sizeof(sa.sa_family));
443ca26842eSHajimu UMEMOTO 	if (error)
444ca26842eSHajimu UMEMOTO 		return (error);
445ca26842eSHajimu UMEMOTO 
446ca26842eSHajimu UMEMOTO 	bdom = bsd_to_linux_domain(sa.sa_family);
447ca26842eSHajimu UMEMOTO 	if (bdom == -1)
448ca26842eSHajimu UMEMOTO 		return (EINVAL);
449ca26842eSHajimu UMEMOTO 
450ca26842eSHajimu UMEMOTO 	sa.sa_family = bdom;
451ca26842eSHajimu UMEMOTO 	error = copyout(&sa, osa, sizeof(sa.sa_family));
452ca26842eSHajimu UMEMOTO 	if (error)
453ca26842eSHajimu UMEMOTO 		return (error);
454ca26842eSHajimu UMEMOTO 
455ca26842eSHajimu UMEMOTO 	return (0);
456ca26842eSHajimu UMEMOTO }
457ca26842eSHajimu UMEMOTO 
4585a8a13e0SDavid Malone static int
45974f5d680SKonstantin Belousov linux_to_bsd_cmsg_type(int cmsg_type)
4605a8a13e0SDavid Malone {
46174f5d680SKonstantin Belousov 
46274f5d680SKonstantin Belousov 	switch (cmsg_type) {
46374f5d680SKonstantin Belousov 	case LINUX_SCM_RIGHTS:
46474f5d680SKonstantin Belousov 		return (SCM_RIGHTS);
465605da56bSAndriy Gapon 	case LINUX_SCM_CREDENTIALS:
466605da56bSAndriy Gapon 		return (SCM_CREDS);
46774f5d680SKonstantin Belousov 	}
46874f5d680SKonstantin Belousov 	return (-1);
46974f5d680SKonstantin Belousov }
47074f5d680SKonstantin Belousov 
47174f5d680SKonstantin Belousov static int
47274f5d680SKonstantin Belousov bsd_to_linux_cmsg_type(int cmsg_type)
47374f5d680SKonstantin Belousov {
47474f5d680SKonstantin Belousov 
47574f5d680SKonstantin Belousov 	switch (cmsg_type) {
47674f5d680SKonstantin Belousov 	case SCM_RIGHTS:
47774f5d680SKonstantin Belousov 		return (LINUX_SCM_RIGHTS);
478605da56bSAndriy Gapon 	case SCM_CREDS:
479605da56bSAndriy Gapon 		return (LINUX_SCM_CREDENTIALS);
48074f5d680SKonstantin Belousov 	}
48174f5d680SKonstantin Belousov 	return (-1);
48274f5d680SKonstantin Belousov }
48374f5d680SKonstantin Belousov 
48474f5d680SKonstantin Belousov static int
48574f5d680SKonstantin Belousov linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
48674f5d680SKonstantin Belousov {
48774f5d680SKonstantin Belousov 	if (lhdr->msg_controllen > INT_MAX)
48874f5d680SKonstantin Belousov 		return (ENOBUFS);
48974f5d680SKonstantin Belousov 
49074f5d680SKonstantin Belousov 	bhdr->msg_name		= PTRIN(lhdr->msg_name);
49174f5d680SKonstantin Belousov 	bhdr->msg_namelen	= lhdr->msg_namelen;
49274f5d680SKonstantin Belousov 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
49374f5d680SKonstantin Belousov 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
49474f5d680SKonstantin Belousov 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
495605da56bSAndriy Gapon 
496605da56bSAndriy Gapon 	/*
497605da56bSAndriy Gapon 	 * msg_controllen is skipped since BSD and LINUX control messages
498605da56bSAndriy Gapon 	 * are potentially different sizes (e.g. the cred structure used
499605da56bSAndriy Gapon 	 * by SCM_CREDS is different between the two operating system).
500605da56bSAndriy Gapon 	 *
501605da56bSAndriy Gapon 	 * The caller can set it (if necessary) after converting all the
502605da56bSAndriy Gapon 	 * control messages.
503605da56bSAndriy Gapon 	 */
504605da56bSAndriy Gapon 
50574f5d680SKonstantin Belousov 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
50674f5d680SKonstantin Belousov 	return (0);
50774f5d680SKonstantin Belousov }
50874f5d680SKonstantin Belousov 
50974f5d680SKonstantin Belousov static int
51074f5d680SKonstantin Belousov bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
51174f5d680SKonstantin Belousov {
51274f5d680SKonstantin Belousov 	lhdr->msg_name		= PTROUT(bhdr->msg_name);
51374f5d680SKonstantin Belousov 	lhdr->msg_namelen	= bhdr->msg_namelen;
51474f5d680SKonstantin Belousov 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
51574f5d680SKonstantin Belousov 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
51674f5d680SKonstantin Belousov 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
517605da56bSAndriy Gapon 
518605da56bSAndriy Gapon 	/*
519605da56bSAndriy Gapon 	 * msg_controllen is skipped since BSD and LINUX control messages
520605da56bSAndriy Gapon 	 * are potentially different sizes (e.g. the cred structure used
521605da56bSAndriy Gapon 	 * by SCM_CREDS is different between the two operating system).
522605da56bSAndriy Gapon 	 *
523605da56bSAndriy Gapon 	 * The caller can set it (if necessary) after converting all the
524605da56bSAndriy Gapon 	 * control messages.
525605da56bSAndriy Gapon 	 */
526605da56bSAndriy Gapon 
52774f5d680SKonstantin Belousov 	/* msg_flags skipped */
52874f5d680SKonstantin Belousov 	return (0);
52974f5d680SKonstantin Belousov }
53074f5d680SKonstantin Belousov 
53174f5d680SKonstantin Belousov static int
53238a18e97SDmitry Chagin linux_set_socket_flags(struct thread *td, int s, int flags)
53338a18e97SDmitry Chagin {
53438a18e97SDmitry Chagin 	int error;
53538a18e97SDmitry Chagin 
53638a18e97SDmitry Chagin 	if (flags & LINUX_SOCK_NONBLOCK) {
53738a18e97SDmitry Chagin 		error = kern_fcntl(td, s, F_SETFL, O_NONBLOCK);
53838a18e97SDmitry Chagin 		if (error)
53938a18e97SDmitry Chagin 			return (error);
54038a18e97SDmitry Chagin 	}
54138a18e97SDmitry Chagin 	if (flags & LINUX_SOCK_CLOEXEC) {
54238a18e97SDmitry Chagin 		error = kern_fcntl(td, s, F_SETFD, FD_CLOEXEC);
54338a18e97SDmitry Chagin 		if (error)
54438a18e97SDmitry Chagin 			return (error);
54538a18e97SDmitry Chagin 	}
54638a18e97SDmitry Chagin 	return (0);
54738a18e97SDmitry Chagin }
54838a18e97SDmitry Chagin 
54938a18e97SDmitry Chagin static int
55074f5d680SKonstantin Belousov linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
55174f5d680SKonstantin Belousov     struct mbuf *control, enum uio_seg segflg)
55274f5d680SKonstantin Belousov {
5535a8a13e0SDavid Malone 	struct sockaddr *to;
5545a8a13e0SDavid Malone 	int error;
5555a8a13e0SDavid Malone 
5565a8a13e0SDavid Malone 	if (mp->msg_name != NULL) {
5575a8a13e0SDavid Malone 		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
5585a8a13e0SDavid Malone 		if (error)
5595a8a13e0SDavid Malone 			return (error);
5605a8a13e0SDavid Malone 		mp->msg_name = to;
5615a8a13e0SDavid Malone 	} else
5625a8a13e0SDavid Malone 		to = NULL;
5635a8a13e0SDavid Malone 
564a6886ef1SMaxim Sobolev 	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
565a6886ef1SMaxim Sobolev 	    segflg);
5665a8a13e0SDavid Malone 
5675a8a13e0SDavid Malone 	if (to)
5681ede983cSDag-Erling Smørgrav 		free(to, M_SONAME);
5695a8a13e0SDavid Malone 	return (error);
5705a8a13e0SDavid Malone }
5715a8a13e0SDavid Malone 
5723f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
573f2477ae1SMike Smith static int
574e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s)
575f2477ae1SMike Smith {
576857ad5a3SDmitry Chagin 	int error, optval;
577857ad5a3SDmitry Chagin 	socklen_t size_val;
578f2477ae1SMike Smith 
579e140eb43SDavid Malone 	size_val = sizeof(optval);
580e140eb43SDavid Malone 	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
581e140eb43SDavid Malone 	    &optval, UIO_SYSSPACE, &size_val);
582e140eb43SDavid Malone 	if (error)
5833f3a4815SMarcel Moolenaar 		return (error);
5843f3a4815SMarcel Moolenaar 
5853f3a4815SMarcel Moolenaar 	return (optval == 0);
586f2477ae1SMike Smith }
587f2477ae1SMike Smith 
588f2477ae1SMike Smith /*
589f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
590f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
591f2477ae1SMike Smith  */
592f2477ae1SMike Smith static int
59338da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
594f2477ae1SMike Smith {
595f2477ae1SMike Smith /*
596f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
597f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
598a6886ef1SMaxim Sobolev  * It should include all the fields we modify (ip_len and ip_off).
599f2477ae1SMike Smith  */
600f2477ae1SMike Smith #define linux_ip_copysize	8
601f2477ae1SMike Smith 
602f2477ae1SMike Smith 	struct ip *packet;
6035a8a13e0SDavid Malone 	struct msghdr msg;
604a6886ef1SMaxim Sobolev 	struct iovec aiov[1];
605f2477ae1SMike Smith 	int error;
606f2477ae1SMike Smith 
607aa675b57SDavid Schultz 	/* Check that the packet isn't too big or too small. */
608aa675b57SDavid Schultz 	if (linux_args->len < linux_ip_copysize ||
609aa675b57SDavid Schultz 	    linux_args->len > IP_MAXPACKET)
6103f3a4815SMarcel Moolenaar 		return (EINVAL);
611f2477ae1SMike Smith 
612*e0d3ea8cSDmitry Chagin 	packet = (struct ip *)malloc(linux_args->len, M_LINUX, M_WAITOK);
613f2477ae1SMike Smith 
614a6886ef1SMaxim Sobolev 	/* Make kernel copy of the packet to be sent */
6154af27623STim J. Robbins 	if ((error = copyin(PTRIN(linux_args->msg), packet,
616a6886ef1SMaxim Sobolev 	    linux_args->len)))
617a6886ef1SMaxim Sobolev 		goto goout;
618f2477ae1SMike Smith 
619f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
6205a8a13e0SDavid Malone 	packet->ip_len = linux_args->len;
621f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
622f2477ae1SMike Smith 
623f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
6244af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args->to);
6255a8a13e0SDavid Malone 	msg.msg_namelen = linux_args->tolen;
6265a8a13e0SDavid Malone 	msg.msg_iov = aiov;
627a6886ef1SMaxim Sobolev 	msg.msg_iovlen = 1;
6285a8a13e0SDavid Malone 	msg.msg_control = NULL;
6295a8a13e0SDavid Malone 	msg.msg_flags = 0;
6305a8a13e0SDavid Malone 	aiov[0].iov_base = (char *)packet;
631a6886ef1SMaxim Sobolev 	aiov[0].iov_len = linux_args->len;
632a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
63374f5d680SKonstantin Belousov 	    NULL, UIO_SYSSPACE);
634a6886ef1SMaxim Sobolev goout:
635*e0d3ea8cSDmitry Chagin 	free(packet, M_LINUX);
6365a8a13e0SDavid Malone 	return (error);
637f2477ae1SMike Smith }
638f2477ae1SMike Smith 
639a12b9b3dSDmitry Chagin int
640b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
641c21dee17SSøren Schmidt {
642ef04503dSPeter Wemm 	struct socket_args /* {
643c21dee17SSøren Schmidt 		int domain;
644c21dee17SSøren Schmidt 		int type;
645c21dee17SSøren Schmidt 		int protocol;
646ef04503dSPeter Wemm 	} */ bsd_args;
6473933bde2SDmitry Chagin 	int retval_socket, socket_flags;
648c21dee17SSøren Schmidt 
649745aaef5SKonstantin Belousov 	bsd_args.protocol = args->protocol;
6503933bde2SDmitry Chagin 	socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK;
6513933bde2SDmitry Chagin 	if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
6523933bde2SDmitry Chagin 		return (EINVAL);
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);
656745aaef5SKonstantin Belousov 	bsd_args.domain = linux_to_bsd_domain(args->domain);
657c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
658d9b063ccSDmitry Chagin 		return (EAFNOSUPPORT);
659f2477ae1SMike Smith 
6608451d0ddSKip Macy 	retval_socket = sys_socket(td, &bsd_args);
6616994ea54SDmitry Chagin 	if (retval_socket)
6626994ea54SDmitry Chagin 		return (retval_socket);
6636994ea54SDmitry Chagin 
66438a18e97SDmitry Chagin 	retval_socket = linux_set_socket_flags(td, td->td_retval[0],
66538a18e97SDmitry Chagin 	    socket_flags);
6663933bde2SDmitry Chagin 	if (retval_socket) {
6673933bde2SDmitry Chagin 		(void)kern_close(td, td->td_retval[0]);
6683933bde2SDmitry Chagin 		goto out;
6693933bde2SDmitry Chagin 	}
6703933bde2SDmitry Chagin 
671f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
672f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
6736994ea54SDmitry Chagin 	    && bsd_args.domain == PF_INET) {
674f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
675e140eb43SDavid Malone 		int hdrincl;
676f2477ae1SMike Smith 
677e140eb43SDavid Malone 		hdrincl = 1;
678e140eb43SDavid Malone 		/* We ignore any error returned by kern_setsockopt() */
679e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
680e140eb43SDavid Malone 		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
681f2477ae1SMike Smith 	}
682ca26842eSHajimu UMEMOTO #ifdef INET6
683ca26842eSHajimu UMEMOTO 	/*
684d97bee3eSBjoern A. Zeeb 	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by default
685d97bee3eSBjoern A. Zeeb 	 * and some apps depend on this. So, set V6ONLY to 0 for Linux apps.
686d97bee3eSBjoern A. Zeeb 	 * For simplicity we do this unconditionally of the net.inet6.ip6.v6only
687d97bee3eSBjoern A. Zeeb 	 * sysctl value.
688ca26842eSHajimu UMEMOTO 	 */
689d97bee3eSBjoern A. Zeeb 	if (bsd_args.domain == PF_INET6) {
690e140eb43SDavid Malone 		int v6only;
691ca26842eSHajimu UMEMOTO 
692e140eb43SDavid Malone 		v6only = 0;
693ca26842eSHajimu UMEMOTO 		/* We ignore any error returned by setsockopt() */
694e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
695e140eb43SDavid Malone 		    &v6only, UIO_SYSSPACE, sizeof(v6only));
696ca26842eSHajimu UMEMOTO 	}
697ca26842eSHajimu UMEMOTO #endif
6983f3a4815SMarcel Moolenaar 
6993933bde2SDmitry Chagin out:
7003f3a4815SMarcel Moolenaar 	return (retval_socket);
701c21dee17SSøren Schmidt }
702c21dee17SSøren Schmidt 
703a12b9b3dSDmitry Chagin int
704b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
705c21dee17SSøren Schmidt {
706ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
707c21dee17SSøren Schmidt 	int error;
708c21dee17SSøren Schmidt 
709745aaef5SKonstantin Belousov 	error = linux_getsockaddr(&sa, PTRIN(args->name),
710745aaef5SKonstantin Belousov 	    args->namelen);
711ca26842eSHajimu UMEMOTO 	if (error)
712ca26842eSHajimu UMEMOTO 		return (error);
713ca26842eSHajimu UMEMOTO 
7146e646651SKonstantin Belousov 	error = kern_bindat(td, AT_FDCWD, args->s, sa);
715b33887eaSJohn Baldwin 	free(sa, M_SONAME);
716745aaef5SKonstantin Belousov 	if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
717d4b7423fSAlexander Leidinger 	   	return (EINVAL);
718b33887eaSJohn Baldwin 	return (error);
719c21dee17SSøren Schmidt }
720c21dee17SSøren Schmidt 
721930a65feSAndrew Gallatin int
722b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
723c21dee17SSøren Schmidt {
7247008be5bSPawel Jakub Dawidek 	cap_rights_t rights;
7250bf301c0SJonathan Lemon 	struct socket *so;
726ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
72739c95b83SMatthew Dillon 	u_int fflag;
728c21dee17SSøren Schmidt 	int error;
729c21dee17SSøren Schmidt 
730745aaef5SKonstantin Belousov 	error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
731745aaef5SKonstantin Belousov 	    args->namelen);
732ca26842eSHajimu UMEMOTO 	if (error)
733ca26842eSHajimu UMEMOTO 		return (error);
734ca26842eSHajimu UMEMOTO 
7356e646651SKonstantin Belousov 	error = kern_connectat(td, AT_FDCWD, args->s, sa);
736b33887eaSJohn Baldwin 	free(sa, M_SONAME);
7370bf301c0SJonathan Lemon 	if (error != EISCONN)
7380bf301c0SJonathan Lemon 		return (error);
7390bf301c0SJonathan Lemon 
740dad3b88aSMike Smith 	/*
741dad3b88aSMike Smith 	 * Linux doesn't return EISCONN the first time it occurs,
742dad3b88aSMike Smith 	 * when on a non-blocking socket. Instead it returns the
743dad3b88aSMike Smith 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
744f7f45ac8SRobert Watson 	 *
745f7f45ac8SRobert Watson 	 * XXXRW: Instead of using fgetsock(), check that it is a
746f7f45ac8SRobert Watson 	 * socket and use the file descriptor reference instead of
747f7f45ac8SRobert Watson 	 * creating a new one.
748dad3b88aSMike Smith 	 */
7497008be5bSPawel Jakub Dawidek 	error = fgetsock(td, args->s, cap_rights_init(&rights, CAP_CONNECT),
7507008be5bSPawel Jakub Dawidek 	    &so, &fflag);
7514641373fSJohn Baldwin 	if (error == 0) {
7520bf301c0SJonathan Lemon 		error = EISCONN;
75339c95b83SMatthew Dillon 		if (fflag & FNONBLOCK) {
7544641373fSJohn Baldwin 			SOCK_LOCK(so);
7555002a60fSMarcel Moolenaar 			if (so->so_emuldata == 0)
7560bf301c0SJonathan Lemon 				error = so->so_error;
7570bf301c0SJonathan Lemon 			so->so_emuldata = (void *)1;
7584641373fSJohn Baldwin 			SOCK_UNLOCK(so);
759dad3b88aSMike Smith 		}
76039c95b83SMatthew Dillon 		fputsock(so);
7614641373fSJohn Baldwin 	}
7623f3a4815SMarcel Moolenaar 	return (error);
763c21dee17SSøren Schmidt }
764c21dee17SSøren Schmidt 
765a12b9b3dSDmitry Chagin int
766b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
767c21dee17SSøren Schmidt {
768ef04503dSPeter Wemm 	struct listen_args /* {
769c21dee17SSøren Schmidt 		int s;
770c21dee17SSøren Schmidt 		int backlog;
771ef04503dSPeter Wemm 	} */ bsd_args;
772c21dee17SSøren Schmidt 
773745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
774745aaef5SKonstantin Belousov 	bsd_args.backlog = args->backlog;
7758451d0ddSKip Macy 	return (sys_listen(td, &bsd_args));
776c21dee17SSøren Schmidt }
777c21dee17SSøren Schmidt 
77801e0ffbaSAlexander Leidinger static int
779c8f37d61SDmitry Chagin linux_accept_common(struct thread *td, int s, l_uintptr_t addr,
780f83427b8SDmitry Chagin     l_uintptr_t namelen, int flags)
781c21dee17SSøren Schmidt {
782ef04503dSPeter Wemm 	struct accept_args /* {
783c21dee17SSøren Schmidt 		int	s;
7843db2a843SBruce Evans 		struct sockaddr * __restrict name;
7853db2a843SBruce Evans 		socklen_t * __restrict anamelen;
786ef04503dSPeter Wemm 	} */ bsd_args;
78793e694c9SDmitry Chagin 	int error;
78893e694c9SDmitry Chagin 
78993e694c9SDmitry Chagin 	if (flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
79093e694c9SDmitry Chagin 		return (EINVAL);
791c21dee17SSøren Schmidt 
792c8f37d61SDmitry Chagin 	bsd_args.s = s;
7933db2a843SBruce Evans 	/* XXX: */
794c8f37d61SDmitry Chagin 	bsd_args.name = (struct sockaddr * __restrict)PTRIN(addr);
795c8f37d61SDmitry Chagin 	bsd_args.anamelen = PTRIN(namelen);/* XXX */
7968451d0ddSKip Macy 	error = sys_accept(td, &bsd_args);
7975c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
798d4b7423fSAlexander Leidinger 	if (error) {
799c8f37d61SDmitry Chagin 		if (error == EFAULT && namelen != sizeof(struct sockaddr_in))
800d4b7423fSAlexander Leidinger 			return (EINVAL);
801dba5ab66SMarcel Moolenaar 		return (error);
802d4b7423fSAlexander Leidinger 	}
803dba5ab66SMarcel Moolenaar 
804dba5ab66SMarcel Moolenaar 	/*
805dba5ab66SMarcel Moolenaar 	 * linux appears not to copy flags from the parent socket to the
80693e694c9SDmitry Chagin 	 * accepted one, so we must clear the flags in the new descriptor
80793e694c9SDmitry Chagin 	 * and apply the requested flags.
808dba5ab66SMarcel Moolenaar 	 */
80993e694c9SDmitry Chagin 	error = kern_fcntl(td, td->td_retval[0], F_SETFL, 0);
81093e694c9SDmitry Chagin 	if (error)
81193e694c9SDmitry Chagin 		goto out;
81293e694c9SDmitry Chagin 	error = linux_set_socket_flags(td, td->td_retval[0], flags);
81393e694c9SDmitry Chagin 	if (error)
81493e694c9SDmitry Chagin 		goto out;
81593e694c9SDmitry Chagin 	if (addr)
81693e694c9SDmitry Chagin 		error = linux_sa_put(PTRIN(addr));
81793e694c9SDmitry Chagin 
81893e694c9SDmitry Chagin out:
81993e694c9SDmitry Chagin 	if (error) {
82093e694c9SDmitry Chagin 		(void)kern_close(td, td->td_retval[0]);
82193e694c9SDmitry Chagin 		td->td_retval[0] = 0;
82293e694c9SDmitry Chagin 	}
82393e694c9SDmitry Chagin 	return (error);
824c21dee17SSøren Schmidt }
825c21dee17SSøren Schmidt 
826a12b9b3dSDmitry Chagin int
827c8f37d61SDmitry Chagin linux_accept(struct thread *td, struct linux_accept_args *args)
828c8f37d61SDmitry Chagin {
829c8f37d61SDmitry Chagin 
830c8f37d61SDmitry Chagin 	return (linux_accept_common(td, args->s, args->addr,
831f83427b8SDmitry Chagin 	    args->namelen, 0));
832c8f37d61SDmitry Chagin }
833c8f37d61SDmitry Chagin 
834a12b9b3dSDmitry Chagin int
835f8cd0af2SDmitry Chagin linux_accept4(struct thread *td, struct linux_accept4_args *args)
836f8cd0af2SDmitry Chagin {
837f8cd0af2SDmitry Chagin 
838f8cd0af2SDmitry Chagin 	return (linux_accept_common(td, args->s, args->addr,
839f8cd0af2SDmitry Chagin 	    args->namelen, args->flags));
840f8cd0af2SDmitry Chagin }
841f8cd0af2SDmitry Chagin 
842a12b9b3dSDmitry Chagin int
843b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
844c21dee17SSøren Schmidt {
845ef04503dSPeter Wemm 	struct getsockname_args /* {
846c21dee17SSøren Schmidt 		int	fdes;
8473db2a843SBruce Evans 		struct sockaddr * __restrict asa;
8483db2a843SBruce Evans 		socklen_t * __restrict alen;
849ef04503dSPeter Wemm 	} */ bsd_args;
850c21dee17SSøren Schmidt 	int error;
851c21dee17SSøren Schmidt 
852745aaef5SKonstantin Belousov 	bsd_args.fdes = args->s;
8533db2a843SBruce Evans 	/* XXX: */
854745aaef5SKonstantin Belousov 	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
855745aaef5SKonstantin Belousov 	bsd_args.alen = PTRIN(args->namelen);	/* XXX */
8568451d0ddSKip Macy 	error = sys_getsockname(td, &bsd_args);
8575c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
858ca26842eSHajimu UMEMOTO 	if (error)
859ca26842eSHajimu UMEMOTO 		return (error);
860745aaef5SKonstantin Belousov 	error = linux_sa_put(PTRIN(args->addr));
861ca26842eSHajimu UMEMOTO 	if (error)
862ca26842eSHajimu UMEMOTO 		return (error);
863ca26842eSHajimu UMEMOTO 	return (0);
864c21dee17SSøren Schmidt }
865c21dee17SSøren Schmidt 
866a12b9b3dSDmitry Chagin int
867b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
868c21dee17SSøren Schmidt {
8695c8919adSAlexander Leidinger 	struct getpeername_args /* {
870c21dee17SSøren Schmidt 		int fdes;
871c21dee17SSøren Schmidt 		caddr_t asa;
872c21dee17SSøren Schmidt 		int *alen;
873ef04503dSPeter Wemm 	} */ bsd_args;
874c21dee17SSøren Schmidt 	int error;
875c21dee17SSøren Schmidt 
876745aaef5SKonstantin Belousov 	bsd_args.fdes = args->s;
877745aaef5SKonstantin Belousov 	bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
878857ad5a3SDmitry Chagin 	bsd_args.alen = (socklen_t *)PTRIN(args->namelen);
8798451d0ddSKip Macy 	error = sys_getpeername(td, &bsd_args);
8805c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
881ca26842eSHajimu UMEMOTO 	if (error)
882ca26842eSHajimu UMEMOTO 		return (error);
883745aaef5SKonstantin Belousov 	error = linux_sa_put(PTRIN(args->addr));
884ca26842eSHajimu UMEMOTO 	if (error)
885ca26842eSHajimu UMEMOTO 		return (error);
886ca26842eSHajimu UMEMOTO 	return (0);
887c21dee17SSøren Schmidt }
888c21dee17SSøren Schmidt 
889a12b9b3dSDmitry Chagin int
890b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
891c21dee17SSøren Schmidt {
892ef04503dSPeter Wemm 	struct socketpair_args /* {
893c21dee17SSøren Schmidt 		int domain;
894c21dee17SSøren Schmidt 		int type;
895c21dee17SSøren Schmidt 		int protocol;
896c21dee17SSøren Schmidt 		int *rsv;
897ef04503dSPeter Wemm 	} */ bsd_args;
89839253cf9SDmitry Chagin 	int error, socket_flags;
89939253cf9SDmitry Chagin 	int sv[2];
900c21dee17SSøren Schmidt 
901745aaef5SKonstantin Belousov 	bsd_args.domain = linux_to_bsd_domain(args->domain);
9021a52a4abSDmitry Chagin 	if (bsd_args.domain != PF_LOCAL)
9031a52a4abSDmitry Chagin 		return (EAFNOSUPPORT);
9043f3a4815SMarcel Moolenaar 
90539253cf9SDmitry Chagin 	socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK;
90639253cf9SDmitry Chagin 	if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
90739253cf9SDmitry Chagin 		return (EINVAL);
90839253cf9SDmitry Chagin 	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
90939253cf9SDmitry Chagin 	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
91039253cf9SDmitry Chagin 		return (EINVAL);
91139253cf9SDmitry Chagin 
9121a52a4abSDmitry Chagin 	if (args->protocol != 0 && args->protocol != PF_UNIX)
9131a52a4abSDmitry Chagin 
9141a52a4abSDmitry Chagin 		/*
9151a52a4abSDmitry Chagin 		 * Use of PF_UNIX as protocol argument is not right,
9161a52a4abSDmitry Chagin 		 * but Linux does it.
9171a52a4abSDmitry Chagin 		 * Do not map PF_UNIX as its Linux value is identical
9181a52a4abSDmitry Chagin 		 * to FreeBSD one.
9191a52a4abSDmitry Chagin 		 */
9201a52a4abSDmitry Chagin 		return (EPROTONOSUPPORT);
92140092d93SDmitry Chagin 	else
9221a52a4abSDmitry Chagin 		bsd_args.protocol = 0;
923745aaef5SKonstantin Belousov 	bsd_args.rsv = (int *)PTRIN(args->rsv);
92439253cf9SDmitry Chagin 	error = kern_socketpair(td, bsd_args.domain, bsd_args.type,
92539253cf9SDmitry Chagin 	    bsd_args.protocol, sv);
92639253cf9SDmitry Chagin 	if (error)
92739253cf9SDmitry Chagin 		return (error);
92839253cf9SDmitry Chagin 	error = linux_set_socket_flags(td, sv[0], socket_flags);
92939253cf9SDmitry Chagin 	if (error)
93039253cf9SDmitry Chagin 		goto out;
93139253cf9SDmitry Chagin 	error = linux_set_socket_flags(td, sv[1], socket_flags);
93239253cf9SDmitry Chagin 	if (error)
93339253cf9SDmitry Chagin 		goto out;
93439253cf9SDmitry Chagin 
93539253cf9SDmitry Chagin 	error = copyout(sv, bsd_args.rsv, 2 * sizeof(int));
93639253cf9SDmitry Chagin 
93739253cf9SDmitry Chagin out:
93839253cf9SDmitry Chagin 	if (error) {
93939253cf9SDmitry Chagin 		(void)kern_close(td, sv[0]);
94039253cf9SDmitry Chagin 		(void)kern_close(td, sv[1]);
94139253cf9SDmitry Chagin 	}
94239253cf9SDmitry Chagin 	return (error);
943c21dee17SSøren Schmidt }
944c21dee17SSøren Schmidt 
945a12b9b3dSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
94601e0ffbaSAlexander Leidinger struct linux_send_args {
947c21dee17SSøren Schmidt 	int s;
9484af27623STim J. Robbins 	l_uintptr_t msg;
949c21dee17SSøren Schmidt 	int len;
950c21dee17SSøren Schmidt 	int flags;
951c21dee17SSøren Schmidt };
952c21dee17SSøren Schmidt 
95301e0ffbaSAlexander Leidinger static int
954b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
955c21dee17SSøren Schmidt {
95687d72a8fSPoul-Henning Kamp 	struct sendto_args /* {
957c21dee17SSøren Schmidt 		int s;
958c21dee17SSøren Schmidt 		caddr_t buf;
959044af7c3SJonathan Mini 		int len;
960c21dee17SSøren Schmidt 		int flags;
96187d72a8fSPoul-Henning Kamp 		caddr_t to;
96287d72a8fSPoul-Henning Kamp 		int tolen;
963ef04503dSPeter Wemm 	} */ bsd_args;
964c21dee17SSøren Schmidt 
965745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
966745aaef5SKonstantin Belousov 	bsd_args.buf = (caddr_t)PTRIN(args->msg);
967745aaef5SKonstantin Belousov 	bsd_args.len = args->len;
968745aaef5SKonstantin Belousov 	bsd_args.flags = args->flags;
96987d72a8fSPoul-Henning Kamp 	bsd_args.to = NULL;
97087d72a8fSPoul-Henning Kamp 	bsd_args.tolen = 0;
9718451d0ddSKip Macy 	return sys_sendto(td, &bsd_args);
972c21dee17SSøren Schmidt }
973c21dee17SSøren Schmidt 
97401e0ffbaSAlexander Leidinger struct linux_recv_args {
975c21dee17SSøren Schmidt 	int s;
9764af27623STim J. Robbins 	l_uintptr_t msg;
977c21dee17SSøren Schmidt 	int len;
978c21dee17SSøren Schmidt 	int flags;
979c21dee17SSøren Schmidt };
980c21dee17SSøren Schmidt 
98101e0ffbaSAlexander Leidinger static int
982b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
983c21dee17SSøren Schmidt {
98487d72a8fSPoul-Henning Kamp 	struct recvfrom_args /* {
985c21dee17SSøren Schmidt 		int s;
986c21dee17SSøren Schmidt 		caddr_t buf;
987c21dee17SSøren Schmidt 		int len;
988c21dee17SSøren Schmidt 		int flags;
98987d72a8fSPoul-Henning Kamp 		struct sockaddr *from;
99087d72a8fSPoul-Henning Kamp 		socklen_t fromlenaddr;
991ef04503dSPeter Wemm 	} */ bsd_args;
992c21dee17SSøren Schmidt 
993745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
994745aaef5SKonstantin Belousov 	bsd_args.buf = (caddr_t)PTRIN(args->msg);
995745aaef5SKonstantin Belousov 	bsd_args.len = args->len;
9963980a435SDmitry Chagin 	bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
99787d72a8fSPoul-Henning Kamp 	bsd_args.from = NULL;
99887d72a8fSPoul-Henning Kamp 	bsd_args.fromlenaddr = 0;
9998451d0ddSKip Macy 	return (sys_recvfrom(td, &bsd_args));
1000c21dee17SSøren Schmidt }
1001a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1002c21dee17SSøren Schmidt 
1003a12b9b3dSDmitry Chagin int
1004b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
1005c21dee17SSøren Schmidt {
10065a8a13e0SDavid Malone 	struct msghdr msg;
10075a8a13e0SDavid Malone 	struct iovec aiov;
10085a8a13e0SDavid Malone 	int error;
1009c21dee17SSøren Schmidt 
1010745aaef5SKonstantin Belousov 	if (linux_check_hdrincl(td, args->s) == 0)
1011f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
1012745aaef5SKonstantin Belousov 		return (linux_sendto_hdrincl(td, args));
1013f2477ae1SMike Smith 
1014745aaef5SKonstantin Belousov 	msg.msg_name = PTRIN(args->to);
1015745aaef5SKonstantin Belousov 	msg.msg_namelen = args->tolen;
10165a8a13e0SDavid Malone 	msg.msg_iov = &aiov;
10175a8a13e0SDavid Malone 	msg.msg_iovlen = 1;
10185a8a13e0SDavid Malone 	msg.msg_control = NULL;
10195a8a13e0SDavid Malone 	msg.msg_flags = 0;
1020745aaef5SKonstantin Belousov 	aiov.iov_base = PTRIN(args->msg);
1021745aaef5SKonstantin Belousov 	aiov.iov_len = args->len;
102274f5d680SKonstantin Belousov 	error = linux_sendit(td, args->s, &msg, args->flags, NULL,
102374f5d680SKonstantin Belousov 	    UIO_USERSPACE);
10245a8a13e0SDavid Malone 	return (error);
1025c21dee17SSøren Schmidt }
1026c21dee17SSøren Schmidt 
1027a12b9b3dSDmitry Chagin int
1028b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
1029c21dee17SSøren Schmidt {
1030ef04503dSPeter Wemm 	struct recvfrom_args /* {
1031c21dee17SSøren Schmidt 		int	s;
1032c21dee17SSøren Schmidt 		caddr_t	buf;
1033c21dee17SSøren Schmidt 		size_t	len;
1034c21dee17SSøren Schmidt 		int	flags;
10353db2a843SBruce Evans 		struct sockaddr * __restrict from;
10363db2a843SBruce Evans 		socklen_t * __restrict fromlenaddr;
1037ef04503dSPeter Wemm 	} */ bsd_args;
10385c8919adSAlexander Leidinger 	size_t len;
1039c21dee17SSøren Schmidt 	int error;
1040c21dee17SSøren Schmidt 
1041745aaef5SKonstantin Belousov 	if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t))))
10423f3a4815SMarcel Moolenaar 		return (error);
10433f3a4815SMarcel Moolenaar 
1044745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1045745aaef5SKonstantin Belousov 	bsd_args.buf = PTRIN(args->buf);
1046745aaef5SKonstantin Belousov 	bsd_args.len = args->len;
1047745aaef5SKonstantin Belousov 	bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
10483db2a843SBruce Evans 	/* XXX: */
1049745aaef5SKonstantin Belousov 	bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from);
1050745aaef5SKonstantin Belousov 	bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */
10515c8919adSAlexander Leidinger 
10525c8919adSAlexander Leidinger 	linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
10538451d0ddSKip Macy 	error = sys_recvfrom(td, &bsd_args);
10545c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
10555c8919adSAlexander Leidinger 
1056ca26842eSHajimu UMEMOTO 	if (error)
1057ca26842eSHajimu UMEMOTO 		return (error);
1058745aaef5SKonstantin Belousov 	if (args->from) {
10594af27623STim J. Robbins 		error = linux_sa_put((struct osockaddr *)
1060745aaef5SKonstantin Belousov 		    PTRIN(args->from));
1061ca26842eSHajimu UMEMOTO 		if (error)
1062ca26842eSHajimu UMEMOTO 			return (error);
1063ca26842eSHajimu UMEMOTO 	}
1064ca26842eSHajimu UMEMOTO 	return (0);
1065ca26842eSHajimu UMEMOTO }
1066ca26842eSHajimu UMEMOTO 
1067a12b9b3dSDmitry Chagin int
1068ca26842eSHajimu UMEMOTO linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1069ca26842eSHajimu UMEMOTO {
107074f5d680SKonstantin Belousov 	struct cmsghdr *cmsg;
1071605da56bSAndriy Gapon 	struct cmsgcred cmcred;
107274f5d680SKonstantin Belousov 	struct mbuf *control;
1073ca26842eSHajimu UMEMOTO 	struct msghdr msg;
107474f5d680SKonstantin Belousov 	struct l_cmsghdr linux_cmsg;
107574f5d680SKonstantin Belousov 	struct l_cmsghdr *ptr_cmsg;
107674f5d680SKonstantin Belousov 	struct l_msghdr linux_msg;
1077552afd9cSPoul-Henning Kamp 	struct iovec *iov;
107874f5d680SKonstantin Belousov 	socklen_t datalen;
1079605da56bSAndriy Gapon 	struct sockaddr *sa;
1080605da56bSAndriy Gapon 	sa_family_t sa_family;
108174f5d680SKonstantin Belousov 	void *data;
1082ca26842eSHajimu UMEMOTO 	int error;
1083ca26842eSHajimu UMEMOTO 
108474f5d680SKonstantin Belousov 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
108574f5d680SKonstantin Belousov 	if (error)
108674f5d680SKonstantin Belousov 		return (error);
1087d72a6158SRobert Watson 
1088d72a6158SRobert Watson 	/*
1089d72a6158SRobert Watson 	 * Some Linux applications (ping) define a non-NULL control data
1090d72a6158SRobert Watson 	 * pointer, but a msg_controllen of 0, which is not allowed in the
1091d72a6158SRobert Watson 	 * FreeBSD system call interface.  NULL the msg_control pointer in
1092d72a6158SRobert Watson 	 * order to handle this case.  This should be checked, but allows the
1093d72a6158SRobert Watson 	 * Linux ping to work.
1094d72a6158SRobert Watson 	 */
1095605da56bSAndriy Gapon 	if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
1096605da56bSAndriy Gapon 		linux_msg.msg_control = PTROUT(NULL);
1097605da56bSAndriy Gapon 
1098605da56bSAndriy Gapon 	error = linux_to_bsd_msghdr(&msg, &linux_msg);
1099605da56bSAndriy Gapon 	if (error)
1100605da56bSAndriy Gapon 		return (error);
110174f5d680SKonstantin Belousov 
110274f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32
110374f5d680SKonstantin Belousov 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
110474f5d680SKonstantin Belousov 	    &iov, EMSGSIZE);
110574f5d680SKonstantin Belousov #else
1106552afd9cSPoul-Henning Kamp 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
110774f5d680SKonstantin Belousov #endif
1108552afd9cSPoul-Henning Kamp 	if (error)
1109552afd9cSPoul-Henning Kamp 		return (error);
111074f5d680SKonstantin Belousov 
1111605da56bSAndriy Gapon 	control = NULL;
1112605da56bSAndriy Gapon 	cmsg = NULL;
1113605da56bSAndriy Gapon 
1114605da56bSAndriy Gapon 	if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
1115605da56bSAndriy Gapon 		error = kern_getsockname(td, args->s, &sa, &datalen);
1116605da56bSAndriy Gapon 		if (error)
1117605da56bSAndriy Gapon 			goto bad;
1118605da56bSAndriy Gapon 		sa_family = sa->sa_family;
1119605da56bSAndriy Gapon 		free(sa, M_SONAME);
1120605da56bSAndriy Gapon 
112174f5d680SKonstantin Belousov 		error = ENOBUFS;
1122*e0d3ea8cSDmitry Chagin 		cmsg = malloc(CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
1123eb1b1807SGleb Smirnoff 		control = m_get(M_WAITOK, MT_CONTROL);
112474f5d680SKonstantin Belousov 		if (control == NULL)
112574f5d680SKonstantin Belousov 			goto bad;
112674f5d680SKonstantin Belousov 
112774f5d680SKonstantin Belousov 		do {
112874f5d680SKonstantin Belousov 			error = copyin(ptr_cmsg, &linux_cmsg,
112974f5d680SKonstantin Belousov 			    sizeof(struct l_cmsghdr));
113074f5d680SKonstantin Belousov 			if (error)
113174f5d680SKonstantin Belousov 				goto bad;
113274f5d680SKonstantin Belousov 
113374f5d680SKonstantin Belousov 			error = EINVAL;
113474f5d680SKonstantin Belousov 			if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr))
113574f5d680SKonstantin Belousov 				goto bad;
113674f5d680SKonstantin Belousov 
113774f5d680SKonstantin Belousov 			/*
1138605da56bSAndriy Gapon 			 * Now we support only SCM_RIGHTS and SCM_CRED,
1139605da56bSAndriy Gapon 			 * so return EINVAL in any other cmsg_type
114074f5d680SKonstantin Belousov 			 */
1141605da56bSAndriy Gapon 			cmsg->cmsg_type =
1142605da56bSAndriy Gapon 			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
114374f5d680SKonstantin Belousov 			cmsg->cmsg_level =
114474f5d680SKonstantin Belousov 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
1145605da56bSAndriy Gapon 			if (cmsg->cmsg_type == -1
1146605da56bSAndriy Gapon 			    || cmsg->cmsg_level != SOL_SOCKET)
1147605da56bSAndriy Gapon 				goto bad;
114874f5d680SKonstantin Belousov 
1149605da56bSAndriy Gapon 			/*
1150605da56bSAndriy Gapon 			 * Some applications (e.g. pulseaudio) attempt to
1151605da56bSAndriy Gapon 			 * send ancillary data even if the underlying protocol
1152605da56bSAndriy Gapon 			 * doesn't support it which is not allowed in the
1153605da56bSAndriy Gapon 			 * FreeBSD system call interface.
1154605da56bSAndriy Gapon 			 */
1155605da56bSAndriy Gapon 			if (sa_family != AF_UNIX)
1156605da56bSAndriy Gapon 				continue;
1157605da56bSAndriy Gapon 
115874f5d680SKonstantin Belousov 			data = LINUX_CMSG_DATA(ptr_cmsg);
1159605da56bSAndriy Gapon 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
1160605da56bSAndriy Gapon 
1161605da56bSAndriy Gapon 			switch (cmsg->cmsg_type)
1162605da56bSAndriy Gapon 			{
1163605da56bSAndriy Gapon 			case SCM_RIGHTS:
1164605da56bSAndriy Gapon 				break;
1165605da56bSAndriy Gapon 
1166605da56bSAndriy Gapon 			case SCM_CREDS:
1167605da56bSAndriy Gapon 				data = &cmcred;
1168605da56bSAndriy Gapon 				datalen = sizeof(cmcred);
1169605da56bSAndriy Gapon 
1170605da56bSAndriy Gapon 				/*
1171605da56bSAndriy Gapon 				 * The lower levels will fill in the structure
1172605da56bSAndriy Gapon 				 */
1173605da56bSAndriy Gapon 				bzero(data, datalen);
1174605da56bSAndriy Gapon 				break;
1175605da56bSAndriy Gapon 			}
1176605da56bSAndriy Gapon 
1177605da56bSAndriy Gapon 			cmsg->cmsg_len = CMSG_LEN(datalen);
117874f5d680SKonstantin Belousov 
117974f5d680SKonstantin Belousov 			error = ENOBUFS;
118074f5d680SKonstantin Belousov 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t)cmsg))
118174f5d680SKonstantin Belousov 				goto bad;
118274f5d680SKonstantin Belousov 			if (!m_append(control, datalen, (c_caddr_t)data))
118374f5d680SKonstantin Belousov 				goto bad;
1184605da56bSAndriy Gapon 		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
1185605da56bSAndriy Gapon 
1186605da56bSAndriy Gapon 		if (m_length(control, NULL) == 0) {
1187605da56bSAndriy Gapon 			m_freem(control);
118874f5d680SKonstantin Belousov 			control = NULL;
1189605da56bSAndriy Gapon 		}
119074f5d680SKonstantin Belousov 	}
119174f5d680SKonstantin Belousov 
11925a8a13e0SDavid Malone 	msg.msg_iov = iov;
11935a8a13e0SDavid Malone 	msg.msg_flags = 0;
119474f5d680SKonstantin Belousov 	error = linux_sendit(td, args->s, &msg, args->flags, control,
119574f5d680SKonstantin Belousov 	    UIO_USERSPACE);
119674f5d680SKonstantin Belousov 
119774f5d680SKonstantin Belousov bad:
1198552afd9cSPoul-Henning Kamp 	free(iov, M_IOV);
119974f5d680SKonstantin Belousov 	if (cmsg)
1200*e0d3ea8cSDmitry Chagin 		free(cmsg, M_LINUX);
1201ca26842eSHajimu UMEMOTO 	return (error);
1202c21dee17SSøren Schmidt }
1203c21dee17SSøren Schmidt 
1204a12b9b3dSDmitry Chagin int
1205b40ce416SJulian Elischer linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
120640dbba57SAssar Westerlund {
120774f5d680SKonstantin Belousov 	struct cmsghdr *cm;
1208605da56bSAndriy Gapon 	struct cmsgcred *cmcred;
1209ca26842eSHajimu UMEMOTO 	struct msghdr msg;
121074f5d680SKonstantin Belousov 	struct l_cmsghdr *linux_cmsg = NULL;
1211605da56bSAndriy Gapon 	struct l_ucred linux_ucred;
1212605da56bSAndriy Gapon 	socklen_t datalen, outlen;
121374f5d680SKonstantin Belousov 	struct l_msghdr linux_msg;
121474f5d680SKonstantin Belousov 	struct iovec *iov, *uiov;
121574f5d680SKonstantin Belousov 	struct mbuf *control = NULL;
121674f5d680SKonstantin Belousov 	struct mbuf **controlp;
121774f5d680SKonstantin Belousov 	caddr_t outbuf;
121874f5d680SKonstantin Belousov 	void *data;
12193a72bf04SDmitry Chagin 	int error, i, fd, fds, *fdp;
122040dbba57SAssar Westerlund 
122174f5d680SKonstantin Belousov 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
1222ca26842eSHajimu UMEMOTO 	if (error)
1223ca26842eSHajimu UMEMOTO 		return (error);
1224ca26842eSHajimu UMEMOTO 
122574f5d680SKonstantin Belousov 	error = linux_to_bsd_msghdr(&msg, &linux_msg);
122674f5d680SKonstantin Belousov 	if (error)
122774f5d680SKonstantin Belousov 		return (error);
122874f5d680SKonstantin Belousov 
122974f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32
123074f5d680SKonstantin Belousov 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
123174f5d680SKonstantin Belousov 	    &iov, EMSGSIZE);
123274f5d680SKonstantin Belousov #else
123374f5d680SKonstantin Belousov 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
123474f5d680SKonstantin Belousov #endif
123574f5d680SKonstantin Belousov 	if (error)
123674f5d680SKonstantin Belousov 		return (error);
123774f5d680SKonstantin Belousov 
123874f5d680SKonstantin Belousov 	if (msg.msg_name) {
123974f5d680SKonstantin Belousov 		error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
124074f5d680SKonstantin Belousov 		    msg.msg_namelen);
124174f5d680SKonstantin Belousov 		if (error)
124274f5d680SKonstantin Belousov 			goto bad;
124384b11cd8SMitsuru IWASAKI 	}
124484b11cd8SMitsuru IWASAKI 
124574f5d680SKonstantin Belousov 	uiov = msg.msg_iov;
124674f5d680SKonstantin Belousov 	msg.msg_iov = iov;
124774f5d680SKonstantin Belousov 	controlp = (msg.msg_control != NULL) ? &control : NULL;
124874f5d680SKonstantin Belousov 	error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp);
124974f5d680SKonstantin Belousov 	msg.msg_iov = uiov;
1250ca26842eSHajimu UMEMOTO 	if (error)
125174f5d680SKonstantin Belousov 		goto bad;
125274f5d680SKonstantin Belousov 
125374f5d680SKonstantin Belousov 	error = bsd_to_linux_msghdr(&msg, &linux_msg);
125474f5d680SKonstantin Belousov 	if (error)
125574f5d680SKonstantin Belousov 		goto bad;
125674f5d680SKonstantin Belousov 
125774f5d680SKonstantin Belousov 	if (linux_msg.msg_name) {
125874f5d680SKonstantin Belousov 		error = bsd_to_linux_sockaddr((struct sockaddr *)
125974f5d680SKonstantin Belousov 		    PTRIN(linux_msg.msg_name));
126074f5d680SKonstantin Belousov 		if (error)
126174f5d680SKonstantin Belousov 			goto bad;
126274f5d680SKonstantin Belousov 	}
126374f5d680SKonstantin Belousov 	if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
126474f5d680SKonstantin Belousov 		error = linux_sa_put(PTRIN(linux_msg.msg_name));
126574f5d680SKonstantin Belousov 		if (error)
126674f5d680SKonstantin Belousov 			goto bad;
126774f5d680SKonstantin Belousov 	}
126874f5d680SKonstantin Belousov 
126974f5d680SKonstantin Belousov 	outbuf = PTRIN(linux_msg.msg_control);
127074f5d680SKonstantin Belousov 	outlen = 0;
1271605da56bSAndriy Gapon 
1272605da56bSAndriy Gapon 	if (control) {
1273*e0d3ea8cSDmitry Chagin 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_LINUX, M_WAITOK | M_ZERO);
1274605da56bSAndriy Gapon 
1275605da56bSAndriy Gapon 		msg.msg_control = mtod(control, struct cmsghdr *);
1276605da56bSAndriy Gapon 		msg.msg_controllen = control->m_len;
1277605da56bSAndriy Gapon 
1278605da56bSAndriy Gapon 		cm = CMSG_FIRSTHDR(&msg);
127974f5d680SKonstantin Belousov 
128074f5d680SKonstantin Belousov 		while (cm != NULL) {
1281605da56bSAndriy Gapon 			linux_cmsg->cmsg_type =
1282605da56bSAndriy Gapon 			    bsd_to_linux_cmsg_type(cm->cmsg_type);
1283605da56bSAndriy Gapon 			linux_cmsg->cmsg_level =
1284605da56bSAndriy Gapon 			    bsd_to_linux_sockopt_level(cm->cmsg_level);
1285605da56bSAndriy Gapon 			if (linux_cmsg->cmsg_type == -1
1286605da56bSAndriy Gapon 			    || cm->cmsg_level != SOL_SOCKET)
128774f5d680SKonstantin Belousov 			{
128874f5d680SKonstantin Belousov 				error = EINVAL;
128974f5d680SKonstantin Belousov 				goto bad;
129074f5d680SKonstantin Belousov 			}
1291605da56bSAndriy Gapon 
129274f5d680SKonstantin Belousov 			data = CMSG_DATA(cm);
129374f5d680SKonstantin Belousov 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
129474f5d680SKonstantin Belousov 
1295605da56bSAndriy Gapon 			switch (cm->cmsg_type)
12963a72bf04SDmitry Chagin 			{
1297605da56bSAndriy Gapon 			case SCM_RIGHTS:
1298605da56bSAndriy Gapon 				if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
1299605da56bSAndriy Gapon 					fds = datalen / sizeof(int);
1300605da56bSAndriy Gapon 					fdp = data;
1301605da56bSAndriy Gapon 					for (i = 0; i < fds; i++) {
1302605da56bSAndriy Gapon 						fd = *fdp++;
1303605da56bSAndriy Gapon 						(void)kern_fcntl(td, fd,
1304605da56bSAndriy Gapon 						    F_SETFD, FD_CLOEXEC);
1305605da56bSAndriy Gapon 					}
1306605da56bSAndriy Gapon 				}
1307605da56bSAndriy Gapon 				break;
1308605da56bSAndriy Gapon 
1309605da56bSAndriy Gapon 			case SCM_CREDS:
1310605da56bSAndriy Gapon 				/*
1311605da56bSAndriy Gapon 				 * Currently LOCAL_CREDS is never in
1312605da56bSAndriy Gapon 				 * effect for Linux so no need to worry
1313605da56bSAndriy Gapon 				 * about sockcred
1314605da56bSAndriy Gapon 				 */
1315605da56bSAndriy Gapon 				if (datalen != sizeof(*cmcred)) {
1316605da56bSAndriy Gapon 					error = EMSGSIZE;
1317605da56bSAndriy Gapon 					goto bad;
1318605da56bSAndriy Gapon 				}
1319605da56bSAndriy Gapon 				cmcred = (struct cmsgcred *)data;
1320605da56bSAndriy Gapon 				bzero(&linux_ucred, sizeof(linux_ucred));
1321605da56bSAndriy Gapon 				linux_ucred.pid = cmcred->cmcred_pid;
1322605da56bSAndriy Gapon 				linux_ucred.uid = cmcred->cmcred_uid;
1323605da56bSAndriy Gapon 				linux_ucred.gid = cmcred->cmcred_gid;
1324605da56bSAndriy Gapon 				data = &linux_ucred;
1325605da56bSAndriy Gapon 				datalen = sizeof(linux_ucred);
1326605da56bSAndriy Gapon 				break;
1327605da56bSAndriy Gapon 			}
1328605da56bSAndriy Gapon 
132974f5d680SKonstantin Belousov 			if (outlen + LINUX_CMSG_LEN(datalen) >
133074f5d680SKonstantin Belousov 			    linux_msg.msg_controllen) {
133174f5d680SKonstantin Belousov 				if (outlen == 0) {
133274f5d680SKonstantin Belousov 					error = EMSGSIZE;
133374f5d680SKonstantin Belousov 					goto bad;
133474f5d680SKonstantin Belousov 				} else {
13353a72bf04SDmitry Chagin 					linux_msg.msg_flags |=
13363a72bf04SDmitry Chagin 					    LINUX_MSG_CTRUNC;
133774f5d680SKonstantin Belousov 					goto out;
133874f5d680SKonstantin Belousov 				}
133974f5d680SKonstantin Belousov 			}
134074f5d680SKonstantin Belousov 
134174f5d680SKonstantin Belousov 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
134274f5d680SKonstantin Belousov 
134374f5d680SKonstantin Belousov 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
134474f5d680SKonstantin Belousov 			if (error)
134574f5d680SKonstantin Belousov 				goto bad;
134674f5d680SKonstantin Belousov 			outbuf += L_CMSG_HDRSZ;
134774f5d680SKonstantin Belousov 
134874f5d680SKonstantin Belousov 			error = copyout(data, outbuf, datalen);
134974f5d680SKonstantin Belousov 			if (error)
135074f5d680SKonstantin Belousov 				goto bad;
135174f5d680SKonstantin Belousov 
135274f5d680SKonstantin Belousov 			outbuf += LINUX_CMSG_ALIGN(datalen);
135374f5d680SKonstantin Belousov 			outlen += LINUX_CMSG_LEN(datalen);
135474f5d680SKonstantin Belousov 
1355605da56bSAndriy Gapon 			cm = CMSG_NXTHDR(&msg, cm);
135674f5d680SKonstantin Belousov 		}
135774f5d680SKonstantin Belousov 	}
135874f5d680SKonstantin Belousov 
135974f5d680SKonstantin Belousov out:
1360605da56bSAndriy Gapon 	linux_msg.msg_controllen = outlen;
136174f5d680SKonstantin Belousov 	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
136274f5d680SKonstantin Belousov 
136374f5d680SKonstantin Belousov bad:
136474f5d680SKonstantin Belousov 	free(iov, M_IOV);
136574f5d680SKonstantin Belousov 	m_freem(control);
1366*e0d3ea8cSDmitry Chagin 	free(linux_cmsg, M_LINUX);
136774f5d680SKonstantin Belousov 
1368ca26842eSHajimu UMEMOTO 	return (error);
136940dbba57SAssar Westerlund }
137040dbba57SAssar Westerlund 
1371a12b9b3dSDmitry Chagin int
1372b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1373c21dee17SSøren Schmidt {
1374ef04503dSPeter Wemm 	struct shutdown_args /* {
1375c21dee17SSøren Schmidt 		int s;
1376c21dee17SSøren Schmidt 		int how;
1377ef04503dSPeter Wemm 	} */ bsd_args;
1378c21dee17SSøren Schmidt 
1379745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1380745aaef5SKonstantin Belousov 	bsd_args.how = args->how;
13818451d0ddSKip Macy 	return (sys_shutdown(td, &bsd_args));
1382c21dee17SSøren Schmidt }
1383c21dee17SSøren Schmidt 
1384a12b9b3dSDmitry Chagin int
1385b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1386c21dee17SSøren Schmidt {
1387ef04503dSPeter Wemm 	struct setsockopt_args /* {
1388c21dee17SSøren Schmidt 		int s;
1389c21dee17SSøren Schmidt 		int level;
1390c21dee17SSøren Schmidt 		int name;
1391c21dee17SSøren Schmidt 		caddr_t val;
1392c21dee17SSøren Schmidt 		int valsize;
1393ef04503dSPeter Wemm 	} */ bsd_args;
139403cc95d2SDmitry Chagin 	l_timeval linux_tv;
139503cc95d2SDmitry Chagin 	struct timeval tv;
1396c21dee17SSøren Schmidt 	int error, name;
1397c21dee17SSøren Schmidt 
1398745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1399745aaef5SKonstantin Belousov 	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1400c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1401c21dee17SSøren Schmidt 	case SOL_SOCKET:
1402745aaef5SKonstantin Belousov 		name = linux_to_bsd_so_sockopt(args->optname);
140303cc95d2SDmitry Chagin 		switch (name) {
140403cc95d2SDmitry Chagin 		case SO_RCVTIMEO:
140503cc95d2SDmitry Chagin 			/* FALLTHROUGH */
140603cc95d2SDmitry Chagin 		case SO_SNDTIMEO:
140703cc95d2SDmitry Chagin 			error = copyin(PTRIN(args->optval), &linux_tv,
140803cc95d2SDmitry Chagin 			    sizeof(linux_tv));
140903cc95d2SDmitry Chagin 			if (error)
141003cc95d2SDmitry Chagin 				return (error);
141103cc95d2SDmitry Chagin 			tv.tv_sec = linux_tv.tv_sec;
141203cc95d2SDmitry Chagin 			tv.tv_usec = linux_tv.tv_usec;
141303cc95d2SDmitry Chagin 			return (kern_setsockopt(td, args->s, bsd_args.level,
141403cc95d2SDmitry Chagin 			    name, &tv, UIO_SYSSPACE, sizeof(tv)));
141503cc95d2SDmitry Chagin 			/* NOTREACHED */
141603cc95d2SDmitry Chagin 			break;
141703cc95d2SDmitry Chagin 		default:
141803cc95d2SDmitry Chagin 			break;
141903cc95d2SDmitry Chagin 		}
1420c21dee17SSøren Schmidt 		break;
1421c21dee17SSøren Schmidt 	case IPPROTO_IP:
1422745aaef5SKonstantin Belousov 		name = linux_to_bsd_ip_sockopt(args->optname);
1423c21dee17SSøren Schmidt 		break;
1424dad3b88aSMike Smith 	case IPPROTO_TCP:
1425fb709557SJohn Baldwin 		name = linux_to_bsd_tcp_sockopt(args->optname);
1426dad3b88aSMike Smith 		break;
1427c21dee17SSøren Schmidt 	default:
14283f3a4815SMarcel Moolenaar 		name = -1;
14293f3a4815SMarcel Moolenaar 		break;
1430c21dee17SSøren Schmidt 	}
1431c21dee17SSøren Schmidt 	if (name == -1)
1432d4b7423fSAlexander Leidinger 		return (ENOPROTOOPT);
14333f3a4815SMarcel Moolenaar 
1434c21dee17SSøren Schmidt 	bsd_args.name = name;
1435745aaef5SKonstantin Belousov 	bsd_args.val = PTRIN(args->optval);
1436745aaef5SKonstantin Belousov 	bsd_args.valsize = args->optlen;
14375c8919adSAlexander Leidinger 
14385c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
14395c8919adSAlexander Leidinger 		linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
14405c8919adSAlexander Leidinger 			bsd_args.valsize);
14418451d0ddSKip Macy 		error = sys_setsockopt(td, &bsd_args);
14425c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
14435c8919adSAlexander Leidinger 	} else
14448451d0ddSKip Macy 		error = sys_setsockopt(td, &bsd_args);
14455c8919adSAlexander Leidinger 
14465c8919adSAlexander Leidinger 	return (error);
1447c21dee17SSøren Schmidt }
1448c21dee17SSøren Schmidt 
1449a12b9b3dSDmitry Chagin int
1450b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1451c21dee17SSøren Schmidt {
1452ef04503dSPeter Wemm 	struct getsockopt_args /* {
1453c21dee17SSøren Schmidt 		int s;
1454c21dee17SSøren Schmidt 		int level;
1455c21dee17SSøren Schmidt 		int name;
1456c21dee17SSøren Schmidt 		caddr_t val;
1457c21dee17SSøren Schmidt 		int *avalsize;
1458ef04503dSPeter Wemm 	} */ bsd_args;
145903cc95d2SDmitry Chagin 	l_timeval linux_tv;
146003cc95d2SDmitry Chagin 	struct timeval tv;
1461d4dd69c4SDmitry Chagin 	socklen_t tv_len, xulen;
1462d4dd69c4SDmitry Chagin 	struct xucred xu;
1463d4dd69c4SDmitry Chagin 	struct l_ucred lxu;
1464c21dee17SSøren Schmidt 	int error, name;
1465c21dee17SSøren Schmidt 
1466745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1467745aaef5SKonstantin Belousov 	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1468c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1469c21dee17SSøren Schmidt 	case SOL_SOCKET:
1470745aaef5SKonstantin Belousov 		name = linux_to_bsd_so_sockopt(args->optname);
147103cc95d2SDmitry Chagin 		switch (name) {
147203cc95d2SDmitry Chagin 		case SO_RCVTIMEO:
147303cc95d2SDmitry Chagin 			/* FALLTHROUGH */
147403cc95d2SDmitry Chagin 		case SO_SNDTIMEO:
147503cc95d2SDmitry Chagin 			tv_len = sizeof(tv);
147603cc95d2SDmitry Chagin 			error = kern_getsockopt(td, args->s, bsd_args.level,
147703cc95d2SDmitry Chagin 			    name, &tv, UIO_SYSSPACE, &tv_len);
147803cc95d2SDmitry Chagin 			if (error)
147903cc95d2SDmitry Chagin 				return (error);
148003cc95d2SDmitry Chagin 			linux_tv.tv_sec = tv.tv_sec;
148103cc95d2SDmitry Chagin 			linux_tv.tv_usec = tv.tv_usec;
148203cc95d2SDmitry Chagin 			return (copyout(&linux_tv, PTRIN(args->optval),
148303cc95d2SDmitry Chagin 			    sizeof(linux_tv)));
148403cc95d2SDmitry Chagin 			/* NOTREACHED */
148503cc95d2SDmitry Chagin 			break;
1486d4dd69c4SDmitry Chagin 		case LOCAL_PEERCRED:
1487d4dd69c4SDmitry Chagin 			if (args->optlen != sizeof(lxu))
1488d4dd69c4SDmitry Chagin 				return (EINVAL);
1489d4dd69c4SDmitry Chagin 			xulen = sizeof(xu);
1490d4dd69c4SDmitry Chagin 			error = kern_getsockopt(td, args->s, bsd_args.level,
1491d4dd69c4SDmitry Chagin 			    name, &xu, UIO_SYSSPACE, &xulen);
1492d4dd69c4SDmitry Chagin 			if (error)
1493d4dd69c4SDmitry Chagin 				return (error);
1494d4dd69c4SDmitry Chagin 			/*
1495d4dd69c4SDmitry Chagin 			 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1496d4dd69c4SDmitry Chagin 			 */
1497d4dd69c4SDmitry Chagin 			lxu.pid = 0;
1498d4dd69c4SDmitry Chagin 			lxu.uid = xu.cr_uid;
1499d4dd69c4SDmitry Chagin 			lxu.gid = xu.cr_gid;
1500d4dd69c4SDmitry Chagin 			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
1501d4dd69c4SDmitry Chagin 			/* NOTREACHED */
1502d4dd69c4SDmitry Chagin 			break;
150303cc95d2SDmitry Chagin 		default:
150403cc95d2SDmitry Chagin 			break;
150503cc95d2SDmitry Chagin 		}
1506c21dee17SSøren Schmidt 		break;
1507c21dee17SSøren Schmidt 	case IPPROTO_IP:
1508745aaef5SKonstantin Belousov 		name = linux_to_bsd_ip_sockopt(args->optname);
1509c21dee17SSøren Schmidt 		break;
1510dad3b88aSMike Smith 	case IPPROTO_TCP:
1511fb709557SJohn Baldwin 		name = linux_to_bsd_tcp_sockopt(args->optname);
1512dad3b88aSMike Smith 		break;
1513c21dee17SSøren Schmidt 	default:
15143f3a4815SMarcel Moolenaar 		name = -1;
15153f3a4815SMarcel Moolenaar 		break;
1516c21dee17SSøren Schmidt 	}
1517c21dee17SSøren Schmidt 	if (name == -1)
15183f3a4815SMarcel Moolenaar 		return (EINVAL);
15193f3a4815SMarcel Moolenaar 
1520f2477ae1SMike Smith 	bsd_args.name = name;
1521745aaef5SKonstantin Belousov 	bsd_args.val = PTRIN(args->optval);
1522745aaef5SKonstantin Belousov 	bsd_args.avalsize = PTRIN(args->optlen);
15235c8919adSAlexander Leidinger 
15245c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
15258451d0ddSKip Macy 		error = sys_getsockopt(td, &bsd_args);
15265c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
15275c8919adSAlexander Leidinger 	} else
15288451d0ddSKip Macy 		error = sys_getsockopt(td, &bsd_args);
15295c8919adSAlexander Leidinger 
15305c8919adSAlexander Leidinger 	return (error);
1531c21dee17SSøren Schmidt }
1532c21dee17SSøren Schmidt 
15337f8f1d7fSDmitry Chagin #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
15347f8f1d7fSDmitry Chagin 
1535ea7b81d2SDmitry Chagin /* Argument list sizes for linux_socketcall */
1536ea7b81d2SDmitry Chagin 
1537ea7b81d2SDmitry Chagin #define LINUX_AL(x) ((x) * sizeof(l_ulong))
1538ea7b81d2SDmitry Chagin 
1539ea7b81d2SDmitry Chagin static const unsigned char lxs_args[] = {
1540ea7b81d2SDmitry Chagin 	LINUX_AL(0) /* unused*/,	LINUX_AL(3) /* socket */,
1541ea7b81d2SDmitry Chagin 	LINUX_AL(3) /* bind */,		LINUX_AL(3) /* connect */,
1542ea7b81d2SDmitry Chagin 	LINUX_AL(2) /* listen */,	LINUX_AL(3) /* accept */,
1543ea7b81d2SDmitry Chagin 	LINUX_AL(3) /* getsockname */,	LINUX_AL(3) /* getpeername */,
1544ea7b81d2SDmitry Chagin 	LINUX_AL(4) /* socketpair */,	LINUX_AL(4) /* send */,
1545ea7b81d2SDmitry Chagin 	LINUX_AL(4) /* recv */,		LINUX_AL(6) /* sendto */,
1546ea7b81d2SDmitry Chagin 	LINUX_AL(6) /* recvfrom */,	LINUX_AL(2) /* shutdown */,
1547ea7b81d2SDmitry Chagin 	LINUX_AL(5) /* setsockopt */,	LINUX_AL(5) /* getsockopt */,
1548f8cd0af2SDmitry Chagin 	LINUX_AL(3) /* sendmsg */,	LINUX_AL(3) /* recvmsg */,
1549f8cd0af2SDmitry Chagin 	LINUX_AL(4) /* accept4 */
1550ea7b81d2SDmitry Chagin };
1551ea7b81d2SDmitry Chagin 
1552ea7b81d2SDmitry Chagin #define	LINUX_AL_SIZE	sizeof(lxs_args) / sizeof(lxs_args[0]) - 1
1553ea7b81d2SDmitry Chagin 
1554c21dee17SSøren Schmidt int
1555b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1556c21dee17SSøren Schmidt {
1557ea7b81d2SDmitry Chagin 	l_ulong a[6];
1558ea7b81d2SDmitry Chagin 	void *arg;
1559ea7b81d2SDmitry Chagin 	int error;
15603f3a4815SMarcel Moolenaar 
1561ea7b81d2SDmitry Chagin 	if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE)
1562ea7b81d2SDmitry Chagin 		return (EINVAL);
1563ea7b81d2SDmitry Chagin 	error = copyin(PTRIN(args->args), a, lxs_args[args->what]);
1564ea7b81d2SDmitry Chagin 	if (error)
1565ea7b81d2SDmitry Chagin 		return (error);
1566ea7b81d2SDmitry Chagin 
1567ea7b81d2SDmitry Chagin 	arg = a;
1568c21dee17SSøren Schmidt 	switch (args->what) {
1569c21dee17SSøren Schmidt 	case LINUX_SOCKET:
1570b40ce416SJulian Elischer 		return (linux_socket(td, arg));
1571c21dee17SSøren Schmidt 	case LINUX_BIND:
1572b40ce416SJulian Elischer 		return (linux_bind(td, arg));
1573c21dee17SSøren Schmidt 	case LINUX_CONNECT:
1574b40ce416SJulian Elischer 		return (linux_connect(td, arg));
1575c21dee17SSøren Schmidt 	case LINUX_LISTEN:
1576b40ce416SJulian Elischer 		return (linux_listen(td, arg));
1577c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
1578b40ce416SJulian Elischer 		return (linux_accept(td, arg));
1579c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
1580b40ce416SJulian Elischer 		return (linux_getsockname(td, arg));
1581c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
1582b40ce416SJulian Elischer 		return (linux_getpeername(td, arg));
1583c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
1584b40ce416SJulian Elischer 		return (linux_socketpair(td, arg));
1585c21dee17SSøren Schmidt 	case LINUX_SEND:
1586b40ce416SJulian Elischer 		return (linux_send(td, arg));
1587c21dee17SSøren Schmidt 	case LINUX_RECV:
1588b40ce416SJulian Elischer 		return (linux_recv(td, arg));
1589c21dee17SSøren Schmidt 	case LINUX_SENDTO:
1590b40ce416SJulian Elischer 		return (linux_sendto(td, arg));
1591c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
1592b40ce416SJulian Elischer 		return (linux_recvfrom(td, arg));
1593c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
1594b40ce416SJulian Elischer 		return (linux_shutdown(td, arg));
1595c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
1596b40ce416SJulian Elischer 		return (linux_setsockopt(td, arg));
1597c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
1598b40ce416SJulian Elischer 		return (linux_getsockopt(td, arg));
1599e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
1600ca26842eSHajimu UMEMOTO 		return (linux_sendmsg(td, arg));
1601e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
1602b40ce416SJulian Elischer 		return (linux_recvmsg(td, arg));
1603f8cd0af2SDmitry Chagin 	case LINUX_ACCEPT4:
1604f8cd0af2SDmitry Chagin 		return (linux_accept4(td, arg));
1605c21dee17SSøren Schmidt 	}
16063f3a4815SMarcel Moolenaar 
16073f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
16083f3a4815SMarcel Moolenaar 	return (ENOSYS);
1609c21dee17SSøren Schmidt }
1610a12b9b3dSDmitry Chagin #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1611