xref: /freebsd/sys/compat/linux/linux_socket.c (revision c1cccebe8bd231f9a75e63ab237deed59bddb9b5)
1c21dee17SSøren Schmidt /*-
2c21dee17SSøren Schmidt  * 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>
40dad3b88aSMike Smith #include <sys/fcntl.h>
410bf301c0SJonathan Lemon #include <sys/file.h>
42104a9b7eSAlexander Kabaev #include <sys/limits.h>
434641373fSJohn Baldwin #include <sys/lock.h>
44ca26842eSHajimu UMEMOTO #include <sys/malloc.h>
454641373fSJohn Baldwin #include <sys/mutex.h>
465a8a13e0SDavid Malone #include <sys/mbuf.h>
47c21dee17SSøren Schmidt #include <sys/socket.h>
480bf301c0SJonathan Lemon #include <sys/socketvar.h>
49ca26842eSHajimu UMEMOTO #include <sys/syscallsubr.h>
5008637435SBruce Evans #include <sys/uio.h>
51ca26842eSHajimu UMEMOTO #include <sys/syslog.h>
521f3dad5aSBruce Evans 
53c21dee17SSøren Schmidt #include <netinet/in.h>
54f2477ae1SMike Smith #include <netinet/in_systm.h>
55f2477ae1SMike Smith #include <netinet/ip.h>
56ca26842eSHajimu UMEMOTO #ifdef INET6
57ca26842eSHajimu UMEMOTO #include <netinet/ip6.h>
58ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h>
59ca26842eSHajimu UMEMOTO #endif
60c21dee17SSøren Schmidt 
611997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
624af27623STim J. Robbins #include <machine/../linux32/linux.h>
634af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
641997c537SDavid E. O'Brien #else
651997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
661997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
674af27623STim J. Robbins #endif
6840dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
69ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
70c21dee17SSøren Schmidt 
71ca26842eSHajimu UMEMOTO static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
72ca26842eSHajimu UMEMOTO     struct malloc_type *);
73ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int);
74ca26842eSHajimu UMEMOTO 
754730796cSBill Fenner /*
76ca26842eSHajimu UMEMOTO  * Reads a linux sockaddr and does any necessary translation.
77ca26842eSHajimu UMEMOTO  * Linux sockaddrs don't have a length field, only a family.
784730796cSBill Fenner  */
794730796cSBill Fenner static int
80ca26842eSHajimu UMEMOTO linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
814730796cSBill Fenner {
82ca26842eSHajimu UMEMOTO 	int osalen = len;
834730796cSBill Fenner 
84ca26842eSHajimu UMEMOTO 	return (do_sa_get(sap, osa, &osalen, M_SONAME));
854730796cSBill Fenner }
864730796cSBill Fenner 
87ca26842eSHajimu UMEMOTO /*
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
92ca26842eSHajimu UMEMOTO do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
93ca26842eSHajimu UMEMOTO     struct malloc_type *mtype)
94ca26842eSHajimu UMEMOTO {
95ca26842eSHajimu UMEMOTO 	int error=0, bdom;
96ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
97ca26842eSHajimu UMEMOTO 	struct osockaddr *kosa;
98ca26842eSHajimu UMEMOTO 	int alloclen;
99ca26842eSHajimu UMEMOTO #ifdef INET6
100ca26842eSHajimu UMEMOTO 	int oldv6size;
101ca26842eSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
102ca26842eSHajimu UMEMOTO #endif
103ca26842eSHajimu UMEMOTO 
104ca26842eSHajimu UMEMOTO 	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
105ca26842eSHajimu UMEMOTO 		return (EINVAL);
106ca26842eSHajimu UMEMOTO 
107ca26842eSHajimu UMEMOTO 	alloclen = *osalen;
108ca26842eSHajimu UMEMOTO #ifdef INET6
109ca26842eSHajimu UMEMOTO 	oldv6size = 0;
110ca26842eSHajimu UMEMOTO 	/*
111ca26842eSHajimu UMEMOTO 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
112ca26842eSHajimu UMEMOTO 	 * if it's a v4-mapped address, so reserve the proper space
113ca26842eSHajimu UMEMOTO 	 * for it.
114ca26842eSHajimu UMEMOTO 	 */
115ca26842eSHajimu UMEMOTO 	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
116ca26842eSHajimu UMEMOTO 		alloclen = sizeof (struct sockaddr_in6);
117ca26842eSHajimu UMEMOTO 		oldv6size = 1;
118ca26842eSHajimu UMEMOTO 	}
119ca26842eSHajimu UMEMOTO #endif
120ca26842eSHajimu UMEMOTO 
1215b13e781SHajimu UMEMOTO 	MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
122ca26842eSHajimu UMEMOTO 
1234b7ef73dSDag-Erling Smørgrav 	if ((error = copyin(osa, kosa, *osalen)))
124ca26842eSHajimu UMEMOTO 		goto out;
125ca26842eSHajimu UMEMOTO 
126ca26842eSHajimu UMEMOTO 	bdom = linux_to_bsd_domain(kosa->sa_family);
127ca26842eSHajimu UMEMOTO 	if (bdom == -1) {
128ca26842eSHajimu UMEMOTO 		error = EINVAL;
129ca26842eSHajimu UMEMOTO 		goto out;
130ca26842eSHajimu UMEMOTO 	}
131ca26842eSHajimu UMEMOTO 
132ca26842eSHajimu UMEMOTO #ifdef INET6
133ca26842eSHajimu UMEMOTO 	/*
134ca26842eSHajimu UMEMOTO 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
135ca26842eSHajimu UMEMOTO 	 * which lacks the scope id compared with RFC2553 one. If we detect
136ca26842eSHajimu UMEMOTO 	 * the situation, reject the address and write a message to system log.
137ca26842eSHajimu UMEMOTO 	 *
138ca26842eSHajimu UMEMOTO 	 * Still accept addresses for which the scope id is not used.
139ca26842eSHajimu UMEMOTO 	 */
140ca26842eSHajimu UMEMOTO 	if (oldv6size && bdom == AF_INET6) {
141ca26842eSHajimu UMEMOTO 		sin6 = (struct sockaddr_in6 *)kosa;
142ca26842eSHajimu UMEMOTO 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
143ca26842eSHajimu UMEMOTO 		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
144ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
145ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
146ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
147ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
148ca26842eSHajimu UMEMOTO 			sin6->sin6_scope_id = 0;
149ca26842eSHajimu UMEMOTO 		} else {
150ca26842eSHajimu UMEMOTO 			log(LOG_DEBUG,
1513c616032SGleb Smirnoff 			    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
152ca26842eSHajimu UMEMOTO 			error = EINVAL;
153ca26842eSHajimu UMEMOTO 			goto out;
154ca26842eSHajimu UMEMOTO 		}
155ca26842eSHajimu UMEMOTO 	} else
156ca26842eSHajimu UMEMOTO #endif
157ca26842eSHajimu UMEMOTO 	if (bdom == AF_INET)
158ca26842eSHajimu UMEMOTO 		alloclen = sizeof(struct sockaddr_in);
159ca26842eSHajimu UMEMOTO 
160ca26842eSHajimu UMEMOTO 	sa = (struct sockaddr *) kosa;
161ca26842eSHajimu UMEMOTO 	sa->sa_family = bdom;
162ca26842eSHajimu UMEMOTO 	sa->sa_len = alloclen;
163ca26842eSHajimu UMEMOTO 
164ca26842eSHajimu UMEMOTO 	*sap = sa;
165ca26842eSHajimu UMEMOTO 	*osalen = alloclen;
166ca26842eSHajimu UMEMOTO 	return (0);
167ca26842eSHajimu UMEMOTO 
168ca26842eSHajimu UMEMOTO out:
169ca26842eSHajimu UMEMOTO 	FREE(kosa, mtype);
170ca26842eSHajimu UMEMOTO 	return (error);
171ca26842eSHajimu UMEMOTO }
172ca26842eSHajimu UMEMOTO 
173c21dee17SSøren Schmidt static int
174c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
175c21dee17SSøren Schmidt {
1763f3a4815SMarcel Moolenaar 
177c21dee17SSøren Schmidt 	switch (domain) {
178c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
1793f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
180c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
1813f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
182c21dee17SSøren Schmidt 	case LINUX_AF_INET:
1833f3a4815SMarcel Moolenaar 		return (AF_INET);
184ca26842eSHajimu UMEMOTO 	case LINUX_AF_INET6:
185ca26842eSHajimu UMEMOTO 		return (AF_INET6);
186c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
1873f3a4815SMarcel Moolenaar 		return (AF_CCITT);
188c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
1893f3a4815SMarcel Moolenaar 		return (AF_IPX);
190c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
1913f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
192c21dee17SSøren Schmidt 	}
1933f3a4815SMarcel Moolenaar 	return (-1);
194c21dee17SSøren Schmidt }
195c21dee17SSøren Schmidt 
196ca26842eSHajimu UMEMOTO static int
197ca26842eSHajimu UMEMOTO bsd_to_linux_domain(int domain)
198ca26842eSHajimu UMEMOTO {
199ca26842eSHajimu UMEMOTO 
200ca26842eSHajimu UMEMOTO 	switch (domain) {
201ca26842eSHajimu UMEMOTO 	case AF_UNSPEC:
202ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNSPEC);
203ca26842eSHajimu UMEMOTO 	case AF_LOCAL:
204ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNIX);
205ca26842eSHajimu UMEMOTO 	case AF_INET:
206ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET);
207ca26842eSHajimu UMEMOTO 	case AF_INET6:
208ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET6);
209ca26842eSHajimu UMEMOTO 	case AF_CCITT:
210ca26842eSHajimu UMEMOTO 		return (LINUX_AF_AX25);
211ca26842eSHajimu UMEMOTO 	case AF_IPX:
212ca26842eSHajimu UMEMOTO 		return (LINUX_AF_IPX);
213ca26842eSHajimu UMEMOTO 	case AF_APPLETALK:
214ca26842eSHajimu UMEMOTO 		return (LINUX_AF_APPLETALK);
215ca26842eSHajimu UMEMOTO 	}
216ca26842eSHajimu UMEMOTO 	return (-1);
217ca26842eSHajimu UMEMOTO }
218ca26842eSHajimu UMEMOTO 
219c21dee17SSøren Schmidt static int
220c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
221c21dee17SSøren Schmidt {
2223f3a4815SMarcel Moolenaar 
223c21dee17SSøren Schmidt 	switch (level) {
224c21dee17SSøren Schmidt 	case LINUX_SOL_SOCKET:
2253f3a4815SMarcel Moolenaar 		return (SOL_SOCKET);
226c21dee17SSøren Schmidt 	}
2273f3a4815SMarcel Moolenaar 	return (level);
228c21dee17SSøren Schmidt }
229c21dee17SSøren Schmidt 
2303f3a4815SMarcel Moolenaar static int
23184b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level)
23284b11cd8SMitsuru IWASAKI {
23384b11cd8SMitsuru IWASAKI 
23484b11cd8SMitsuru IWASAKI 	switch (level) {
23584b11cd8SMitsuru IWASAKI 	case SOL_SOCKET:
23684b11cd8SMitsuru IWASAKI 		return (LINUX_SOL_SOCKET);
23784b11cd8SMitsuru IWASAKI 	}
23884b11cd8SMitsuru IWASAKI 	return (level);
23984b11cd8SMitsuru IWASAKI }
24084b11cd8SMitsuru IWASAKI 
24184b11cd8SMitsuru IWASAKI static int
2423f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
243c21dee17SSøren Schmidt {
2443f3a4815SMarcel Moolenaar 
245c21dee17SSøren Schmidt 	switch (opt) {
246c21dee17SSøren Schmidt 	case LINUX_IP_TOS:
2473f3a4815SMarcel Moolenaar 		return (IP_TOS);
248c21dee17SSøren Schmidt 	case LINUX_IP_TTL:
2493f3a4815SMarcel Moolenaar 		return (IP_TTL);
25066ff6a3cSBill Fenner 	case LINUX_IP_OPTIONS:
2513f3a4815SMarcel Moolenaar 		return (IP_OPTIONS);
25266ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_IF:
2533f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_IF);
25466ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_TTL:
2553f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_TTL);
25666ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_LOOP:
2573f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_LOOP);
25866ff6a3cSBill Fenner 	case LINUX_IP_ADD_MEMBERSHIP:
2593f3a4815SMarcel Moolenaar 		return (IP_ADD_MEMBERSHIP);
26066ff6a3cSBill Fenner 	case LINUX_IP_DROP_MEMBERSHIP:
2613f3a4815SMarcel Moolenaar 		return (IP_DROP_MEMBERSHIP);
26266ff6a3cSBill Fenner 	case LINUX_IP_HDRINCL:
2633f3a4815SMarcel Moolenaar 		return (IP_HDRINCL);
264c21dee17SSøren Schmidt 	}
2653f3a4815SMarcel Moolenaar 	return (-1);
266c21dee17SSøren Schmidt }
267c21dee17SSøren Schmidt 
268c21dee17SSøren Schmidt static int
269c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
270c21dee17SSøren Schmidt {
2713f3a4815SMarcel Moolenaar 
272c21dee17SSøren Schmidt 	switch (opt) {
273c21dee17SSøren Schmidt 	case LINUX_SO_DEBUG:
2743f3a4815SMarcel Moolenaar 		return (SO_DEBUG);
275c21dee17SSøren Schmidt 	case LINUX_SO_REUSEADDR:
2763f3a4815SMarcel Moolenaar 		return (SO_REUSEADDR);
277c21dee17SSøren Schmidt 	case LINUX_SO_TYPE:
2783f3a4815SMarcel Moolenaar 		return (SO_TYPE);
279c21dee17SSøren Schmidt 	case LINUX_SO_ERROR:
2803f3a4815SMarcel Moolenaar 		return (SO_ERROR);
281c21dee17SSøren Schmidt 	case LINUX_SO_DONTROUTE:
2823f3a4815SMarcel Moolenaar 		return (SO_DONTROUTE);
283c21dee17SSøren Schmidt 	case LINUX_SO_BROADCAST:
2843f3a4815SMarcel Moolenaar 		return (SO_BROADCAST);
285c21dee17SSøren Schmidt 	case LINUX_SO_SNDBUF:
2863f3a4815SMarcel Moolenaar 		return (SO_SNDBUF);
287c21dee17SSøren Schmidt 	case LINUX_SO_RCVBUF:
2883f3a4815SMarcel Moolenaar 		return (SO_RCVBUF);
289c21dee17SSøren Schmidt 	case LINUX_SO_KEEPALIVE:
2903f3a4815SMarcel Moolenaar 		return (SO_KEEPALIVE);
291c21dee17SSøren Schmidt 	case LINUX_SO_OOBINLINE:
2923f3a4815SMarcel Moolenaar 		return (SO_OOBINLINE);
293c21dee17SSøren Schmidt 	case LINUX_SO_LINGER:
2943f3a4815SMarcel Moolenaar 		return (SO_LINGER);
295c21dee17SSøren Schmidt 	}
2963f3a4815SMarcel Moolenaar 	return (-1);
297c21dee17SSøren Schmidt }
298c21dee17SSøren Schmidt 
29940dbba57SAssar Westerlund static int
30040dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
30140dbba57SAssar Westerlund {
30240dbba57SAssar Westerlund 	int ret_flags = 0;
30340dbba57SAssar Westerlund 
30440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
30540dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
30640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
30740dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
30840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
30940dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
31040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
31140dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
31240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
31340dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
31440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
31540dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
31640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
31740dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
31840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
31940dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
3208d6e40c3SMaxim Sobolev 	if (flags & LINUX_MSG_NOSIGNAL)
3218d6e40c3SMaxim Sobolev 		ret_flags |= MSG_NOSIGNAL;
32240dbba57SAssar Westerlund #if 0 /* not handled */
32340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
32440dbba57SAssar Westerlund 		;
32540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
32640dbba57SAssar Westerlund 		;
32740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
32840dbba57SAssar Westerlund 		;
32940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
33040dbba57SAssar Westerlund 		;
33140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
33240dbba57SAssar Westerlund 		;
33340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
33440dbba57SAssar Westerlund 		;
33540dbba57SAssar Westerlund #endif
33640dbba57SAssar Westerlund 	return ret_flags;
33740dbba57SAssar Westerlund }
33840dbba57SAssar Westerlund 
3395c8919adSAlexander Leidinger /*
3405c8919adSAlexander Leidinger * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
3415c8919adSAlexander Leidinger * native syscall will fault.  Thus, we don't really need to check the
3425c8919adSAlexander Leidinger * return values for these functions.
3435c8919adSAlexander Leidinger */
3445c8919adSAlexander Leidinger 
3455c8919adSAlexander Leidinger static int
3465c8919adSAlexander Leidinger bsd_to_linux_sockaddr(struct sockaddr *arg)
3475c8919adSAlexander Leidinger {
3485c8919adSAlexander Leidinger 	struct sockaddr sa;
3495c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
3505c8919adSAlexander Leidinger 	int error;
3515c8919adSAlexander Leidinger 
3525c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
3535c8919adSAlexander Leidinger 		return (error);
3545c8919adSAlexander Leidinger 
3555c8919adSAlexander Leidinger 	*(u_short *)&sa = sa.sa_family;
3565c8919adSAlexander Leidinger 
3575c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
3585c8919adSAlexander Leidinger 
3595c8919adSAlexander Leidinger 	return (error);
3605c8919adSAlexander Leidinger }
3615c8919adSAlexander Leidinger 
3625c8919adSAlexander Leidinger static int
3635c8919adSAlexander Leidinger linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
3645c8919adSAlexander Leidinger {
3655c8919adSAlexander Leidinger 	struct sockaddr sa;
3665c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
3675c8919adSAlexander Leidinger 	int error;
3685c8919adSAlexander Leidinger 
3695c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
3705c8919adSAlexander Leidinger 		return (error);
3715c8919adSAlexander Leidinger 
3725c8919adSAlexander Leidinger 	sa.sa_family = *(sa_family_t *)&sa;
3735c8919adSAlexander Leidinger 	sa.sa_len = len;
3745c8919adSAlexander Leidinger 
3755c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
3765c8919adSAlexander Leidinger 
3775c8919adSAlexander Leidinger 	return (error);
3785c8919adSAlexander Leidinger }
3795c8919adSAlexander Leidinger 
3805c8919adSAlexander Leidinger 
381ca26842eSHajimu UMEMOTO static int
382ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa)
383ca26842eSHajimu UMEMOTO {
384ca26842eSHajimu UMEMOTO 	struct osockaddr sa;
385ca26842eSHajimu UMEMOTO 	int error, bdom;
386ca26842eSHajimu UMEMOTO 
387ca26842eSHajimu UMEMOTO 	/*
388ca26842eSHajimu UMEMOTO 	 * Only read/write the osockaddr family part, the rest is
389ca26842eSHajimu UMEMOTO 	 * not changed.
390ca26842eSHajimu UMEMOTO 	 */
3914b7ef73dSDag-Erling Smørgrav 	error = copyin(osa, &sa, sizeof(sa.sa_family));
392ca26842eSHajimu UMEMOTO 	if (error)
393ca26842eSHajimu UMEMOTO 		return (error);
394ca26842eSHajimu UMEMOTO 
395ca26842eSHajimu UMEMOTO 	bdom = bsd_to_linux_domain(sa.sa_family);
396ca26842eSHajimu UMEMOTO 	if (bdom == -1)
397ca26842eSHajimu UMEMOTO 		return (EINVAL);
398ca26842eSHajimu UMEMOTO 
399ca26842eSHajimu UMEMOTO 	sa.sa_family = bdom;
400ca26842eSHajimu UMEMOTO 	error = copyout(&sa, osa, sizeof(sa.sa_family));
401ca26842eSHajimu UMEMOTO 	if (error)
402ca26842eSHajimu UMEMOTO 		return (error);
403ca26842eSHajimu UMEMOTO 
404ca26842eSHajimu UMEMOTO 	return (0);
405ca26842eSHajimu UMEMOTO }
406ca26842eSHajimu UMEMOTO 
4075a8a13e0SDavid Malone static int
408a6886ef1SMaxim Sobolev linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
409a6886ef1SMaxim Sobolev     enum uio_seg segflg)
4105a8a13e0SDavid Malone {
4115a8a13e0SDavid Malone 	struct mbuf *control;
4125a8a13e0SDavid Malone 	struct sockaddr *to;
4135a8a13e0SDavid Malone 	int error;
4145a8a13e0SDavid Malone 
4155a8a13e0SDavid Malone 	if (mp->msg_name != NULL) {
4165a8a13e0SDavid Malone 		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
4175a8a13e0SDavid Malone 		if (error)
4185a8a13e0SDavid Malone 			return (error);
4195a8a13e0SDavid Malone 		mp->msg_name = to;
4205a8a13e0SDavid Malone 	} else
4215a8a13e0SDavid Malone 		to = NULL;
4225a8a13e0SDavid Malone 
4235a8a13e0SDavid Malone 	if (mp->msg_control != NULL) {
4245a8a13e0SDavid Malone 		struct cmsghdr *cmsg;
4255a8a13e0SDavid Malone 
4265a8a13e0SDavid Malone 		if (mp->msg_controllen < sizeof(struct cmsghdr)) {
4275a8a13e0SDavid Malone 			error = EINVAL;
4285a8a13e0SDavid Malone 			goto bad;
4295a8a13e0SDavid Malone 		}
4305a8a13e0SDavid Malone 		error = sockargs(&control, mp->msg_control,
4315a8a13e0SDavid Malone 		    mp->msg_controllen, MT_CONTROL);
4325a8a13e0SDavid Malone 		if (error)
4335a8a13e0SDavid Malone 			goto bad;
4345a8a13e0SDavid Malone 
4355a8a13e0SDavid Malone 		cmsg = mtod(control, struct cmsghdr *);
4365a8a13e0SDavid Malone 		cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level);
4375a8a13e0SDavid Malone 	} else
4385a8a13e0SDavid Malone 		control = NULL;
4395a8a13e0SDavid Malone 
440a6886ef1SMaxim Sobolev 	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
441a6886ef1SMaxim Sobolev 	    segflg);
4425a8a13e0SDavid Malone 
4435a8a13e0SDavid Malone bad:
4445a8a13e0SDavid Malone 	if (to)
4455a8a13e0SDavid Malone 		FREE(to, M_SONAME);
4465a8a13e0SDavid Malone 	return (error);
4475a8a13e0SDavid Malone }
4485a8a13e0SDavid Malone 
4493f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
450f2477ae1SMike Smith static int
451e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s)
452f2477ae1SMike Smith {
4533db2a843SBruce Evans 	int error, optval, size_val;
454f2477ae1SMike Smith 
455e140eb43SDavid Malone 	size_val = sizeof(optval);
456e140eb43SDavid Malone 	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
457e140eb43SDavid Malone 	    &optval, UIO_SYSSPACE, &size_val);
458e140eb43SDavid Malone 	if (error)
4593f3a4815SMarcel Moolenaar 		return (error);
4603f3a4815SMarcel Moolenaar 
4613f3a4815SMarcel Moolenaar 	return (optval == 0);
462f2477ae1SMike Smith }
463f2477ae1SMike Smith 
4645a8a13e0SDavid Malone struct linux_sendto_args {
4655a8a13e0SDavid Malone 	int s;
4664af27623STim J. Robbins 	l_uintptr_t msg;
4675a8a13e0SDavid Malone 	int len;
4685a8a13e0SDavid Malone 	int flags;
4694af27623STim J. Robbins 	l_uintptr_t to;
4705a8a13e0SDavid Malone 	int tolen;
4715a8a13e0SDavid Malone };
4725a8a13e0SDavid Malone 
473f2477ae1SMike Smith /*
474f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
475f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
476f2477ae1SMike Smith  */
477f2477ae1SMike Smith static int
47838da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
479f2477ae1SMike Smith {
480f2477ae1SMike Smith /*
481f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
482f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
483a6886ef1SMaxim Sobolev  * It should include all the fields we modify (ip_len and ip_off).
484f2477ae1SMike Smith  */
485f2477ae1SMike Smith #define linux_ip_copysize	8
486f2477ae1SMike Smith 
487f2477ae1SMike Smith 	struct ip *packet;
4885a8a13e0SDavid Malone 	struct msghdr msg;
489a6886ef1SMaxim Sobolev 	struct iovec aiov[1];
490f2477ae1SMike Smith 	int error;
491f2477ae1SMike Smith 
492aa675b57SDavid Schultz 	/* Check that the packet isn't too big or too small. */
493aa675b57SDavid Schultz 	if (linux_args->len < linux_ip_copysize ||
494aa675b57SDavid Schultz 	    linux_args->len > IP_MAXPACKET)
4953f3a4815SMarcel Moolenaar 		return (EINVAL);
496f2477ae1SMike Smith 
497a6886ef1SMaxim Sobolev 	packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
498f2477ae1SMike Smith 
499a6886ef1SMaxim Sobolev 	/* Make kernel copy of the packet to be sent */
5004af27623STim J. Robbins 	if ((error = copyin(PTRIN(linux_args->msg), packet,
501a6886ef1SMaxim Sobolev 	    linux_args->len)))
502a6886ef1SMaxim Sobolev 		goto goout;
503f2477ae1SMike Smith 
504f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
5055a8a13e0SDavid Malone 	packet->ip_len = linux_args->len;
506f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
507f2477ae1SMike Smith 
508f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
5094af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args->to);
5105a8a13e0SDavid Malone 	msg.msg_namelen = linux_args->tolen;
5115a8a13e0SDavid Malone 	msg.msg_iov = aiov;
512a6886ef1SMaxim Sobolev 	msg.msg_iovlen = 1;
5135a8a13e0SDavid Malone 	msg.msg_control = NULL;
5145a8a13e0SDavid Malone 	msg.msg_flags = 0;
5155a8a13e0SDavid Malone 	aiov[0].iov_base = (char *)packet;
516a6886ef1SMaxim Sobolev 	aiov[0].iov_len = linux_args->len;
517a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
518a6886ef1SMaxim Sobolev 	    UIO_SYSSPACE);
519a6886ef1SMaxim Sobolev goout:
520a6886ef1SMaxim Sobolev 	free(packet, M_TEMP);
5215a8a13e0SDavid Malone 	return (error);
522f2477ae1SMike Smith }
523f2477ae1SMike Smith 
524c21dee17SSøren Schmidt struct linux_socket_args {
525c21dee17SSøren Schmidt 	int domain;
526c21dee17SSøren Schmidt 	int type;
527c21dee17SSøren Schmidt 	int protocol;
528c21dee17SSøren Schmidt };
529c21dee17SSøren Schmidt 
530c21dee17SSøren Schmidt static int
531b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
532c21dee17SSøren Schmidt {
533c21dee17SSøren Schmidt 	struct linux_socket_args linux_args;
534ef04503dSPeter Wemm 	struct socket_args /* {
535c21dee17SSøren Schmidt 		int domain;
536c21dee17SSøren Schmidt 		int type;
537c21dee17SSøren Schmidt 		int protocol;
538ef04503dSPeter Wemm 	} */ bsd_args;
539c21dee17SSøren Schmidt 	int error;
540f2477ae1SMike Smith 	int retval_socket;
541c21dee17SSøren Schmidt 
5423f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5433f3a4815SMarcel Moolenaar 		return (error);
5443f3a4815SMarcel Moolenaar 
545c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
546c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
547c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
548c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
5493f3a4815SMarcel Moolenaar 		return (EINVAL);
550f2477ae1SMike Smith 
551b40ce416SJulian Elischer 	retval_socket = socket(td, &bsd_args);
552f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
553f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
554f2477ae1SMike Smith 	    && bsd_args.domain == AF_INET
555f2477ae1SMike Smith 	    && retval_socket >= 0) {
556f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
557e140eb43SDavid Malone 		int hdrincl;
558f2477ae1SMike Smith 
559e140eb43SDavid Malone 		hdrincl = 1;
560e140eb43SDavid Malone 		/* We ignore any error returned by kern_setsockopt() */
561e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
562e140eb43SDavid Malone 		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
563f2477ae1SMike Smith 	}
564ca26842eSHajimu UMEMOTO #ifdef INET6
565ca26842eSHajimu UMEMOTO 	/*
566ca26842eSHajimu UMEMOTO 	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
567ca26842eSHajimu UMEMOTO 	 * default and some apps depend on this. So, set V6ONLY to 0
568ca26842eSHajimu UMEMOTO 	 * for Linux apps if the sysctl value is set to 1.
569ca26842eSHajimu UMEMOTO 	 */
57037e7a5a2SHajimu UMEMOTO 	if (bsd_args.domain == PF_INET6 && retval_socket >= 0
57137e7a5a2SHajimu UMEMOTO #ifndef KLD_MODULE
57237e7a5a2SHajimu UMEMOTO 	    /*
57337e7a5a2SHajimu UMEMOTO 	     * XXX: Avoid undefined symbol error with an IPv4 only
57437e7a5a2SHajimu UMEMOTO 	     * kernel.
57537e7a5a2SHajimu UMEMOTO 	     */
57637e7a5a2SHajimu UMEMOTO 	    && ip6_v6only
57737e7a5a2SHajimu UMEMOTO #endif
57837e7a5a2SHajimu UMEMOTO 	    ) {
579e140eb43SDavid Malone 		int v6only;
580ca26842eSHajimu UMEMOTO 
581e140eb43SDavid Malone 		v6only = 0;
582ca26842eSHajimu UMEMOTO 		/* We ignore any error returned by setsockopt() */
583e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
584e140eb43SDavid Malone 		    &v6only, UIO_SYSSPACE, sizeof(v6only));
585ca26842eSHajimu UMEMOTO 	}
586ca26842eSHajimu UMEMOTO #endif
5873f3a4815SMarcel Moolenaar 
5883f3a4815SMarcel Moolenaar 	return (retval_socket);
589c21dee17SSøren Schmidt }
590c21dee17SSøren Schmidt 
591c21dee17SSøren Schmidt struct linux_bind_args {
592c21dee17SSøren Schmidt 	int s;
5934af27623STim J. Robbins 	l_uintptr_t name;
594c21dee17SSøren Schmidt 	int namelen;
595c21dee17SSøren Schmidt };
596c21dee17SSøren Schmidt 
597c21dee17SSøren Schmidt static int
598b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
599c21dee17SSøren Schmidt {
600c21dee17SSøren Schmidt 	struct linux_bind_args linux_args;
601ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
602c21dee17SSøren Schmidt 	int error;
603c21dee17SSøren Schmidt 
6043f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6053f3a4815SMarcel Moolenaar 		return (error);
6063f3a4815SMarcel Moolenaar 
6074af27623STim J. Robbins 	error = linux_getsockaddr(&sa, PTRIN(linux_args.name),
6084af27623STim J. Robbins 	    linux_args.namelen);
609ca26842eSHajimu UMEMOTO 	if (error)
610ca26842eSHajimu UMEMOTO 		return (error);
611ca26842eSHajimu UMEMOTO 
612ca26842eSHajimu UMEMOTO 	return (kern_bind(td, linux_args.s, sa));
613c21dee17SSøren Schmidt }
614c21dee17SSøren Schmidt 
61501e0ffbaSAlexander Leidinger struct linux_connect_args {
616c21dee17SSøren Schmidt 	int s;
6174af27623STim J. Robbins 	l_uintptr_t name;
618c21dee17SSøren Schmidt 	int namelen;
619c21dee17SSøren Schmidt };
620b40ce416SJulian Elischer int linux_connect(struct thread *, struct linux_connect_args *);
621c21dee17SSøren Schmidt 
622930a65feSAndrew Gallatin int
623b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
624c21dee17SSøren Schmidt {
62501e0ffbaSAlexander Leidinger 	struct linux_connect_args linux_args;
6260bf301c0SJonathan Lemon 	struct socket *so;
627ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
62839c95b83SMatthew Dillon 	u_int fflag;
629c21dee17SSøren Schmidt 	int error;
630c21dee17SSøren Schmidt 
6313f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6323f3a4815SMarcel Moolenaar 		return (error);
6333f3a4815SMarcel Moolenaar 
6344af27623STim J. Robbins 	error = linux_getsockaddr(&sa,
6354af27623STim J. Robbins 	    (struct osockaddr *)PTRIN(linux_args.name),
6364d45de74SDavid Malone 	    linux_args.namelen);
637ca26842eSHajimu UMEMOTO 	if (error)
638ca26842eSHajimu UMEMOTO 		return (error);
639ca26842eSHajimu UMEMOTO 
640ca26842eSHajimu UMEMOTO 	error = kern_connect(td, linux_args.s, sa);
6410bf301c0SJonathan Lemon 	if (error != EISCONN)
6420bf301c0SJonathan Lemon 		return (error);
6430bf301c0SJonathan Lemon 
644dad3b88aSMike Smith 	/*
645dad3b88aSMike Smith 	 * Linux doesn't return EISCONN the first time it occurs,
646dad3b88aSMike Smith 	 * when on a non-blocking socket. Instead it returns the
647dad3b88aSMike Smith 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
648f7f45ac8SRobert Watson 	 *
649f7f45ac8SRobert Watson 	 * XXXRW: Instead of using fgetsock(), check that it is a
650f7f45ac8SRobert Watson 	 * socket and use the file descriptor reference instead of
651f7f45ac8SRobert Watson 	 * creating a new one.
652dad3b88aSMike Smith 	 */
6534641373fSJohn Baldwin 	NET_LOCK_GIANT();
6544641373fSJohn Baldwin 	error = fgetsock(td, linux_args.s, &so, &fflag);
6554641373fSJohn Baldwin 	if (error == 0) {
6560bf301c0SJonathan Lemon 		error = EISCONN;
65739c95b83SMatthew Dillon 		if (fflag & FNONBLOCK) {
6584641373fSJohn Baldwin 			SOCK_LOCK(so);
6595002a60fSMarcel Moolenaar 			if (so->so_emuldata == 0)
6600bf301c0SJonathan Lemon 				error = so->so_error;
6610bf301c0SJonathan Lemon 			so->so_emuldata = (void *)1;
6624641373fSJohn Baldwin 			SOCK_UNLOCK(so);
663dad3b88aSMike Smith 		}
66439c95b83SMatthew Dillon 		fputsock(so);
6654641373fSJohn Baldwin 	}
6664641373fSJohn Baldwin 	NET_UNLOCK_GIANT();
6673f3a4815SMarcel Moolenaar 	return (error);
668c21dee17SSøren Schmidt }
669c21dee17SSøren Schmidt 
670c21dee17SSøren Schmidt struct linux_listen_args {
671c21dee17SSøren Schmidt 	int s;
672c21dee17SSøren Schmidt 	int backlog;
673c21dee17SSøren Schmidt };
674c21dee17SSøren Schmidt 
675c21dee17SSøren Schmidt static int
676b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
677c21dee17SSøren Schmidt {
678c21dee17SSøren Schmidt 	struct linux_listen_args linux_args;
679ef04503dSPeter Wemm 	struct listen_args /* {
680c21dee17SSøren Schmidt 		int s;
681c21dee17SSøren Schmidt 		int backlog;
682ef04503dSPeter Wemm 	} */ bsd_args;
683c21dee17SSøren Schmidt 	int error;
684c21dee17SSøren Schmidt 
6853f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6863f3a4815SMarcel Moolenaar 		return (error);
6873f3a4815SMarcel Moolenaar 
688c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
689c21dee17SSøren Schmidt 	bsd_args.backlog = linux_args.backlog;
690b40ce416SJulian Elischer 	return (listen(td, &bsd_args));
691c21dee17SSøren Schmidt }
692c21dee17SSøren Schmidt 
69301e0ffbaSAlexander Leidinger struct linux_accept_args {
694c21dee17SSøren Schmidt 	int s;
6954af27623STim J. Robbins 	l_uintptr_t addr;
6964af27623STim J. Robbins 	l_uintptr_t namelen;
697c21dee17SSøren Schmidt };
698c21dee17SSøren Schmidt 
69901e0ffbaSAlexander Leidinger static int
700b40ce416SJulian Elischer linux_accept(struct thread *td, struct linux_accept_args *args)
701c21dee17SSøren Schmidt {
70201e0ffbaSAlexander Leidinger 	struct linux_accept_args linux_args;
703ef04503dSPeter Wemm 	struct accept_args /* {
704c21dee17SSøren Schmidt 		int	s;
7053db2a843SBruce Evans 		struct sockaddr * __restrict name;
7063db2a843SBruce Evans 		socklen_t * __restrict anamelen;
707ef04503dSPeter Wemm 	} */ bsd_args;
7082ca25ab5SJohn Baldwin 	int error, fd;
709c21dee17SSøren Schmidt 
7103f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7113f3a4815SMarcel Moolenaar 		return (error);
7123f3a4815SMarcel Moolenaar 
713c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
7143db2a843SBruce Evans 	/* XXX: */
7154af27623STim J. Robbins 	bsd_args.name = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
7164af27623STim J. Robbins 	bsd_args.anamelen = PTRIN(linux_args.namelen);/* XXX */
7175c8919adSAlexander Leidinger 	error = accept(td, &bsd_args);
7185c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
719dba5ab66SMarcel Moolenaar 	if (error)
720dba5ab66SMarcel Moolenaar 		return (error);
721ca26842eSHajimu UMEMOTO 	if (linux_args.addr) {
7224af27623STim J. Robbins 		error = linux_sa_put(PTRIN(linux_args.addr));
723ca26842eSHajimu UMEMOTO 		if (error) {
724c1cccebeSJohn Baldwin 			(void)kern_close(td, td->td_retval[0]);
725ca26842eSHajimu UMEMOTO 			return (error);
726ca26842eSHajimu UMEMOTO 		}
727ca26842eSHajimu UMEMOTO 	}
728dba5ab66SMarcel Moolenaar 
729dba5ab66SMarcel Moolenaar 	/*
730dba5ab66SMarcel Moolenaar 	 * linux appears not to copy flags from the parent socket to the
731dba5ab66SMarcel Moolenaar 	 * accepted one, so we must clear the flags in the new descriptor.
732dba5ab66SMarcel Moolenaar 	 * Ignore any errors, because we already have an open fd.
733dba5ab66SMarcel Moolenaar 	 */
7342ca25ab5SJohn Baldwin 	fd = td->td_retval[0];
7352ca25ab5SJohn Baldwin 	(void)kern_fcntl(td, fd, F_SETFL, 0);
7362ca25ab5SJohn Baldwin 	td->td_retval[0] = fd;
737dba5ab66SMarcel Moolenaar 	return (0);
738c21dee17SSøren Schmidt }
739c21dee17SSøren Schmidt 
74001e0ffbaSAlexander Leidinger struct linux_getsockname_args {
741c21dee17SSøren Schmidt 	int s;
7424af27623STim J. Robbins 	l_uintptr_t addr;
7434af27623STim J. Robbins 	l_uintptr_t namelen;
744c21dee17SSøren Schmidt };
745c21dee17SSøren Schmidt 
74601e0ffbaSAlexander Leidinger static int
747b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
748c21dee17SSøren Schmidt {
74901e0ffbaSAlexander Leidinger 	struct linux_getsockname_args linux_args;
750ef04503dSPeter Wemm 	struct getsockname_args /* {
751c21dee17SSøren Schmidt 		int	fdes;
7523db2a843SBruce Evans 		struct sockaddr * __restrict asa;
7533db2a843SBruce Evans 		socklen_t * __restrict alen;
754ef04503dSPeter Wemm 	} */ bsd_args;
755c21dee17SSøren Schmidt 	int error;
756c21dee17SSøren Schmidt 
7573f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7583f3a4815SMarcel Moolenaar 		return (error);
7593f3a4815SMarcel Moolenaar 
760c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
7613db2a843SBruce Evans 	/* XXX: */
7624af27623STim J. Robbins 	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
7634af27623STim J. Robbins 	bsd_args.alen = PTRIN(linux_args.namelen);	/* XXX */
7645c8919adSAlexander Leidinger 	error = getsockname(td, &bsd_args);
7655c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
766ca26842eSHajimu UMEMOTO 	if (error)
767ca26842eSHajimu UMEMOTO 		return (error);
7684af27623STim J. Robbins 	error = linux_sa_put(PTRIN(linux_args.addr));
769ca26842eSHajimu UMEMOTO 	if (error)
770ca26842eSHajimu UMEMOTO 		return (error);
771ca26842eSHajimu UMEMOTO 	return (0);
772c21dee17SSøren Schmidt }
773c21dee17SSøren Schmidt 
77401e0ffbaSAlexander Leidinger struct linux_getpeername_args {
775c21dee17SSøren Schmidt 	int s;
7764af27623STim J. Robbins 	l_uintptr_t addr;
7774af27623STim J. Robbins 	l_uintptr_t namelen;
778c21dee17SSøren Schmidt };
779c21dee17SSøren Schmidt 
78001e0ffbaSAlexander Leidinger static int
781b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
782c21dee17SSøren Schmidt {
78301e0ffbaSAlexander Leidinger 	struct linux_getpeername_args linux_args;
7845c8919adSAlexander Leidinger 	struct getpeername_args /* {
785c21dee17SSøren Schmidt 		int fdes;
786c21dee17SSøren Schmidt 		caddr_t asa;
787c21dee17SSøren Schmidt 		int *alen;
788ef04503dSPeter Wemm 	} */ bsd_args;
789c21dee17SSøren Schmidt 	int error;
790c21dee17SSøren Schmidt 
7913f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7923f3a4815SMarcel Moolenaar 		return (error);
7933f3a4815SMarcel Moolenaar 
794c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
7955c8919adSAlexander Leidinger 	bsd_args.asa = (struct sockaddr *)PTRIN(linux_args.addr);
7964af27623STim J. Robbins 	bsd_args.alen = (int *)PTRIN(linux_args.namelen);
7975c8919adSAlexander Leidinger 	error = getpeername(td, &bsd_args);
7985c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
799ca26842eSHajimu UMEMOTO 	if (error)
800ca26842eSHajimu UMEMOTO 		return (error);
8014af27623STim J. Robbins 	error = linux_sa_put(PTRIN(linux_args.addr));
802ca26842eSHajimu UMEMOTO 	if (error)
803ca26842eSHajimu UMEMOTO 		return (error);
804ca26842eSHajimu UMEMOTO 	return (0);
805c21dee17SSøren Schmidt }
806c21dee17SSøren Schmidt 
80701e0ffbaSAlexander Leidinger struct linux_socketpair_args {
808c21dee17SSøren Schmidt 	int domain;
809c21dee17SSøren Schmidt 	int type;
810c21dee17SSøren Schmidt 	int protocol;
8114af27623STim J. Robbins 	l_uintptr_t rsv;
812c21dee17SSøren Schmidt };
813c21dee17SSøren Schmidt 
81401e0ffbaSAlexander Leidinger static int
815b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
816c21dee17SSøren Schmidt {
81701e0ffbaSAlexander Leidinger 	struct linux_socketpair_args linux_args;
818ef04503dSPeter Wemm 	struct socketpair_args /* {
819c21dee17SSøren Schmidt 		int domain;
820c21dee17SSøren Schmidt 		int type;
821c21dee17SSøren Schmidt 		int protocol;
822c21dee17SSøren Schmidt 		int *rsv;
823ef04503dSPeter Wemm 	} */ bsd_args;
824c21dee17SSøren Schmidt 	int error;
825c21dee17SSøren Schmidt 
8263f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8273f3a4815SMarcel Moolenaar 		return (error);
8283f3a4815SMarcel Moolenaar 
829c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
830c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
8313f3a4815SMarcel Moolenaar 		return (EINVAL);
8323f3a4815SMarcel Moolenaar 
833c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
834c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
8354af27623STim J. Robbins 	bsd_args.rsv = (int *)PTRIN(linux_args.rsv);
836b40ce416SJulian Elischer 	return (socketpair(td, &bsd_args));
837c21dee17SSøren Schmidt }
838c21dee17SSøren Schmidt 
83901e0ffbaSAlexander Leidinger struct linux_send_args {
840c21dee17SSøren Schmidt 	int s;
8414af27623STim J. Robbins 	l_uintptr_t msg;
842c21dee17SSøren Schmidt 	int len;
843c21dee17SSøren Schmidt 	int flags;
844c21dee17SSøren Schmidt };
845c21dee17SSøren Schmidt 
84601e0ffbaSAlexander Leidinger static int
847b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
848c21dee17SSøren Schmidt {
84901e0ffbaSAlexander Leidinger 	struct linux_send_args linux_args;
85087d72a8fSPoul-Henning Kamp 	struct sendto_args /* {
851c21dee17SSøren Schmidt 		int s;
852c21dee17SSøren Schmidt 		caddr_t buf;
853044af7c3SJonathan Mini 		int len;
854c21dee17SSøren Schmidt 		int flags;
85587d72a8fSPoul-Henning Kamp 		caddr_t to;
85687d72a8fSPoul-Henning Kamp 		int tolen;
857ef04503dSPeter Wemm 	} */ bsd_args;
8588d6e40c3SMaxim Sobolev 	int error;
859c21dee17SSøren Schmidt 
8603f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8613f3a4815SMarcel Moolenaar 		return (error);
8623f3a4815SMarcel Moolenaar 
863c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
8644af27623STim J. Robbins 	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
865c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
866c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
86787d72a8fSPoul-Henning Kamp 	bsd_args.to = NULL;
86887d72a8fSPoul-Henning Kamp 	bsd_args.tolen = 0;
8698d6e40c3SMaxim Sobolev 	return sendto(td, &bsd_args);
870c21dee17SSøren Schmidt }
871c21dee17SSøren Schmidt 
87201e0ffbaSAlexander Leidinger struct linux_recv_args {
873c21dee17SSøren Schmidt 	int s;
8744af27623STim J. Robbins 	l_uintptr_t msg;
875c21dee17SSøren Schmidt 	int len;
876c21dee17SSøren Schmidt 	int flags;
877c21dee17SSøren Schmidt };
878c21dee17SSøren Schmidt 
87901e0ffbaSAlexander Leidinger static int
880b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
881c21dee17SSøren Schmidt {
88201e0ffbaSAlexander Leidinger 	struct linux_recv_args linux_args;
88387d72a8fSPoul-Henning Kamp 	struct recvfrom_args /* {
884c21dee17SSøren Schmidt 		int s;
885c21dee17SSøren Schmidt 		caddr_t buf;
886c21dee17SSøren Schmidt 		int len;
887c21dee17SSøren Schmidt 		int flags;
88887d72a8fSPoul-Henning Kamp 		struct sockaddr *from;
88987d72a8fSPoul-Henning Kamp 		socklen_t fromlenaddr;
890ef04503dSPeter Wemm 	} */ bsd_args;
891c21dee17SSøren Schmidt 	int error;
892c21dee17SSøren Schmidt 
8933f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8943f3a4815SMarcel Moolenaar 		return (error);
8953f3a4815SMarcel Moolenaar 
896c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
8974af27623STim J. Robbins 	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
898c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
899c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
90087d72a8fSPoul-Henning Kamp 	bsd_args.from = NULL;
90187d72a8fSPoul-Henning Kamp 	bsd_args.fromlenaddr = 0;
90287d72a8fSPoul-Henning Kamp 	return (recvfrom(td, &bsd_args));
903c21dee17SSøren Schmidt }
904c21dee17SSøren Schmidt 
905c21dee17SSøren Schmidt static int
906b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
907c21dee17SSøren Schmidt {
908c21dee17SSøren Schmidt 	struct linux_sendto_args linux_args;
9095a8a13e0SDavid Malone 	struct msghdr msg;
9105a8a13e0SDavid Malone 	struct iovec aiov;
9115a8a13e0SDavid Malone 	int error;
912c21dee17SSøren Schmidt 
9133f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
9143f3a4815SMarcel Moolenaar 		return (error);
9153f3a4815SMarcel Moolenaar 
916e140eb43SDavid Malone 	if (linux_check_hdrincl(td, linux_args.s) == 0)
917f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
918e140eb43SDavid Malone 		return (linux_sendto_hdrincl(td, &linux_args));
919f2477ae1SMike Smith 
9204af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args.to);
9215a8a13e0SDavid Malone 	msg.msg_namelen = linux_args.tolen;
9225a8a13e0SDavid Malone 	msg.msg_iov = &aiov;
9235a8a13e0SDavid Malone 	msg.msg_iovlen = 1;
9245a8a13e0SDavid Malone 	msg.msg_control = NULL;
9255a8a13e0SDavid Malone 	msg.msg_flags = 0;
9264af27623STim J. Robbins 	aiov.iov_base = PTRIN(linux_args.msg);
9275a8a13e0SDavid Malone 	aiov.iov_len = linux_args.len;
928a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
929a6886ef1SMaxim Sobolev 	    UIO_USERSPACE);
9305a8a13e0SDavid Malone 	return (error);
931c21dee17SSøren Schmidt }
932c21dee17SSøren Schmidt 
93301e0ffbaSAlexander Leidinger struct linux_recvfrom_args {
934c21dee17SSøren Schmidt 	int s;
9354af27623STim J. Robbins 	l_uintptr_t buf;
936c21dee17SSøren Schmidt 	int len;
937c21dee17SSøren Schmidt 	int flags;
9384af27623STim J. Robbins 	l_uintptr_t from;
9394af27623STim J. Robbins 	l_uintptr_t fromlen;
940c21dee17SSøren Schmidt };
941c21dee17SSøren Schmidt 
94201e0ffbaSAlexander Leidinger static int
943b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
944c21dee17SSøren Schmidt {
94501e0ffbaSAlexander Leidinger 	struct linux_recvfrom_args linux_args;
946ef04503dSPeter Wemm 	struct recvfrom_args /* {
947c21dee17SSøren Schmidt 		int	s;
948c21dee17SSøren Schmidt 		caddr_t	buf;
949c21dee17SSøren Schmidt 		size_t	len;
950c21dee17SSøren Schmidt 		int	flags;
9513db2a843SBruce Evans 		struct sockaddr * __restrict from;
9523db2a843SBruce Evans 		socklen_t * __restrict fromlenaddr;
953ef04503dSPeter Wemm 	} */ bsd_args;
9545c8919adSAlexander Leidinger 	size_t len;
955c21dee17SSøren Schmidt 	int error;
956c21dee17SSøren Schmidt 
9573f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
9583f3a4815SMarcel Moolenaar 		return (error);
9593f3a4815SMarcel Moolenaar 
9605c8919adSAlexander Leidinger 	if ((error = copyin(PTRIN(linux_args.fromlen), &len, sizeof(size_t))))
9615c8919adSAlexander Leidinger 		return (error);
9625c8919adSAlexander Leidinger 
963c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
9644af27623STim J. Robbins 	bsd_args.buf = PTRIN(linux_args.buf);
965c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
96640dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
9673db2a843SBruce Evans 	/* XXX: */
9684af27623STim J. Robbins 	bsd_args.from = (struct sockaddr * __restrict)PTRIN(linux_args.from);
9694af27623STim J. Robbins 	bsd_args.fromlenaddr = PTRIN(linux_args.fromlen);/* XXX */
9705c8919adSAlexander Leidinger 
9715c8919adSAlexander Leidinger 	linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
9725c8919adSAlexander Leidinger 	error = recvfrom(td, &bsd_args);
9735c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
9745c8919adSAlexander Leidinger 
975ca26842eSHajimu UMEMOTO 	if (error)
976ca26842eSHajimu UMEMOTO 		return (error);
977ca26842eSHajimu UMEMOTO 	if (linux_args.from) {
9784af27623STim J. Robbins 		error = linux_sa_put((struct osockaddr *)
9794af27623STim J. Robbins 		    PTRIN(linux_args.from));
980ca26842eSHajimu UMEMOTO 		if (error)
981ca26842eSHajimu UMEMOTO 			return (error);
982ca26842eSHajimu UMEMOTO 	}
983ca26842eSHajimu UMEMOTO 	return (0);
984ca26842eSHajimu UMEMOTO }
985ca26842eSHajimu UMEMOTO 
98601e0ffbaSAlexander Leidinger struct linux_sendmsg_args {
987ca26842eSHajimu UMEMOTO 	int s;
9884af27623STim J. Robbins 	l_uintptr_t msg;
989ca26842eSHajimu UMEMOTO 	int flags;
990ca26842eSHajimu UMEMOTO };
991ca26842eSHajimu UMEMOTO 
99201e0ffbaSAlexander Leidinger static int
993ca26842eSHajimu UMEMOTO linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
994ca26842eSHajimu UMEMOTO {
99501e0ffbaSAlexander Leidinger 	struct linux_sendmsg_args linux_args;
996ca26842eSHajimu UMEMOTO 	struct msghdr msg;
997552afd9cSPoul-Henning Kamp 	struct iovec *iov;
998ca26842eSHajimu UMEMOTO 	int error;
999ca26842eSHajimu UMEMOTO 
10004af27623STim J. Robbins 	/* XXXTJR sendmsg is broken on amd64 */
10014af27623STim J. Robbins 
1002552afd9cSPoul-Henning Kamp 	error = copyin(args, &linux_args, sizeof(linux_args));
1003552afd9cSPoul-Henning Kamp 	if (error)
1004ca26842eSHajimu UMEMOTO 		return (error);
10054af27623STim J. Robbins 	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1006ca26842eSHajimu UMEMOTO 	if (error)
1007ca26842eSHajimu UMEMOTO 		return (error);
1008552afd9cSPoul-Henning Kamp 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1009552afd9cSPoul-Henning Kamp 	if (error)
1010552afd9cSPoul-Henning Kamp 		return (error);
10115a8a13e0SDavid Malone 	msg.msg_iov = iov;
10125a8a13e0SDavid Malone 	msg.msg_flags = 0;
1013a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
1014a6886ef1SMaxim Sobolev 	    UIO_USERSPACE);
1015552afd9cSPoul-Henning Kamp 	free(iov, M_IOV);
1016ca26842eSHajimu UMEMOTO 	return (error);
1017c21dee17SSøren Schmidt }
1018c21dee17SSøren Schmidt 
101901e0ffbaSAlexander Leidinger struct linux_recvmsg_args {
102040dbba57SAssar Westerlund 	int s;
10214af27623STim J. Robbins 	l_uintptr_t msg;
102240dbba57SAssar Westerlund 	int flags;
102340dbba57SAssar Westerlund };
102440dbba57SAssar Westerlund 
102501e0ffbaSAlexander Leidinger static int
1026b40ce416SJulian Elischer linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
102740dbba57SAssar Westerlund {
102801e0ffbaSAlexander Leidinger 	struct linux_recvmsg_args linux_args;
102940dbba57SAssar Westerlund 	struct recvmsg_args /* {
103040dbba57SAssar Westerlund 		int	s;
103140dbba57SAssar Westerlund 		struct	msghdr *msg;
103240dbba57SAssar Westerlund 		int	flags;
103340dbba57SAssar Westerlund 	} */ bsd_args;
1034ca26842eSHajimu UMEMOTO 	struct msghdr msg;
103584b11cd8SMitsuru IWASAKI 	struct cmsghdr *cmsg;
103640dbba57SAssar Westerlund 	int error;
103740dbba57SAssar Westerlund 
10384af27623STim J. Robbins 	/* XXXTJR recvmsg is broken on amd64 */
10394af27623STim J. Robbins 
104040dbba57SAssar Westerlund 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
104140dbba57SAssar Westerlund 		return (error);
104240dbba57SAssar Westerlund 
104340dbba57SAssar Westerlund 	bsd_args.s = linux_args.s;
10444af27623STim J. Robbins 	bsd_args.msg = PTRIN(linux_args.msg);
104540dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
10465c8919adSAlexander Leidinger 	if (msg.msg_name) {
10475c8919adSAlexander Leidinger 	   	linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
10485c8919adSAlexander Leidinger 		      msg.msg_namelen);
10495c8919adSAlexander Leidinger 		error = recvmsg(td, &bsd_args);
10505c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name);
10515c8919adSAlexander Leidinger 	} else
1052ca26842eSHajimu UMEMOTO 	   	error = recvmsg(td, &bsd_args);
1053ca26842eSHajimu UMEMOTO 	if (error)
1054ca26842eSHajimu UMEMOTO 		return (error);
1055ca26842eSHajimu UMEMOTO 
105672261b9fSDag-Erling Smørgrav 	if (bsd_args.msg->msg_control != NULL &&
105772261b9fSDag-Erling Smørgrav 	    bsd_args.msg->msg_controllen > 0) {
105884b11cd8SMitsuru IWASAKI 		cmsg = (struct cmsghdr*)bsd_args.msg->msg_control;
105984b11cd8SMitsuru IWASAKI 		cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level);
106084b11cd8SMitsuru IWASAKI 	}
106184b11cd8SMitsuru IWASAKI 
10624af27623STim J. Robbins 	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1063ca26842eSHajimu UMEMOTO 	if (error)
1064ca26842eSHajimu UMEMOTO 		return (error);
1065ca26842eSHajimu UMEMOTO 	if (msg.msg_name && msg.msg_namelen > 2)
1066ca26842eSHajimu UMEMOTO 		error = linux_sa_put(msg.msg_name);
1067ca26842eSHajimu UMEMOTO 	return (error);
106840dbba57SAssar Westerlund }
106940dbba57SAssar Westerlund 
1070c21dee17SSøren Schmidt struct linux_shutdown_args {
1071c21dee17SSøren Schmidt 	int s;
1072c21dee17SSøren Schmidt 	int how;
1073c21dee17SSøren Schmidt };
1074c21dee17SSøren Schmidt 
1075c21dee17SSøren Schmidt static int
1076b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1077c21dee17SSøren Schmidt {
1078c21dee17SSøren Schmidt 	struct linux_shutdown_args linux_args;
1079ef04503dSPeter Wemm 	struct shutdown_args /* {
1080c21dee17SSøren Schmidt 		int s;
1081c21dee17SSøren Schmidt 		int how;
1082ef04503dSPeter Wemm 	} */ bsd_args;
1083c21dee17SSøren Schmidt 	int error;
1084c21dee17SSøren Schmidt 
10853f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
10863f3a4815SMarcel Moolenaar 		return (error);
10873f3a4815SMarcel Moolenaar 
1088c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1089c21dee17SSøren Schmidt 	bsd_args.how = linux_args.how;
1090b40ce416SJulian Elischer 	return (shutdown(td, &bsd_args));
1091c21dee17SSøren Schmidt }
1092c21dee17SSøren Schmidt 
1093c21dee17SSøren Schmidt struct linux_setsockopt_args {
1094c21dee17SSøren Schmidt 	int s;
1095c21dee17SSøren Schmidt 	int level;
1096c21dee17SSøren Schmidt 	int optname;
10974af27623STim J. Robbins 	l_uintptr_t optval;
1098c21dee17SSøren Schmidt 	int optlen;
1099c21dee17SSøren Schmidt };
1100c21dee17SSøren Schmidt 
1101c21dee17SSøren Schmidt static int
1102b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1103c21dee17SSøren Schmidt {
1104c21dee17SSøren Schmidt 	struct linux_setsockopt_args linux_args;
1105ef04503dSPeter Wemm 	struct setsockopt_args /* {
1106c21dee17SSøren Schmidt 		int s;
1107c21dee17SSøren Schmidt 		int level;
1108c21dee17SSøren Schmidt 		int name;
1109c21dee17SSøren Schmidt 		caddr_t val;
1110c21dee17SSøren Schmidt 		int valsize;
1111ef04503dSPeter Wemm 	} */ bsd_args;
1112c21dee17SSøren Schmidt 	int error, name;
1113c21dee17SSøren Schmidt 
11143f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
11153f3a4815SMarcel Moolenaar 		return (error);
11163f3a4815SMarcel Moolenaar 
1117c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1118c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1119c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1120c21dee17SSøren Schmidt 	case SOL_SOCKET:
1121c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1122c21dee17SSøren Schmidt 		break;
1123c21dee17SSøren Schmidt 	case IPPROTO_IP:
1124c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1125c21dee17SSøren Schmidt 		break;
1126dad3b88aSMike Smith 	case IPPROTO_TCP:
1127dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1128dad3b88aSMike Smith 		name = linux_args.optname;
1129dad3b88aSMike Smith 		break;
1130c21dee17SSøren Schmidt 	default:
11313f3a4815SMarcel Moolenaar 		name = -1;
11323f3a4815SMarcel Moolenaar 		break;
1133c21dee17SSøren Schmidt 	}
1134c21dee17SSøren Schmidt 	if (name == -1)
11353f3a4815SMarcel Moolenaar 		return (EINVAL);
11363f3a4815SMarcel Moolenaar 
1137c21dee17SSøren Schmidt 	bsd_args.name = name;
11384af27623STim J. Robbins 	bsd_args.val = PTRIN(linux_args.optval);
1139c21dee17SSøren Schmidt 	bsd_args.valsize = linux_args.optlen;
11405c8919adSAlexander Leidinger 
11415c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
11425c8919adSAlexander Leidinger 		linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
11435c8919adSAlexander Leidinger 			bsd_args.valsize);
11445c8919adSAlexander Leidinger 		error = setsockopt(td, &bsd_args);
11455c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
11465c8919adSAlexander Leidinger 	} else
11475c8919adSAlexander Leidinger 		error = setsockopt(td, &bsd_args);
11485c8919adSAlexander Leidinger 
11495c8919adSAlexander Leidinger 	return (error);
1150c21dee17SSøren Schmidt }
1151c21dee17SSøren Schmidt 
1152c21dee17SSøren Schmidt struct linux_getsockopt_args {
1153c21dee17SSøren Schmidt 	int s;
1154c21dee17SSøren Schmidt 	int level;
1155c21dee17SSøren Schmidt 	int optname;
11564af27623STim J. Robbins 	l_uintptr_t optval;
11574af27623STim J. Robbins 	l_uintptr_t optlen;
1158c21dee17SSøren Schmidt };
1159c21dee17SSøren Schmidt 
1160c21dee17SSøren Schmidt static int
1161b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1162c21dee17SSøren Schmidt {
1163c21dee17SSøren Schmidt 	struct linux_getsockopt_args linux_args;
1164ef04503dSPeter Wemm 	struct getsockopt_args /* {
1165c21dee17SSøren Schmidt 		int s;
1166c21dee17SSøren Schmidt 		int level;
1167c21dee17SSøren Schmidt 		int name;
1168c21dee17SSøren Schmidt 		caddr_t val;
1169c21dee17SSøren Schmidt 		int *avalsize;
1170ef04503dSPeter Wemm 	} */ bsd_args;
1171c21dee17SSøren Schmidt 	int error, name;
1172c21dee17SSøren Schmidt 
11733f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
11743f3a4815SMarcel Moolenaar 		return (error);
11753f3a4815SMarcel Moolenaar 
1176c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1177c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1178c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1179c21dee17SSøren Schmidt 	case SOL_SOCKET:
1180c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1181c21dee17SSøren Schmidt 		break;
1182c21dee17SSøren Schmidt 	case IPPROTO_IP:
1183c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1184c21dee17SSøren Schmidt 		break;
1185dad3b88aSMike Smith 	case IPPROTO_TCP:
1186dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1187dad3b88aSMike Smith 		name = linux_args.optname;
1188dad3b88aSMike Smith 		break;
1189c21dee17SSøren Schmidt 	default:
11903f3a4815SMarcel Moolenaar 		name = -1;
11913f3a4815SMarcel Moolenaar 		break;
1192c21dee17SSøren Schmidt 	}
1193c21dee17SSøren Schmidt 	if (name == -1)
11943f3a4815SMarcel Moolenaar 		return (EINVAL);
11953f3a4815SMarcel Moolenaar 
1196f2477ae1SMike Smith 	bsd_args.name = name;
11974af27623STim J. Robbins 	bsd_args.val = PTRIN(linux_args.optval);
11984af27623STim J. Robbins 	bsd_args.avalsize = PTRIN(linux_args.optlen);
11995c8919adSAlexander Leidinger 
12005c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
12015c8919adSAlexander Leidinger 		error = getsockopt(td, &bsd_args);
12025c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
12035c8919adSAlexander Leidinger 	} else
12045c8919adSAlexander Leidinger 		error = getsockopt(td, &bsd_args);
12055c8919adSAlexander Leidinger 
12065c8919adSAlexander Leidinger 	return (error);
1207c21dee17SSøren Schmidt }
1208c21dee17SSøren Schmidt 
1209c21dee17SSøren Schmidt int
1210b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1211c21dee17SSøren Schmidt {
12124af27623STim J. Robbins 	void *arg = (void *)(intptr_t)args->args;
12133f3a4815SMarcel Moolenaar 
1214c21dee17SSøren Schmidt 	switch (args->what) {
1215c21dee17SSøren Schmidt 	case LINUX_SOCKET:
1216b40ce416SJulian Elischer 		return (linux_socket(td, arg));
1217c21dee17SSøren Schmidt 	case LINUX_BIND:
1218b40ce416SJulian Elischer 		return (linux_bind(td, arg));
1219c21dee17SSøren Schmidt 	case LINUX_CONNECT:
1220b40ce416SJulian Elischer 		return (linux_connect(td, arg));
1221c21dee17SSøren Schmidt 	case LINUX_LISTEN:
1222b40ce416SJulian Elischer 		return (linux_listen(td, arg));
1223c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
1224b40ce416SJulian Elischer 		return (linux_accept(td, arg));
1225c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
1226b40ce416SJulian Elischer 		return (linux_getsockname(td, arg));
1227c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
1228b40ce416SJulian Elischer 		return (linux_getpeername(td, arg));
1229c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
1230b40ce416SJulian Elischer 		return (linux_socketpair(td, arg));
1231c21dee17SSøren Schmidt 	case LINUX_SEND:
1232b40ce416SJulian Elischer 		return (linux_send(td, arg));
1233c21dee17SSøren Schmidt 	case LINUX_RECV:
1234b40ce416SJulian Elischer 		return (linux_recv(td, arg));
1235c21dee17SSøren Schmidt 	case LINUX_SENDTO:
1236b40ce416SJulian Elischer 		return (linux_sendto(td, arg));
1237c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
1238b40ce416SJulian Elischer 		return (linux_recvfrom(td, arg));
1239c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
1240b40ce416SJulian Elischer 		return (linux_shutdown(td, arg));
1241c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
1242b40ce416SJulian Elischer 		return (linux_setsockopt(td, arg));
1243c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
1244b40ce416SJulian Elischer 		return (linux_getsockopt(td, arg));
1245e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
1246ca26842eSHajimu UMEMOTO 		return (linux_sendmsg(td, arg));
1247e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
1248b40ce416SJulian Elischer 		return (linux_recvmsg(td, arg));
1249c21dee17SSøren Schmidt 	}
12503f3a4815SMarcel Moolenaar 
12513f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
12523f3a4815SMarcel Moolenaar 	return (ENOSYS);
1253c21dee17SSøren Schmidt }
1254