xref: /freebsd/sys/compat/linux/linux_socket.c (revision 2ca25ab53ec018a64ecbf89e780fe9ff4298811e)
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. */
335591b823SEivind Eklund #include "opt_compat.h"
34ca26842eSHajimu UMEMOTO #include "opt_inet6.h"
355591b823SEivind Eklund 
365591b823SEivind Eklund #ifndef COMPAT_43
375591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
385591b823SEivind Eklund #endif
391f3dad5aSBruce Evans 
40c21dee17SSøren Schmidt #include <sys/param.h>
41f2477ae1SMike Smith #include <sys/proc.h>
42c21dee17SSøren Schmidt #include <sys/systm.h>
431f3dad5aSBruce Evans #include <sys/sysproto.h>
44dad3b88aSMike Smith #include <sys/fcntl.h>
450bf301c0SJonathan Lemon #include <sys/file.h>
46104a9b7eSAlexander Kabaev #include <sys/limits.h>
47ca26842eSHajimu UMEMOTO #include <sys/malloc.h>
485a8a13e0SDavid Malone #include <sys/mbuf.h>
49c21dee17SSøren Schmidt #include <sys/socket.h>
500bf301c0SJonathan Lemon #include <sys/socketvar.h>
51ca26842eSHajimu UMEMOTO #include <sys/syscallsubr.h>
5208637435SBruce Evans #include <sys/uio.h>
53ca26842eSHajimu UMEMOTO #include <sys/syslog.h>
541f3dad5aSBruce Evans 
55c21dee17SSøren Schmidt #include <netinet/in.h>
56f2477ae1SMike Smith #include <netinet/in_systm.h>
57f2477ae1SMike Smith #include <netinet/ip.h>
58ca26842eSHajimu UMEMOTO #ifdef INET6
59ca26842eSHajimu UMEMOTO #include <netinet/ip6.h>
60ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h>
61ca26842eSHajimu UMEMOTO #endif
62c21dee17SSøren Schmidt 
634af27623STim J. Robbins #include "opt_compat.h"
644af27623STim J. Robbins 
654af27623STim J. Robbins #if !COMPAT_LINUX32
66ac951e62SMarcel Moolenaar #include <machine/../linux/linux.h>
67ebea8660SMarcel Moolenaar #include <machine/../linux/linux_proto.h>
684af27623STim J. Robbins #else
694af27623STim J. Robbins #include <machine/../linux32/linux.h>
704af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
714af27623STim J. Robbins #endif
7240dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
73ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
74c21dee17SSøren Schmidt 
75ca26842eSHajimu UMEMOTO static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
76ca26842eSHajimu UMEMOTO     struct malloc_type *);
77ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int);
78ca26842eSHajimu UMEMOTO 
794730796cSBill Fenner /*
80ca26842eSHajimu UMEMOTO  * Reads a linux sockaddr and does any necessary translation.
81ca26842eSHajimu UMEMOTO  * Linux sockaddrs don't have a length field, only a family.
824730796cSBill Fenner  */
834730796cSBill Fenner static int
84ca26842eSHajimu UMEMOTO linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
854730796cSBill Fenner {
86ca26842eSHajimu UMEMOTO 	int osalen = len;
874730796cSBill Fenner 
88ca26842eSHajimu UMEMOTO 	return (do_sa_get(sap, osa, &osalen, M_SONAME));
894730796cSBill Fenner }
904730796cSBill Fenner 
91ca26842eSHajimu UMEMOTO /*
92ca26842eSHajimu UMEMOTO  * Copy the osockaddr structure pointed to by osa to kernel, adjust
93ca26842eSHajimu UMEMOTO  * family and convert to sockaddr.
94ca26842eSHajimu UMEMOTO  */
95ca26842eSHajimu UMEMOTO static int
96ca26842eSHajimu UMEMOTO do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
97ca26842eSHajimu UMEMOTO     struct malloc_type *mtype)
98ca26842eSHajimu UMEMOTO {
99ca26842eSHajimu UMEMOTO 	int error=0, bdom;
100ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
101ca26842eSHajimu UMEMOTO 	struct osockaddr *kosa;
102ca26842eSHajimu UMEMOTO 	int alloclen;
103ca26842eSHajimu UMEMOTO #ifdef INET6
104ca26842eSHajimu UMEMOTO 	int oldv6size;
105ca26842eSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
106ca26842eSHajimu UMEMOTO #endif
107ca26842eSHajimu UMEMOTO 
108ca26842eSHajimu UMEMOTO 	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
109ca26842eSHajimu UMEMOTO 		return (EINVAL);
110ca26842eSHajimu UMEMOTO 
111ca26842eSHajimu UMEMOTO 	alloclen = *osalen;
112ca26842eSHajimu UMEMOTO #ifdef INET6
113ca26842eSHajimu UMEMOTO 	oldv6size = 0;
114ca26842eSHajimu UMEMOTO 	/*
115ca26842eSHajimu UMEMOTO 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
116ca26842eSHajimu UMEMOTO 	 * if it's a v4-mapped address, so reserve the proper space
117ca26842eSHajimu UMEMOTO 	 * for it.
118ca26842eSHajimu UMEMOTO 	 */
119ca26842eSHajimu UMEMOTO 	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
120ca26842eSHajimu UMEMOTO 		alloclen = sizeof (struct sockaddr_in6);
121ca26842eSHajimu UMEMOTO 		oldv6size = 1;
122ca26842eSHajimu UMEMOTO 	}
123ca26842eSHajimu UMEMOTO #endif
124ca26842eSHajimu UMEMOTO 
1255b13e781SHajimu UMEMOTO 	MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
126ca26842eSHajimu UMEMOTO 
1274b7ef73dSDag-Erling Smørgrav 	if ((error = copyin(osa, kosa, *osalen)))
128ca26842eSHajimu UMEMOTO 		goto out;
129ca26842eSHajimu UMEMOTO 
130ca26842eSHajimu UMEMOTO 	bdom = linux_to_bsd_domain(kosa->sa_family);
131ca26842eSHajimu UMEMOTO 	if (bdom == -1) {
132ca26842eSHajimu UMEMOTO 		error = EINVAL;
133ca26842eSHajimu UMEMOTO 		goto out;
134ca26842eSHajimu UMEMOTO 	}
135ca26842eSHajimu UMEMOTO 
136ca26842eSHajimu UMEMOTO #ifdef INET6
137ca26842eSHajimu UMEMOTO 	/*
138ca26842eSHajimu UMEMOTO 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
139ca26842eSHajimu UMEMOTO 	 * which lacks the scope id compared with RFC2553 one. If we detect
140ca26842eSHajimu UMEMOTO 	 * the situation, reject the address and write a message to system log.
141ca26842eSHajimu UMEMOTO 	 *
142ca26842eSHajimu UMEMOTO 	 * Still accept addresses for which the scope id is not used.
143ca26842eSHajimu UMEMOTO 	 */
144ca26842eSHajimu UMEMOTO 	if (oldv6size && bdom == AF_INET6) {
145ca26842eSHajimu UMEMOTO 		sin6 = (struct sockaddr_in6 *)kosa;
146ca26842eSHajimu UMEMOTO 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
147ca26842eSHajimu UMEMOTO 		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
148ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
149ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
150ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
151ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
152ca26842eSHajimu UMEMOTO 			sin6->sin6_scope_id = 0;
153ca26842eSHajimu UMEMOTO 		} else {
154ca26842eSHajimu UMEMOTO 			log(LOG_DEBUG,
155ca26842eSHajimu UMEMOTO 			    "obsolete pre-RFC2553 sockaddr_in6 rejected");
156ca26842eSHajimu UMEMOTO 			error = EINVAL;
157ca26842eSHajimu UMEMOTO 			goto out;
158ca26842eSHajimu UMEMOTO 		}
159ca26842eSHajimu UMEMOTO 	} else
160ca26842eSHajimu UMEMOTO #endif
161ca26842eSHajimu UMEMOTO 	if (bdom == AF_INET)
162ca26842eSHajimu UMEMOTO 		alloclen = sizeof(struct sockaddr_in);
163ca26842eSHajimu UMEMOTO 
164ca26842eSHajimu UMEMOTO 	sa = (struct sockaddr *) kosa;
165ca26842eSHajimu UMEMOTO 	sa->sa_family = bdom;
166ca26842eSHajimu UMEMOTO 	sa->sa_len = alloclen;
167ca26842eSHajimu UMEMOTO 
168ca26842eSHajimu UMEMOTO 	*sap = sa;
169ca26842eSHajimu UMEMOTO 	*osalen = alloclen;
170ca26842eSHajimu UMEMOTO 	return (0);
171ca26842eSHajimu UMEMOTO 
172ca26842eSHajimu UMEMOTO out:
173ca26842eSHajimu UMEMOTO 	FREE(kosa, mtype);
174ca26842eSHajimu UMEMOTO 	return (error);
175ca26842eSHajimu UMEMOTO }
176ca26842eSHajimu UMEMOTO 
177c21dee17SSøren Schmidt static int
178c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
179c21dee17SSøren Schmidt {
1803f3a4815SMarcel Moolenaar 
181c21dee17SSøren Schmidt 	switch (domain) {
182c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
1833f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
184c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
1853f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
186c21dee17SSøren Schmidt 	case LINUX_AF_INET:
1873f3a4815SMarcel Moolenaar 		return (AF_INET);
188ca26842eSHajimu UMEMOTO 	case LINUX_AF_INET6:
189ca26842eSHajimu UMEMOTO 		return (AF_INET6);
190c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
1913f3a4815SMarcel Moolenaar 		return (AF_CCITT);
192c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
1933f3a4815SMarcel Moolenaar 		return (AF_IPX);
194c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
1953f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
196c21dee17SSøren Schmidt 	}
1973f3a4815SMarcel Moolenaar 	return (-1);
198c21dee17SSøren Schmidt }
199c21dee17SSøren Schmidt 
200ca26842eSHajimu UMEMOTO #ifndef __alpha__
201ca26842eSHajimu UMEMOTO static int
202ca26842eSHajimu UMEMOTO bsd_to_linux_domain(int domain)
203ca26842eSHajimu UMEMOTO {
204ca26842eSHajimu UMEMOTO 
205ca26842eSHajimu UMEMOTO 	switch (domain) {
206ca26842eSHajimu UMEMOTO 	case AF_UNSPEC:
207ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNSPEC);
208ca26842eSHajimu UMEMOTO 	case AF_LOCAL:
209ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNIX);
210ca26842eSHajimu UMEMOTO 	case AF_INET:
211ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET);
212ca26842eSHajimu UMEMOTO 	case AF_INET6:
213ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET6);
214ca26842eSHajimu UMEMOTO 	case AF_CCITT:
215ca26842eSHajimu UMEMOTO 		return (LINUX_AF_AX25);
216ca26842eSHajimu UMEMOTO 	case AF_IPX:
217ca26842eSHajimu UMEMOTO 		return (LINUX_AF_IPX);
218ca26842eSHajimu UMEMOTO 	case AF_APPLETALK:
219ca26842eSHajimu UMEMOTO 		return (LINUX_AF_APPLETALK);
220ca26842eSHajimu UMEMOTO 	}
221ca26842eSHajimu UMEMOTO 	return (-1);
222ca26842eSHajimu UMEMOTO }
223ca26842eSHajimu UMEMOTO 
224c21dee17SSøren Schmidt static int
225c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
226c21dee17SSøren Schmidt {
2273f3a4815SMarcel Moolenaar 
228c21dee17SSøren Schmidt 	switch (level) {
229c21dee17SSøren Schmidt 	case LINUX_SOL_SOCKET:
2303f3a4815SMarcel Moolenaar 		return (SOL_SOCKET);
231c21dee17SSøren Schmidt 	}
2323f3a4815SMarcel Moolenaar 	return (level);
233c21dee17SSøren Schmidt }
234c21dee17SSøren Schmidt 
2353f3a4815SMarcel Moolenaar static int
23684b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level)
23784b11cd8SMitsuru IWASAKI {
23884b11cd8SMitsuru IWASAKI 
23984b11cd8SMitsuru IWASAKI 	switch (level) {
24084b11cd8SMitsuru IWASAKI 	case SOL_SOCKET:
24184b11cd8SMitsuru IWASAKI 		return (LINUX_SOL_SOCKET);
24284b11cd8SMitsuru IWASAKI 	}
24384b11cd8SMitsuru IWASAKI 	return (level);
24484b11cd8SMitsuru IWASAKI }
24584b11cd8SMitsuru IWASAKI 
24684b11cd8SMitsuru IWASAKI static int
2473f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
248c21dee17SSøren Schmidt {
2493f3a4815SMarcel Moolenaar 
250c21dee17SSøren Schmidt 	switch (opt) {
251c21dee17SSøren Schmidt 	case LINUX_IP_TOS:
2523f3a4815SMarcel Moolenaar 		return (IP_TOS);
253c21dee17SSøren Schmidt 	case LINUX_IP_TTL:
2543f3a4815SMarcel Moolenaar 		return (IP_TTL);
25566ff6a3cSBill Fenner 	case LINUX_IP_OPTIONS:
2563f3a4815SMarcel Moolenaar 		return (IP_OPTIONS);
25766ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_IF:
2583f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_IF);
25966ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_TTL:
2603f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_TTL);
26166ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_LOOP:
2623f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_LOOP);
26366ff6a3cSBill Fenner 	case LINUX_IP_ADD_MEMBERSHIP:
2643f3a4815SMarcel Moolenaar 		return (IP_ADD_MEMBERSHIP);
26566ff6a3cSBill Fenner 	case LINUX_IP_DROP_MEMBERSHIP:
2663f3a4815SMarcel Moolenaar 		return (IP_DROP_MEMBERSHIP);
26766ff6a3cSBill Fenner 	case LINUX_IP_HDRINCL:
2683f3a4815SMarcel Moolenaar 		return (IP_HDRINCL);
269c21dee17SSøren Schmidt 	}
2703f3a4815SMarcel Moolenaar 	return (-1);
271c21dee17SSøren Schmidt }
272c21dee17SSøren Schmidt 
273c21dee17SSøren Schmidt static int
274c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
275c21dee17SSøren Schmidt {
2763f3a4815SMarcel Moolenaar 
277c21dee17SSøren Schmidt 	switch (opt) {
278c21dee17SSøren Schmidt 	case LINUX_SO_DEBUG:
2793f3a4815SMarcel Moolenaar 		return (SO_DEBUG);
280c21dee17SSøren Schmidt 	case LINUX_SO_REUSEADDR:
2813f3a4815SMarcel Moolenaar 		return (SO_REUSEADDR);
282c21dee17SSøren Schmidt 	case LINUX_SO_TYPE:
2833f3a4815SMarcel Moolenaar 		return (SO_TYPE);
284c21dee17SSøren Schmidt 	case LINUX_SO_ERROR:
2853f3a4815SMarcel Moolenaar 		return (SO_ERROR);
286c21dee17SSøren Schmidt 	case LINUX_SO_DONTROUTE:
2873f3a4815SMarcel Moolenaar 		return (SO_DONTROUTE);
288c21dee17SSøren Schmidt 	case LINUX_SO_BROADCAST:
2893f3a4815SMarcel Moolenaar 		return (SO_BROADCAST);
290c21dee17SSøren Schmidt 	case LINUX_SO_SNDBUF:
2913f3a4815SMarcel Moolenaar 		return (SO_SNDBUF);
292c21dee17SSøren Schmidt 	case LINUX_SO_RCVBUF:
2933f3a4815SMarcel Moolenaar 		return (SO_RCVBUF);
294c21dee17SSøren Schmidt 	case LINUX_SO_KEEPALIVE:
2953f3a4815SMarcel Moolenaar 		return (SO_KEEPALIVE);
296c21dee17SSøren Schmidt 	case LINUX_SO_OOBINLINE:
2973f3a4815SMarcel Moolenaar 		return (SO_OOBINLINE);
298c21dee17SSøren Schmidt 	case LINUX_SO_LINGER:
2993f3a4815SMarcel Moolenaar 		return (SO_LINGER);
300c21dee17SSøren Schmidt 	}
3013f3a4815SMarcel Moolenaar 	return (-1);
302c21dee17SSøren Schmidt }
303c21dee17SSøren Schmidt 
30440dbba57SAssar Westerlund static int
30540dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
30640dbba57SAssar Westerlund {
30740dbba57SAssar Westerlund 	int ret_flags = 0;
30840dbba57SAssar Westerlund 
30940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
31040dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
31140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
31240dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
31340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
31440dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
31540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
31640dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
31740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
31840dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
31940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
32040dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
32140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
32240dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
32340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
32440dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
32540dbba57SAssar Westerlund #if 0 /* not handled */
32640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
32740dbba57SAssar Westerlund 		;
32840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
32940dbba57SAssar Westerlund 		;
33040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
33140dbba57SAssar Westerlund 		;
33240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
33340dbba57SAssar Westerlund 		;
33440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
33540dbba57SAssar Westerlund 		;
33640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
33740dbba57SAssar Westerlund 		;
33840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_NOSIGNAL)
33940dbba57SAssar Westerlund 		;
34040dbba57SAssar Westerlund #endif
34140dbba57SAssar Westerlund 	return ret_flags;
34240dbba57SAssar Westerlund }
34340dbba57SAssar Westerlund 
344ca26842eSHajimu UMEMOTO static int
345ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa)
346ca26842eSHajimu UMEMOTO {
347ca26842eSHajimu UMEMOTO 	struct osockaddr sa;
348ca26842eSHajimu UMEMOTO 	int error, bdom;
349ca26842eSHajimu UMEMOTO 
350ca26842eSHajimu UMEMOTO 	/*
351ca26842eSHajimu UMEMOTO 	 * Only read/write the osockaddr family part, the rest is
352ca26842eSHajimu UMEMOTO 	 * not changed.
353ca26842eSHajimu UMEMOTO 	 */
3544b7ef73dSDag-Erling Smørgrav 	error = copyin(osa, &sa, sizeof(sa.sa_family));
355ca26842eSHajimu UMEMOTO 	if (error)
356ca26842eSHajimu UMEMOTO 		return (error);
357ca26842eSHajimu UMEMOTO 
358ca26842eSHajimu UMEMOTO 	bdom = bsd_to_linux_domain(sa.sa_family);
359ca26842eSHajimu UMEMOTO 	if (bdom == -1)
360ca26842eSHajimu UMEMOTO 		return (EINVAL);
361ca26842eSHajimu UMEMOTO 
362ca26842eSHajimu UMEMOTO 	sa.sa_family = bdom;
363ca26842eSHajimu UMEMOTO 	error = copyout(&sa, osa, sizeof(sa.sa_family));
364ca26842eSHajimu UMEMOTO 	if (error)
365ca26842eSHajimu UMEMOTO 		return (error);
366ca26842eSHajimu UMEMOTO 
367ca26842eSHajimu UMEMOTO 	return (0);
368ca26842eSHajimu UMEMOTO }
369ca26842eSHajimu UMEMOTO 
3705a8a13e0SDavid Malone static int
3715a8a13e0SDavid Malone linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags)
3725a8a13e0SDavid Malone {
3735a8a13e0SDavid Malone 	struct mbuf *control;
3745a8a13e0SDavid Malone 	struct sockaddr *to;
3755a8a13e0SDavid Malone 	int error;
3765a8a13e0SDavid Malone 
3775a8a13e0SDavid Malone 	if (mp->msg_name != NULL) {
3785a8a13e0SDavid Malone 		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
3795a8a13e0SDavid Malone 		if (error)
3805a8a13e0SDavid Malone 			return (error);
3815a8a13e0SDavid Malone 		mp->msg_name = to;
3825a8a13e0SDavid Malone 	} else
3835a8a13e0SDavid Malone 		to = NULL;
3845a8a13e0SDavid Malone 
3855a8a13e0SDavid Malone 	if (mp->msg_control != NULL) {
3865a8a13e0SDavid Malone 		struct cmsghdr *cmsg;
3875a8a13e0SDavid Malone 
3885a8a13e0SDavid Malone 		if (mp->msg_controllen < sizeof(struct cmsghdr)) {
3895a8a13e0SDavid Malone 			error = EINVAL;
3905a8a13e0SDavid Malone 			goto bad;
3915a8a13e0SDavid Malone 		}
3925a8a13e0SDavid Malone 		error = sockargs(&control, mp->msg_control,
3935a8a13e0SDavid Malone 		    mp->msg_controllen, MT_CONTROL);
3945a8a13e0SDavid Malone 		if (error)
3955a8a13e0SDavid Malone 			goto bad;
3965a8a13e0SDavid Malone 
3975a8a13e0SDavid Malone 		cmsg = mtod(control, struct cmsghdr *);
3985a8a13e0SDavid Malone 		cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level);
3995a8a13e0SDavid Malone 	} else
4005a8a13e0SDavid Malone 		control = NULL;
4015a8a13e0SDavid Malone 
4025a8a13e0SDavid Malone 	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control);
4035a8a13e0SDavid Malone 
4045a8a13e0SDavid Malone bad:
4055a8a13e0SDavid Malone 	if (to)
4065a8a13e0SDavid Malone 		FREE(to, M_SONAME);
4075a8a13e0SDavid Malone 	return (error);
4085a8a13e0SDavid Malone }
4095a8a13e0SDavid Malone 
4103f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
411f2477ae1SMike Smith static int
412e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s)
413f2477ae1SMike Smith {
4143db2a843SBruce Evans 	int error, optval, size_val;
415f2477ae1SMike Smith 
416e140eb43SDavid Malone 	size_val = sizeof(optval);
417e140eb43SDavid Malone 	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
418e140eb43SDavid Malone 	    &optval, UIO_SYSSPACE, &size_val);
419e140eb43SDavid Malone 	if (error)
4203f3a4815SMarcel Moolenaar 		return (error);
4213f3a4815SMarcel Moolenaar 
4223f3a4815SMarcel Moolenaar 	return (optval == 0);
423f2477ae1SMike Smith }
424f2477ae1SMike Smith 
4255a8a13e0SDavid Malone struct linux_sendto_args {
4265a8a13e0SDavid Malone 	int s;
4274af27623STim J. Robbins 	l_uintptr_t msg;
4285a8a13e0SDavid Malone 	int len;
4295a8a13e0SDavid Malone 	int flags;
4304af27623STim J. Robbins 	l_uintptr_t to;
4315a8a13e0SDavid Malone 	int tolen;
4325a8a13e0SDavid Malone };
4335a8a13e0SDavid Malone 
434f2477ae1SMike Smith /*
435f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
436f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
437f2477ae1SMike Smith  */
438f2477ae1SMike Smith static int
43938da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
440f2477ae1SMike Smith {
441f2477ae1SMike Smith /*
442f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
443f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
444f2477ae1SMike Smith  * It should include all the fields we modify (ip_len and ip_off)
445f2477ae1SMike Smith  * and be as small as possible to minimize copying overhead.
446f2477ae1SMike Smith  */
447f2477ae1SMike Smith #define linux_ip_copysize	8
448f2477ae1SMike Smith 
449f2477ae1SMike Smith 	struct ip *packet;
450e140eb43SDavid Malone 	caddr_t sg = stackgap_init();
4515a8a13e0SDavid Malone 	struct msghdr msg;
4525a8a13e0SDavid Malone 	struct iovec aiov[2];
453f2477ae1SMike Smith 	int error;
454f2477ae1SMike Smith 
455f2477ae1SMike Smith 	/* Check the packet isn't too small before we mess with it */
4565a8a13e0SDavid Malone 	if (linux_args->len < linux_ip_copysize)
4573f3a4815SMarcel Moolenaar 		return (EINVAL);
458f2477ae1SMike Smith 
459f2477ae1SMike Smith 	/*
460f2477ae1SMike Smith 	 * Tweaking the user buffer in place would be bad manners.
461f2477ae1SMike Smith 	 * We create a corrected IP header with just the needed length,
462f2477ae1SMike Smith 	 * then use an iovec to glue it to the rest of the user packet
4635a8a13e0SDavid Malone 	 * when calling sendit().
464f2477ae1SMike Smith 	 */
465fb75797eSDavid Malone 	packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
466f2477ae1SMike Smith 
467f2477ae1SMike Smith 	/* Make a copy of the beginning of the packet to be sent */
4684af27623STim J. Robbins 	if ((error = copyin(PTRIN(linux_args->msg), packet,
4694af27623STim J. Robbins 	    linux_ip_copysize)))
4703f3a4815SMarcel Moolenaar 		return (error);
471f2477ae1SMike Smith 
472f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
4735a8a13e0SDavid Malone 	packet->ip_len = linux_args->len;
474f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
475f2477ae1SMike Smith 
476f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
4774af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args->to);
4785a8a13e0SDavid Malone 	msg.msg_namelen = linux_args->tolen;
4795a8a13e0SDavid Malone 	msg.msg_iov = aiov;
4805a8a13e0SDavid Malone 	msg.msg_iovlen = 2;
4815a8a13e0SDavid Malone 	msg.msg_control = NULL;
4825a8a13e0SDavid Malone 	msg.msg_flags = 0;
4835a8a13e0SDavid Malone 	aiov[0].iov_base = (char *)packet;
4845a8a13e0SDavid Malone 	aiov[0].iov_len = linux_ip_copysize;
4854af27623STim J. Robbins 	aiov[1].iov_base = (char *)PTRIN(linux_args->msg) +
4864af27623STim J. Robbins 	    linux_ip_copysize;
4875a8a13e0SDavid Malone 	aiov[1].iov_len = linux_args->len - linux_ip_copysize;
4885a8a13e0SDavid Malone 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags);
4895a8a13e0SDavid Malone 	return (error);
490f2477ae1SMike Smith }
491f2477ae1SMike Smith 
492c21dee17SSøren Schmidt struct linux_socket_args {
493c21dee17SSøren Schmidt 	int domain;
494c21dee17SSøren Schmidt 	int type;
495c21dee17SSøren Schmidt 	int protocol;
496c21dee17SSøren Schmidt };
497c21dee17SSøren Schmidt 
498c21dee17SSøren Schmidt static int
499b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
500c21dee17SSøren Schmidt {
501c21dee17SSøren Schmidt 	struct linux_socket_args linux_args;
502ef04503dSPeter Wemm 	struct socket_args /* {
503c21dee17SSøren Schmidt 		int domain;
504c21dee17SSøren Schmidt 		int type;
505c21dee17SSøren Schmidt 		int protocol;
506ef04503dSPeter Wemm 	} */ bsd_args;
507c21dee17SSøren Schmidt 	int error;
508f2477ae1SMike Smith 	int retval_socket;
509c21dee17SSøren Schmidt 
5103f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5113f3a4815SMarcel Moolenaar 		return (error);
5123f3a4815SMarcel Moolenaar 
513c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
514c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
515c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
516c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
5173f3a4815SMarcel Moolenaar 		return (EINVAL);
518f2477ae1SMike Smith 
519b40ce416SJulian Elischer 	retval_socket = socket(td, &bsd_args);
520f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
521f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
522f2477ae1SMike Smith 	    && bsd_args.domain == AF_INET
523f2477ae1SMike Smith 	    && retval_socket >= 0) {
524f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
525e140eb43SDavid Malone 		int hdrincl;
526f2477ae1SMike Smith 
527e140eb43SDavid Malone 		hdrincl = 1;
528e140eb43SDavid Malone 		/* We ignore any error returned by kern_setsockopt() */
529e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
530e140eb43SDavid Malone 		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
531f2477ae1SMike Smith 	}
532ca26842eSHajimu UMEMOTO #ifdef INET6
533ca26842eSHajimu UMEMOTO 	/*
534ca26842eSHajimu UMEMOTO 	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
535ca26842eSHajimu UMEMOTO 	 * default and some apps depend on this. So, set V6ONLY to 0
536ca26842eSHajimu UMEMOTO 	 * for Linux apps if the sysctl value is set to 1.
537ca26842eSHajimu UMEMOTO 	 */
53837e7a5a2SHajimu UMEMOTO 	if (bsd_args.domain == PF_INET6 && retval_socket >= 0
53937e7a5a2SHajimu UMEMOTO #ifndef KLD_MODULE
54037e7a5a2SHajimu UMEMOTO 	    /*
54137e7a5a2SHajimu UMEMOTO 	     * XXX: Avoid undefined symbol error with an IPv4 only
54237e7a5a2SHajimu UMEMOTO 	     * kernel.
54337e7a5a2SHajimu UMEMOTO 	     */
54437e7a5a2SHajimu UMEMOTO 	    && ip6_v6only
54537e7a5a2SHajimu UMEMOTO #endif
54637e7a5a2SHajimu UMEMOTO 	    ) {
547e140eb43SDavid Malone 		int v6only;
548ca26842eSHajimu UMEMOTO 
549e140eb43SDavid Malone 		v6only = 0;
550ca26842eSHajimu UMEMOTO 		/* We ignore any error returned by setsockopt() */
551e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
552e140eb43SDavid Malone 		    &v6only, UIO_SYSSPACE, sizeof(v6only));
553ca26842eSHajimu UMEMOTO 	}
554ca26842eSHajimu UMEMOTO #endif
5553f3a4815SMarcel Moolenaar 
5563f3a4815SMarcel Moolenaar 	return (retval_socket);
557c21dee17SSøren Schmidt }
558c21dee17SSøren Schmidt 
559c21dee17SSøren Schmidt struct linux_bind_args {
560c21dee17SSøren Schmidt 	int s;
5614af27623STim J. Robbins 	l_uintptr_t name;
562c21dee17SSøren Schmidt 	int namelen;
563c21dee17SSøren Schmidt };
564c21dee17SSøren Schmidt 
565c21dee17SSøren Schmidt static int
566b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
567c21dee17SSøren Schmidt {
568c21dee17SSøren Schmidt 	struct linux_bind_args linux_args;
569ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
570c21dee17SSøren Schmidt 	int error;
571c21dee17SSøren Schmidt 
5723f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5733f3a4815SMarcel Moolenaar 		return (error);
5743f3a4815SMarcel Moolenaar 
5754af27623STim J. Robbins 	error = linux_getsockaddr(&sa, PTRIN(linux_args.name),
5764af27623STim J. Robbins 	    linux_args.namelen);
577ca26842eSHajimu UMEMOTO 	if (error)
578ca26842eSHajimu UMEMOTO 		return (error);
579ca26842eSHajimu UMEMOTO 
580ca26842eSHajimu UMEMOTO 	return (kern_bind(td, linux_args.s, sa));
581c21dee17SSøren Schmidt }
582c21dee17SSøren Schmidt 
583c21dee17SSøren Schmidt struct linux_connect_args {
584c21dee17SSøren Schmidt 	int s;
5854af27623STim J. Robbins 	l_uintptr_t name;
586c21dee17SSøren Schmidt 	int namelen;
587c21dee17SSøren Schmidt };
588b40ce416SJulian Elischer int linux_connect(struct thread *, struct linux_connect_args *);
589930a65feSAndrew Gallatin #endif /* !__alpha__*/
590c21dee17SSøren Schmidt 
591930a65feSAndrew Gallatin int
592b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
593c21dee17SSøren Schmidt {
594c21dee17SSøren Schmidt 	struct linux_connect_args linux_args;
5950bf301c0SJonathan Lemon 	struct socket *so;
596ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
59739c95b83SMatthew Dillon 	u_int fflag;
598c21dee17SSøren Schmidt 	int error;
599c21dee17SSøren Schmidt 
600930a65feSAndrew Gallatin #ifdef __alpha__
601930a65feSAndrew Gallatin 	bcopy(args, &linux_args, sizeof(linux_args));
602930a65feSAndrew Gallatin #else
6033f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6043f3a4815SMarcel Moolenaar 		return (error);
605930a65feSAndrew Gallatin #endif /* __alpha__ */
6063f3a4815SMarcel Moolenaar 
6074af27623STim J. Robbins 	error = linux_getsockaddr(&sa,
6084af27623STim J. Robbins 	    (struct osockaddr *)PTRIN(linux_args.name),
6094d45de74SDavid Malone 	    linux_args.namelen);
610ca26842eSHajimu UMEMOTO 	if (error)
611ca26842eSHajimu UMEMOTO 		return (error);
612ca26842eSHajimu UMEMOTO 
613ca26842eSHajimu UMEMOTO 	error = kern_connect(td, linux_args.s, sa);
6140bf301c0SJonathan Lemon 	if (error != EISCONN)
6150bf301c0SJonathan Lemon 		return (error);
6160bf301c0SJonathan Lemon 
617dad3b88aSMike Smith 	/*
618dad3b88aSMike Smith 	 * Linux doesn't return EISCONN the first time it occurs,
619dad3b88aSMike Smith 	 * when on a non-blocking socket. Instead it returns the
620dad3b88aSMike Smith 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
621dad3b88aSMike Smith 	 */
62239c95b83SMatthew Dillon 	if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0)
6233f3a4815SMarcel Moolenaar 		return(error);
6240bf301c0SJonathan Lemon 	error = EISCONN;
62539c95b83SMatthew Dillon 	if (fflag & FNONBLOCK) {
6265002a60fSMarcel Moolenaar 		if (so->so_emuldata == 0)
6270bf301c0SJonathan Lemon 			error = so->so_error;
6280bf301c0SJonathan Lemon 		so->so_emuldata = (void *)1;
629dad3b88aSMike Smith 	}
63039c95b83SMatthew Dillon 	fputsock(so);
6313f3a4815SMarcel Moolenaar 	return (error);
632c21dee17SSøren Schmidt }
633c21dee17SSøren Schmidt 
634930a65feSAndrew Gallatin #ifndef __alpha__
635930a65feSAndrew Gallatin 
636c21dee17SSøren Schmidt struct linux_listen_args {
637c21dee17SSøren Schmidt 	int s;
638c21dee17SSøren Schmidt 	int backlog;
639c21dee17SSøren Schmidt };
640c21dee17SSøren Schmidt 
641c21dee17SSøren Schmidt static int
642b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
643c21dee17SSøren Schmidt {
644c21dee17SSøren Schmidt 	struct linux_listen_args linux_args;
645ef04503dSPeter Wemm 	struct listen_args /* {
646c21dee17SSøren Schmidt 		int s;
647c21dee17SSøren Schmidt 		int backlog;
648ef04503dSPeter Wemm 	} */ bsd_args;
649c21dee17SSøren Schmidt 	int error;
650c21dee17SSøren Schmidt 
6513f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6523f3a4815SMarcel Moolenaar 		return (error);
6533f3a4815SMarcel Moolenaar 
654c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
655c21dee17SSøren Schmidt 	bsd_args.backlog = linux_args.backlog;
656b40ce416SJulian Elischer 	return (listen(td, &bsd_args));
657c21dee17SSøren Schmidt }
658c21dee17SSøren Schmidt 
659c21dee17SSøren Schmidt struct linux_accept_args {
660c21dee17SSøren Schmidt 	int s;
6614af27623STim J. Robbins 	l_uintptr_t addr;
6624af27623STim J. Robbins 	l_uintptr_t namelen;
663c21dee17SSøren Schmidt };
664c21dee17SSøren Schmidt 
665c21dee17SSøren Schmidt static int
666b40ce416SJulian Elischer linux_accept(struct thread *td, struct linux_accept_args *args)
667c21dee17SSøren Schmidt {
668c21dee17SSøren Schmidt 	struct linux_accept_args linux_args;
669ef04503dSPeter Wemm 	struct accept_args /* {
670c21dee17SSøren Schmidt 		int	s;
6713db2a843SBruce Evans 		struct sockaddr * __restrict name;
6723db2a843SBruce Evans 		socklen_t * __restrict anamelen;
673ef04503dSPeter Wemm 	} */ bsd_args;
674ca26842eSHajimu UMEMOTO 	struct close_args /* {
675ca26842eSHajimu UMEMOTO 		int     fd;
676ca26842eSHajimu UMEMOTO 	} */ c_args;
6772ca25ab5SJohn Baldwin 	int error, fd;
678c21dee17SSøren Schmidt 
6793f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6803f3a4815SMarcel Moolenaar 		return (error);
6813f3a4815SMarcel Moolenaar 
682c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
6833db2a843SBruce Evans 	/* XXX: */
6844af27623STim J. Robbins 	bsd_args.name = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
6854af27623STim J. Robbins 	bsd_args.anamelen = PTRIN(linux_args.namelen);/* XXX */
686044af7c3SJonathan Mini 	error = oaccept(td, &bsd_args);
687dba5ab66SMarcel Moolenaar 	if (error)
688dba5ab66SMarcel Moolenaar 		return (error);
689ca26842eSHajimu UMEMOTO 	if (linux_args.addr) {
6904af27623STim J. Robbins 		error = linux_sa_put(PTRIN(linux_args.addr));
691ca26842eSHajimu UMEMOTO 		if (error) {
692ca26842eSHajimu UMEMOTO 			c_args.fd = td->td_retval[0];
693ca26842eSHajimu UMEMOTO 			(void)close(td, &c_args);
694ca26842eSHajimu UMEMOTO 			return (error);
695ca26842eSHajimu UMEMOTO 		}
696ca26842eSHajimu UMEMOTO 	}
697dba5ab66SMarcel Moolenaar 
698dba5ab66SMarcel Moolenaar 	/*
699dba5ab66SMarcel Moolenaar 	 * linux appears not to copy flags from the parent socket to the
700dba5ab66SMarcel Moolenaar 	 * accepted one, so we must clear the flags in the new descriptor.
701dba5ab66SMarcel Moolenaar 	 * Ignore any errors, because we already have an open fd.
702dba5ab66SMarcel Moolenaar 	 */
7032ca25ab5SJohn Baldwin 	fd = td->td_retval[0];
7042ca25ab5SJohn Baldwin 	(void)kern_fcntl(td, fd, F_SETFL, 0);
7052ca25ab5SJohn Baldwin 	td->td_retval[0] = fd;
706dba5ab66SMarcel Moolenaar 	return (0);
707c21dee17SSøren Schmidt }
708c21dee17SSøren Schmidt 
709c21dee17SSøren Schmidt struct linux_getsockname_args {
710c21dee17SSøren Schmidt 	int s;
7114af27623STim J. Robbins 	l_uintptr_t addr;
7124af27623STim J. Robbins 	l_uintptr_t namelen;
713c21dee17SSøren Schmidt };
714c21dee17SSøren Schmidt 
715c21dee17SSøren Schmidt static int
716b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
717c21dee17SSøren Schmidt {
718c21dee17SSøren Schmidt 	struct linux_getsockname_args linux_args;
719ef04503dSPeter Wemm 	struct getsockname_args /* {
720c21dee17SSøren Schmidt 		int	fdes;
7213db2a843SBruce Evans 		struct sockaddr * __restrict asa;
7223db2a843SBruce Evans 		socklen_t * __restrict alen;
723ef04503dSPeter Wemm 	} */ bsd_args;
724c21dee17SSøren Schmidt 	int error;
725c21dee17SSøren Schmidt 
7263f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7273f3a4815SMarcel Moolenaar 		return (error);
7283f3a4815SMarcel Moolenaar 
729c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
7303db2a843SBruce Evans 	/* XXX: */
7314af27623STim J. Robbins 	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
7324af27623STim J. Robbins 	bsd_args.alen = PTRIN(linux_args.namelen);	/* XXX */
733ca26842eSHajimu UMEMOTO 	error = ogetsockname(td, &bsd_args);
734ca26842eSHajimu UMEMOTO 	if (error)
735ca26842eSHajimu UMEMOTO 		return (error);
7364af27623STim J. Robbins 	error = linux_sa_put(PTRIN(linux_args.addr));
737ca26842eSHajimu UMEMOTO 	if (error)
738ca26842eSHajimu UMEMOTO 		return (error);
739ca26842eSHajimu UMEMOTO 	return (0);
740c21dee17SSøren Schmidt }
741c21dee17SSøren Schmidt 
742c21dee17SSøren Schmidt struct linux_getpeername_args {
743c21dee17SSøren Schmidt 	int s;
7444af27623STim J. Robbins 	l_uintptr_t addr;
7454af27623STim J. Robbins 	l_uintptr_t namelen;
746c21dee17SSøren Schmidt };
747c21dee17SSøren Schmidt 
748c21dee17SSøren Schmidt static int
749b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
750c21dee17SSøren Schmidt {
751c21dee17SSøren Schmidt 	struct linux_getpeername_args linux_args;
752044af7c3SJonathan Mini 	struct ogetpeername_args /* {
753c21dee17SSøren Schmidt 		int fdes;
754c21dee17SSøren Schmidt 		caddr_t asa;
755c21dee17SSøren Schmidt 		int *alen;
756ef04503dSPeter Wemm 	} */ bsd_args;
757c21dee17SSøren Schmidt 	int error;
758c21dee17SSøren Schmidt 
7593f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7603f3a4815SMarcel Moolenaar 		return (error);
7613f3a4815SMarcel Moolenaar 
762c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
7634af27623STim J. Robbins 	bsd_args.asa = (caddr_t)PTRIN(linux_args.addr);
7644af27623STim J. Robbins 	bsd_args.alen = (int *)PTRIN(linux_args.namelen);
765ca26842eSHajimu UMEMOTO 	error = ogetpeername(td, &bsd_args);
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 
774c21dee17SSøren Schmidt struct linux_socketpair_args {
775c21dee17SSøren Schmidt 	int domain;
776c21dee17SSøren Schmidt 	int type;
777c21dee17SSøren Schmidt 	int protocol;
7784af27623STim J. Robbins 	l_uintptr_t rsv;
779c21dee17SSøren Schmidt };
780c21dee17SSøren Schmidt 
781c21dee17SSøren Schmidt static int
782b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
783c21dee17SSøren Schmidt {
784c21dee17SSøren Schmidt 	struct linux_socketpair_args linux_args;
785ef04503dSPeter Wemm 	struct socketpair_args /* {
786c21dee17SSøren Schmidt 		int domain;
787c21dee17SSøren Schmidt 		int type;
788c21dee17SSøren Schmidt 		int protocol;
789c21dee17SSøren Schmidt 		int *rsv;
790ef04503dSPeter Wemm 	} */ bsd_args;
791c21dee17SSøren Schmidt 	int error;
792c21dee17SSøren Schmidt 
7933f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7943f3a4815SMarcel Moolenaar 		return (error);
7953f3a4815SMarcel Moolenaar 
796c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
797c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
7983f3a4815SMarcel Moolenaar 		return (EINVAL);
7993f3a4815SMarcel Moolenaar 
800c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
801c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
8024af27623STim J. Robbins 	bsd_args.rsv = (int *)PTRIN(linux_args.rsv);
803b40ce416SJulian Elischer 	return (socketpair(td, &bsd_args));
804c21dee17SSøren Schmidt }
805c21dee17SSøren Schmidt 
806c21dee17SSøren Schmidt struct linux_send_args {
807c21dee17SSøren Schmidt 	int s;
8084af27623STim J. Robbins 	l_uintptr_t msg;
809c21dee17SSøren Schmidt 	int len;
810c21dee17SSøren Schmidt 	int flags;
811c21dee17SSøren Schmidt };
812c21dee17SSøren Schmidt 
813c21dee17SSøren Schmidt static int
814b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
815c21dee17SSøren Schmidt {
816c21dee17SSøren Schmidt 	struct linux_send_args linux_args;
81787d72a8fSPoul-Henning Kamp 	struct sendto_args /* {
818c21dee17SSøren Schmidt 		int s;
819c21dee17SSøren Schmidt 		caddr_t buf;
820044af7c3SJonathan Mini 		int len;
821c21dee17SSøren Schmidt 		int flags;
82287d72a8fSPoul-Henning Kamp 		caddr_t to;
82387d72a8fSPoul-Henning Kamp 		int tolen;
824ef04503dSPeter Wemm 	} */ bsd_args;
825c21dee17SSøren Schmidt 	int error;
826c21dee17SSøren Schmidt 
8273f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8283f3a4815SMarcel Moolenaar 		return (error);
8293f3a4815SMarcel Moolenaar 
830c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
8314af27623STim J. Robbins 	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
832c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
833c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
83487d72a8fSPoul-Henning Kamp 	bsd_args.to = NULL;
83587d72a8fSPoul-Henning Kamp 	bsd_args.tolen = 0;
83687d72a8fSPoul-Henning Kamp 	return (sendto(td, &bsd_args));
837c21dee17SSøren Schmidt }
838c21dee17SSøren Schmidt 
839c21dee17SSøren Schmidt struct linux_recv_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 
846c21dee17SSøren Schmidt static int
847b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
848c21dee17SSøren Schmidt {
849c21dee17SSøren Schmidt 	struct linux_recv_args linux_args;
85087d72a8fSPoul-Henning Kamp 	struct recvfrom_args /* {
851c21dee17SSøren Schmidt 		int s;
852c21dee17SSøren Schmidt 		caddr_t buf;
853c21dee17SSøren Schmidt 		int len;
854c21dee17SSøren Schmidt 		int flags;
85587d72a8fSPoul-Henning Kamp 		struct sockaddr *from;
85687d72a8fSPoul-Henning Kamp 		socklen_t fromlenaddr;
857ef04503dSPeter Wemm 	} */ bsd_args;
858c21dee17SSøren Schmidt 	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.from = NULL;
86887d72a8fSPoul-Henning Kamp 	bsd_args.fromlenaddr = 0;
86987d72a8fSPoul-Henning Kamp 	return (recvfrom(td, &bsd_args));
870c21dee17SSøren Schmidt }
871c21dee17SSøren Schmidt 
872c21dee17SSøren Schmidt static int
873b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
874c21dee17SSøren Schmidt {
875c21dee17SSøren Schmidt 	struct linux_sendto_args linux_args;
8765a8a13e0SDavid Malone 	struct msghdr msg;
8775a8a13e0SDavid Malone 	struct iovec aiov;
8785a8a13e0SDavid Malone 	int error;
879c21dee17SSøren Schmidt 
8803f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8813f3a4815SMarcel Moolenaar 		return (error);
8823f3a4815SMarcel Moolenaar 
883e140eb43SDavid Malone 	if (linux_check_hdrincl(td, linux_args.s) == 0)
884f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
885e140eb43SDavid Malone 		return (linux_sendto_hdrincl(td, &linux_args));
886f2477ae1SMike Smith 
8874af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args.to);
8885a8a13e0SDavid Malone 	msg.msg_namelen = linux_args.tolen;
8895a8a13e0SDavid Malone 	msg.msg_iov = &aiov;
8905a8a13e0SDavid Malone 	msg.msg_iovlen = 1;
8915a8a13e0SDavid Malone 	msg.msg_control = NULL;
8925a8a13e0SDavid Malone 	msg.msg_flags = 0;
8934af27623STim J. Robbins 	aiov.iov_base = PTRIN(linux_args.msg);
8945a8a13e0SDavid Malone 	aiov.iov_len = linux_args.len;
8955a8a13e0SDavid Malone 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags);
8965a8a13e0SDavid Malone 	return (error);
897c21dee17SSøren Schmidt }
898c21dee17SSøren Schmidt 
899c21dee17SSøren Schmidt struct linux_recvfrom_args {
900c21dee17SSøren Schmidt 	int s;
9014af27623STim J. Robbins 	l_uintptr_t buf;
902c21dee17SSøren Schmidt 	int len;
903c21dee17SSøren Schmidt 	int flags;
9044af27623STim J. Robbins 	l_uintptr_t from;
9054af27623STim J. Robbins 	l_uintptr_t fromlen;
906c21dee17SSøren Schmidt };
907c21dee17SSøren Schmidt 
908c21dee17SSøren Schmidt static int
909b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
910c21dee17SSøren Schmidt {
911c21dee17SSøren Schmidt 	struct linux_recvfrom_args linux_args;
912ef04503dSPeter Wemm 	struct recvfrom_args /* {
913c21dee17SSøren Schmidt 		int	s;
914c21dee17SSøren Schmidt 		caddr_t	buf;
915c21dee17SSøren Schmidt 		size_t	len;
916c21dee17SSøren Schmidt 		int	flags;
9173db2a843SBruce Evans 		struct sockaddr * __restrict from;
9183db2a843SBruce Evans 		socklen_t * __restrict fromlenaddr;
919ef04503dSPeter Wemm 	} */ bsd_args;
920c21dee17SSøren Schmidt 	int error;
921c21dee17SSøren Schmidt 
9223f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
9233f3a4815SMarcel Moolenaar 		return (error);
9243f3a4815SMarcel Moolenaar 
925c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
9264af27623STim J. Robbins 	bsd_args.buf = PTRIN(linux_args.buf);
927c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
92840dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
9293db2a843SBruce Evans 	/* XXX: */
9304af27623STim J. Robbins 	bsd_args.from = (struct sockaddr * __restrict)PTRIN(linux_args.from);
9314af27623STim J. Robbins 	bsd_args.fromlenaddr = PTRIN(linux_args.fromlen);/* XXX */
932ca26842eSHajimu UMEMOTO 	error = orecvfrom(td, &bsd_args);
933ca26842eSHajimu UMEMOTO 	if (error)
934ca26842eSHajimu UMEMOTO 		return (error);
935ca26842eSHajimu UMEMOTO 	if (linux_args.from) {
9364af27623STim J. Robbins 		error = linux_sa_put((struct osockaddr *)
9374af27623STim J. Robbins 		    PTRIN(linux_args.from));
938ca26842eSHajimu UMEMOTO 		if (error)
939ca26842eSHajimu UMEMOTO 			return (error);
940ca26842eSHajimu UMEMOTO 	}
941ca26842eSHajimu UMEMOTO 	return (0);
942ca26842eSHajimu UMEMOTO }
943ca26842eSHajimu UMEMOTO 
944ca26842eSHajimu UMEMOTO struct linux_sendmsg_args {
945ca26842eSHajimu UMEMOTO 	int s;
9464af27623STim J. Robbins 	l_uintptr_t msg;
947ca26842eSHajimu UMEMOTO 	int flags;
948ca26842eSHajimu UMEMOTO };
949ca26842eSHajimu UMEMOTO 
950ca26842eSHajimu UMEMOTO static int
951ca26842eSHajimu UMEMOTO linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
952ca26842eSHajimu UMEMOTO {
953ca26842eSHajimu UMEMOTO 	struct linux_sendmsg_args linux_args;
954ca26842eSHajimu UMEMOTO 	struct msghdr msg;
955552afd9cSPoul-Henning Kamp 	struct iovec *iov;
956ca26842eSHajimu UMEMOTO 	int error;
957ca26842eSHajimu UMEMOTO 
9584af27623STim J. Robbins 	/* XXXTJR sendmsg is broken on amd64 */
9594af27623STim J. Robbins 
960552afd9cSPoul-Henning Kamp 	error = copyin(args, &linux_args, sizeof(linux_args));
961552afd9cSPoul-Henning Kamp 	if (error)
962ca26842eSHajimu UMEMOTO 		return (error);
9634af27623STim J. Robbins 	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
964ca26842eSHajimu UMEMOTO 	if (error)
965ca26842eSHajimu UMEMOTO 		return (error);
966552afd9cSPoul-Henning Kamp 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
967552afd9cSPoul-Henning Kamp 	if (error)
968552afd9cSPoul-Henning Kamp 		return (error);
9695a8a13e0SDavid Malone 	msg.msg_iov = iov;
9705a8a13e0SDavid Malone 	msg.msg_flags = 0;
9715a8a13e0SDavid Malone 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags);
972552afd9cSPoul-Henning Kamp 	free(iov, M_IOV);
973ca26842eSHajimu UMEMOTO 	return (error);
974c21dee17SSøren Schmidt }
975c21dee17SSøren Schmidt 
97640dbba57SAssar Westerlund struct linux_recvmsg_args {
97740dbba57SAssar Westerlund 	int s;
9784af27623STim J. Robbins 	l_uintptr_t msg;
97940dbba57SAssar Westerlund 	int flags;
98040dbba57SAssar Westerlund };
98140dbba57SAssar Westerlund 
98240dbba57SAssar Westerlund static int
983b40ce416SJulian Elischer linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
98440dbba57SAssar Westerlund {
98540dbba57SAssar Westerlund 	struct linux_recvmsg_args linux_args;
98640dbba57SAssar Westerlund 	struct recvmsg_args /* {
98740dbba57SAssar Westerlund 		int	s;
98840dbba57SAssar Westerlund 		struct	msghdr *msg;
98940dbba57SAssar Westerlund 		int	flags;
99040dbba57SAssar Westerlund 	} */ bsd_args;
991ca26842eSHajimu UMEMOTO 	struct msghdr msg;
99284b11cd8SMitsuru IWASAKI 	struct cmsghdr *cmsg;
99340dbba57SAssar Westerlund 	int error;
99440dbba57SAssar Westerlund 
9954af27623STim J. Robbins 	/* XXXTJR recvmsg is broken on amd64 */
9964af27623STim J. Robbins 
99740dbba57SAssar Westerlund 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
99840dbba57SAssar Westerlund 		return (error);
99940dbba57SAssar Westerlund 
100040dbba57SAssar Westerlund 	bsd_args.s = linux_args.s;
10014af27623STim J. Robbins 	bsd_args.msg = PTRIN(linux_args.msg);
100240dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
1003ca26842eSHajimu UMEMOTO 	error = recvmsg(td, &bsd_args);
1004ca26842eSHajimu UMEMOTO 	if (error)
1005ca26842eSHajimu UMEMOTO 		return (error);
1006ca26842eSHajimu UMEMOTO 
100772261b9fSDag-Erling Smørgrav 	if (bsd_args.msg->msg_control != NULL &&
100872261b9fSDag-Erling Smørgrav 	    bsd_args.msg->msg_controllen > 0) {
100984b11cd8SMitsuru IWASAKI 		cmsg = (struct cmsghdr*)bsd_args.msg->msg_control;
101084b11cd8SMitsuru IWASAKI 		cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level);
101184b11cd8SMitsuru IWASAKI 	}
101284b11cd8SMitsuru IWASAKI 
10134af27623STim J. Robbins 	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1014ca26842eSHajimu UMEMOTO 	if (error)
1015ca26842eSHajimu UMEMOTO 		return (error);
1016ca26842eSHajimu UMEMOTO 	if (msg.msg_name && msg.msg_namelen > 2)
1017ca26842eSHajimu UMEMOTO 		error = linux_sa_put(msg.msg_name);
1018ca26842eSHajimu UMEMOTO 	return (error);
101940dbba57SAssar Westerlund }
102040dbba57SAssar Westerlund 
1021c21dee17SSøren Schmidt struct linux_shutdown_args {
1022c21dee17SSøren Schmidt 	int s;
1023c21dee17SSøren Schmidt 	int how;
1024c21dee17SSøren Schmidt };
1025c21dee17SSøren Schmidt 
1026c21dee17SSøren Schmidt static int
1027b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1028c21dee17SSøren Schmidt {
1029c21dee17SSøren Schmidt 	struct linux_shutdown_args linux_args;
1030ef04503dSPeter Wemm 	struct shutdown_args /* {
1031c21dee17SSøren Schmidt 		int s;
1032c21dee17SSøren Schmidt 		int how;
1033ef04503dSPeter Wemm 	} */ bsd_args;
1034c21dee17SSøren Schmidt 	int error;
1035c21dee17SSøren Schmidt 
10363f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
10373f3a4815SMarcel Moolenaar 		return (error);
10383f3a4815SMarcel Moolenaar 
1039c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1040c21dee17SSøren Schmidt 	bsd_args.how = linux_args.how;
1041b40ce416SJulian Elischer 	return (shutdown(td, &bsd_args));
1042c21dee17SSøren Schmidt }
1043c21dee17SSøren Schmidt 
1044c21dee17SSøren Schmidt struct linux_setsockopt_args {
1045c21dee17SSøren Schmidt 	int s;
1046c21dee17SSøren Schmidt 	int level;
1047c21dee17SSøren Schmidt 	int optname;
10484af27623STim J. Robbins 	l_uintptr_t optval;
1049c21dee17SSøren Schmidt 	int optlen;
1050c21dee17SSøren Schmidt };
1051c21dee17SSøren Schmidt 
1052c21dee17SSøren Schmidt static int
1053b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1054c21dee17SSøren Schmidt {
1055c21dee17SSøren Schmidt 	struct linux_setsockopt_args linux_args;
1056ef04503dSPeter Wemm 	struct setsockopt_args /* {
1057c21dee17SSøren Schmidt 		int s;
1058c21dee17SSøren Schmidt 		int level;
1059c21dee17SSøren Schmidt 		int name;
1060c21dee17SSøren Schmidt 		caddr_t val;
1061c21dee17SSøren Schmidt 		int valsize;
1062ef04503dSPeter Wemm 	} */ bsd_args;
1063c21dee17SSøren Schmidt 	int error, name;
1064c21dee17SSøren Schmidt 
10653f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
10663f3a4815SMarcel Moolenaar 		return (error);
10673f3a4815SMarcel Moolenaar 
1068c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1069c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1070c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1071c21dee17SSøren Schmidt 	case SOL_SOCKET:
1072c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1073c21dee17SSøren Schmidt 		break;
1074c21dee17SSøren Schmidt 	case IPPROTO_IP:
1075c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1076c21dee17SSøren Schmidt 		break;
1077dad3b88aSMike Smith 	case IPPROTO_TCP:
1078dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1079dad3b88aSMike Smith 		name = linux_args.optname;
1080dad3b88aSMike Smith 		break;
1081c21dee17SSøren Schmidt 	default:
10823f3a4815SMarcel Moolenaar 		name = -1;
10833f3a4815SMarcel Moolenaar 		break;
1084c21dee17SSøren Schmidt 	}
1085c21dee17SSøren Schmidt 	if (name == -1)
10863f3a4815SMarcel Moolenaar 		return (EINVAL);
10873f3a4815SMarcel Moolenaar 
1088c21dee17SSøren Schmidt 	bsd_args.name = name;
10894af27623STim J. Robbins 	bsd_args.val = PTRIN(linux_args.optval);
1090c21dee17SSøren Schmidt 	bsd_args.valsize = linux_args.optlen;
1091b40ce416SJulian Elischer 	return (setsockopt(td, &bsd_args));
1092c21dee17SSøren Schmidt }
1093c21dee17SSøren Schmidt 
1094c21dee17SSøren Schmidt struct linux_getsockopt_args {
1095c21dee17SSøren Schmidt 	int s;
1096c21dee17SSøren Schmidt 	int level;
1097c21dee17SSøren Schmidt 	int optname;
10984af27623STim J. Robbins 	l_uintptr_t optval;
10994af27623STim J. Robbins 	l_uintptr_t optlen;
1100c21dee17SSøren Schmidt };
1101c21dee17SSøren Schmidt 
1102c21dee17SSøren Schmidt static int
1103b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1104c21dee17SSøren Schmidt {
1105c21dee17SSøren Schmidt 	struct linux_getsockopt_args linux_args;
1106ef04503dSPeter Wemm 	struct getsockopt_args /* {
1107c21dee17SSøren Schmidt 		int s;
1108c21dee17SSøren Schmidt 		int level;
1109c21dee17SSøren Schmidt 		int name;
1110c21dee17SSøren Schmidt 		caddr_t val;
1111c21dee17SSøren Schmidt 		int *avalsize;
1112ef04503dSPeter Wemm 	} */ bsd_args;
1113c21dee17SSøren Schmidt 	int error, name;
1114c21dee17SSøren Schmidt 
11153f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
11163f3a4815SMarcel Moolenaar 		return (error);
11173f3a4815SMarcel Moolenaar 
1118c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1119c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1120c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1121c21dee17SSøren Schmidt 	case SOL_SOCKET:
1122c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1123c21dee17SSøren Schmidt 		break;
1124c21dee17SSøren Schmidt 	case IPPROTO_IP:
1125c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1126c21dee17SSøren Schmidt 		break;
1127dad3b88aSMike Smith 	case IPPROTO_TCP:
1128dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1129dad3b88aSMike Smith 		name = linux_args.optname;
1130dad3b88aSMike Smith 		break;
1131c21dee17SSøren Schmidt 	default:
11323f3a4815SMarcel Moolenaar 		name = -1;
11333f3a4815SMarcel Moolenaar 		break;
1134c21dee17SSøren Schmidt 	}
1135c21dee17SSøren Schmidt 	if (name == -1)
11363f3a4815SMarcel Moolenaar 		return (EINVAL);
11373f3a4815SMarcel Moolenaar 
1138f2477ae1SMike Smith 	bsd_args.name = name;
11394af27623STim J. Robbins 	bsd_args.val = PTRIN(linux_args.optval);
11404af27623STim J. Robbins 	bsd_args.avalsize = PTRIN(linux_args.optlen);
1141b40ce416SJulian Elischer 	return (getsockopt(td, &bsd_args));
1142c21dee17SSøren Schmidt }
1143c21dee17SSøren Schmidt 
1144c21dee17SSøren Schmidt int
1145b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1146c21dee17SSøren Schmidt {
11474af27623STim J. Robbins 	void *arg = (void *)(intptr_t)args->args;
11483f3a4815SMarcel Moolenaar 
1149c21dee17SSøren Schmidt 	switch (args->what) {
1150c21dee17SSøren Schmidt 	case LINUX_SOCKET:
1151b40ce416SJulian Elischer 		return (linux_socket(td, arg));
1152c21dee17SSøren Schmidt 	case LINUX_BIND:
1153b40ce416SJulian Elischer 		return (linux_bind(td, arg));
1154c21dee17SSøren Schmidt 	case LINUX_CONNECT:
1155b40ce416SJulian Elischer 		return (linux_connect(td, arg));
1156c21dee17SSøren Schmidt 	case LINUX_LISTEN:
1157b40ce416SJulian Elischer 		return (linux_listen(td, arg));
1158c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
1159b40ce416SJulian Elischer 		return (linux_accept(td, arg));
1160c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
1161b40ce416SJulian Elischer 		return (linux_getsockname(td, arg));
1162c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
1163b40ce416SJulian Elischer 		return (linux_getpeername(td, arg));
1164c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
1165b40ce416SJulian Elischer 		return (linux_socketpair(td, arg));
1166c21dee17SSøren Schmidt 	case LINUX_SEND:
1167b40ce416SJulian Elischer 		return (linux_send(td, arg));
1168c21dee17SSøren Schmidt 	case LINUX_RECV:
1169b40ce416SJulian Elischer 		return (linux_recv(td, arg));
1170c21dee17SSøren Schmidt 	case LINUX_SENDTO:
1171b40ce416SJulian Elischer 		return (linux_sendto(td, arg));
1172c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
1173b40ce416SJulian Elischer 		return (linux_recvfrom(td, arg));
1174c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
1175b40ce416SJulian Elischer 		return (linux_shutdown(td, arg));
1176c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
1177b40ce416SJulian Elischer 		return (linux_setsockopt(td, arg));
1178c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
1179b40ce416SJulian Elischer 		return (linux_getsockopt(td, arg));
1180e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
1181ca26842eSHajimu UMEMOTO 		return (linux_sendmsg(td, arg));
1182e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
1183b40ce416SJulian Elischer 		return (linux_recvmsg(td, arg));
1184c21dee17SSøren Schmidt 	}
11853f3a4815SMarcel Moolenaar 
11863f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
11873f3a4815SMarcel Moolenaar 	return (ENOSYS);
1188c21dee17SSøren Schmidt }
11895231fb20SDavid E. O'Brien #endif	/*!__alpha__*/
1190