xref: /freebsd/sys/compat/linux/linux_socket.c (revision 3933bde22e2b21e4be54f033529b164b72aca3ea)
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>
52d0b2365eSKonstantin Belousov #include <sys/un.h>
53603724d3SBjoern A. Zeeb #include <sys/vimage.h>
541f3dad5aSBruce Evans 
554b79449eSBjoern A. Zeeb #include <net/if.h>
56c21dee17SSøren Schmidt #include <netinet/in.h>
57f2477ae1SMike Smith #include <netinet/in_systm.h>
58f2477ae1SMike Smith #include <netinet/ip.h>
59ca26842eSHajimu UMEMOTO #ifdef INET6
60ca26842eSHajimu UMEMOTO #include <netinet/ip6.h>
61ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h>
624b79449eSBjoern A. Zeeb #include <netinet6/in6_var.h>
634b79449eSBjoern A. Zeeb #include <netinet6/vinet6.h>
64ca26842eSHajimu UMEMOTO #endif
65c21dee17SSøren Schmidt 
661997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
674af27623STim J. Robbins #include <machine/../linux32/linux.h>
684af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
691997c537SDavid E. O'Brien #else
701997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
711997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
724af27623STim J. Robbins #endif
7340dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
74ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
75c21dee17SSøren Schmidt 
76ca26842eSHajimu UMEMOTO static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
77ca26842eSHajimu UMEMOTO     struct malloc_type *);
78ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int);
79ca26842eSHajimu UMEMOTO 
804730796cSBill Fenner /*
81ca26842eSHajimu UMEMOTO  * Reads a linux sockaddr and does any necessary translation.
82ca26842eSHajimu UMEMOTO  * Linux sockaddrs don't have a length field, only a family.
834730796cSBill Fenner  */
844730796cSBill Fenner static int
85ca26842eSHajimu UMEMOTO linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
864730796cSBill Fenner {
87ca26842eSHajimu UMEMOTO 	int osalen = len;
884730796cSBill Fenner 
89ca26842eSHajimu UMEMOTO 	return (do_sa_get(sap, osa, &osalen, M_SONAME));
904730796cSBill Fenner }
914730796cSBill Fenner 
92ca26842eSHajimu UMEMOTO /*
93ca26842eSHajimu UMEMOTO  * Copy the osockaddr structure pointed to by osa to kernel, adjust
94ca26842eSHajimu UMEMOTO  * family and convert to sockaddr.
95ca26842eSHajimu UMEMOTO  */
96ca26842eSHajimu UMEMOTO static int
97ca26842eSHajimu UMEMOTO do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
98ca26842eSHajimu UMEMOTO     struct malloc_type *mtype)
99ca26842eSHajimu UMEMOTO {
100ca26842eSHajimu UMEMOTO 	int error=0, bdom;
101ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
102ca26842eSHajimu UMEMOTO 	struct osockaddr *kosa;
103ca26842eSHajimu UMEMOTO 	int alloclen;
104ca26842eSHajimu UMEMOTO #ifdef INET6
105ca26842eSHajimu UMEMOTO 	int oldv6size;
106ca26842eSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
107ca26842eSHajimu UMEMOTO #endif
108ca26842eSHajimu UMEMOTO 
109ca26842eSHajimu UMEMOTO 	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
110ca26842eSHajimu UMEMOTO 		return (EINVAL);
111ca26842eSHajimu UMEMOTO 
112ca26842eSHajimu UMEMOTO 	alloclen = *osalen;
113ca26842eSHajimu UMEMOTO #ifdef INET6
114ca26842eSHajimu UMEMOTO 	oldv6size = 0;
115ca26842eSHajimu UMEMOTO 	/*
116ca26842eSHajimu UMEMOTO 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
117ca26842eSHajimu UMEMOTO 	 * if it's a v4-mapped address, so reserve the proper space
118ca26842eSHajimu UMEMOTO 	 * for it.
119ca26842eSHajimu UMEMOTO 	 */
120ca26842eSHajimu UMEMOTO 	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
121ca26842eSHajimu UMEMOTO 		alloclen = sizeof (struct sockaddr_in6);
122ca26842eSHajimu UMEMOTO 		oldv6size = 1;
123ca26842eSHajimu UMEMOTO 	}
124ca26842eSHajimu UMEMOTO #endif
125ca26842eSHajimu UMEMOTO 
1261ede983cSDag-Erling Smørgrav 	kosa = malloc(alloclen, mtype, M_WAITOK);
127ca26842eSHajimu UMEMOTO 
1284b7ef73dSDag-Erling Smørgrav 	if ((error = copyin(osa, kosa, *osalen)))
129ca26842eSHajimu UMEMOTO 		goto out;
130ca26842eSHajimu UMEMOTO 
131ca26842eSHajimu UMEMOTO 	bdom = linux_to_bsd_domain(kosa->sa_family);
132ca26842eSHajimu UMEMOTO 	if (bdom == -1) {
133ca26842eSHajimu UMEMOTO 		error = EINVAL;
134ca26842eSHajimu UMEMOTO 		goto out;
135ca26842eSHajimu UMEMOTO 	}
136ca26842eSHajimu UMEMOTO 
137ca26842eSHajimu UMEMOTO #ifdef INET6
138ca26842eSHajimu UMEMOTO 	/*
139ca26842eSHajimu UMEMOTO 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
140ca26842eSHajimu UMEMOTO 	 * which lacks the scope id compared with RFC2553 one. If we detect
141ca26842eSHajimu UMEMOTO 	 * the situation, reject the address and write a message to system log.
142ca26842eSHajimu UMEMOTO 	 *
143ca26842eSHajimu UMEMOTO 	 * Still accept addresses for which the scope id is not used.
144ca26842eSHajimu UMEMOTO 	 */
145ca26842eSHajimu UMEMOTO 	if (oldv6size && bdom == AF_INET6) {
146ca26842eSHajimu UMEMOTO 		sin6 = (struct sockaddr_in6 *)kosa;
147ca26842eSHajimu UMEMOTO 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
148ca26842eSHajimu UMEMOTO 		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
149ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
150ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
151ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
152ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
153ca26842eSHajimu UMEMOTO 			sin6->sin6_scope_id = 0;
154ca26842eSHajimu UMEMOTO 		} else {
155ca26842eSHajimu UMEMOTO 			log(LOG_DEBUG,
1563c616032SGleb Smirnoff 			    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
157ca26842eSHajimu UMEMOTO 			error = EINVAL;
158ca26842eSHajimu UMEMOTO 			goto out;
159ca26842eSHajimu UMEMOTO 		}
160ca26842eSHajimu UMEMOTO 	} else
161ca26842eSHajimu UMEMOTO #endif
162ca26842eSHajimu UMEMOTO 	if (bdom == AF_INET)
163ca26842eSHajimu UMEMOTO 		alloclen = sizeof(struct sockaddr_in);
164ca26842eSHajimu UMEMOTO 
165ca26842eSHajimu UMEMOTO 	sa = (struct sockaddr *) kosa;
166ca26842eSHajimu UMEMOTO 	sa->sa_family = bdom;
167ca26842eSHajimu UMEMOTO 	sa->sa_len = alloclen;
168ca26842eSHajimu UMEMOTO 
169ca26842eSHajimu UMEMOTO 	*sap = sa;
170ca26842eSHajimu UMEMOTO 	*osalen = alloclen;
171ca26842eSHajimu UMEMOTO 	return (0);
172ca26842eSHajimu UMEMOTO 
173ca26842eSHajimu UMEMOTO out:
1741ede983cSDag-Erling Smørgrav 	free(kosa, mtype);
175ca26842eSHajimu UMEMOTO 	return (error);
176ca26842eSHajimu UMEMOTO }
177ca26842eSHajimu UMEMOTO 
178c21dee17SSøren Schmidt static int
179c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
180c21dee17SSøren Schmidt {
1813f3a4815SMarcel Moolenaar 
182c21dee17SSøren Schmidt 	switch (domain) {
183c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
1843f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
185c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
1863f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
187c21dee17SSøren Schmidt 	case LINUX_AF_INET:
1883f3a4815SMarcel Moolenaar 		return (AF_INET);
189ca26842eSHajimu UMEMOTO 	case LINUX_AF_INET6:
190ca26842eSHajimu UMEMOTO 		return (AF_INET6);
191c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
1923f3a4815SMarcel Moolenaar 		return (AF_CCITT);
193c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
1943f3a4815SMarcel Moolenaar 		return (AF_IPX);
195c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
1963f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
197c21dee17SSøren Schmidt 	}
1983f3a4815SMarcel Moolenaar 	return (-1);
199c21dee17SSøren Schmidt }
200c21dee17SSøren Schmidt 
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);
300d0b2365eSKonstantin Belousov 	case LINUX_SO_PEERCRED:
301d0b2365eSKonstantin Belousov 		return (LOCAL_PEERCRED);
302d0b2365eSKonstantin Belousov 	case LINUX_SO_RCVLOWAT:
303d0b2365eSKonstantin Belousov 		return (SO_RCVLOWAT);
304d0b2365eSKonstantin Belousov 	case LINUX_SO_SNDLOWAT:
305d0b2365eSKonstantin Belousov 		return (SO_SNDLOWAT);
306d0b2365eSKonstantin Belousov 	case LINUX_SO_RCVTIMEO:
307d0b2365eSKonstantin Belousov 		return (SO_RCVTIMEO);
308d0b2365eSKonstantin Belousov 	case LINUX_SO_SNDTIMEO:
309d0b2365eSKonstantin Belousov 		return (SO_SNDTIMEO);
310d0b2365eSKonstantin Belousov 	case LINUX_SO_TIMESTAMP:
311d0b2365eSKonstantin Belousov 		return (SO_TIMESTAMP);
312d0b2365eSKonstantin Belousov 	case LINUX_SO_ACCEPTCONN:
313d0b2365eSKonstantin Belousov 		return (SO_ACCEPTCONN);
314c21dee17SSøren Schmidt 	}
3153f3a4815SMarcel Moolenaar 	return (-1);
316c21dee17SSøren Schmidt }
317c21dee17SSøren Schmidt 
31840dbba57SAssar Westerlund static int
31940dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
32040dbba57SAssar Westerlund {
32140dbba57SAssar Westerlund 	int ret_flags = 0;
32240dbba57SAssar Westerlund 
32340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
32440dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
32540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
32640dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
32740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
32840dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
32940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
33040dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
33140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
33240dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
33340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
33440dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
33540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
33640dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
33740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
33840dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
3398d6e40c3SMaxim Sobolev 	if (flags & LINUX_MSG_NOSIGNAL)
3408d6e40c3SMaxim Sobolev 		ret_flags |= MSG_NOSIGNAL;
34140dbba57SAssar Westerlund #if 0 /* not handled */
34240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
34340dbba57SAssar Westerlund 		;
34440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
34540dbba57SAssar Westerlund 		;
34640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
34740dbba57SAssar Westerlund 		;
34840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
34940dbba57SAssar Westerlund 		;
35040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
35140dbba57SAssar Westerlund 		;
35240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
35340dbba57SAssar Westerlund 		;
35440dbba57SAssar Westerlund #endif
35540dbba57SAssar Westerlund 	return ret_flags;
35640dbba57SAssar Westerlund }
35740dbba57SAssar Westerlund 
3585c8919adSAlexander Leidinger /*
3595c8919adSAlexander Leidinger * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
3605c8919adSAlexander Leidinger * native syscall will fault.  Thus, we don't really need to check the
3615c8919adSAlexander Leidinger * return values for these functions.
3625c8919adSAlexander Leidinger */
3635c8919adSAlexander Leidinger 
3645c8919adSAlexander Leidinger static int
3655c8919adSAlexander Leidinger bsd_to_linux_sockaddr(struct sockaddr *arg)
3665c8919adSAlexander Leidinger {
3675c8919adSAlexander Leidinger 	struct sockaddr sa;
3685c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
3695c8919adSAlexander Leidinger 	int error;
3705c8919adSAlexander Leidinger 
3715c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
3725c8919adSAlexander Leidinger 		return (error);
3735c8919adSAlexander Leidinger 
3745c8919adSAlexander Leidinger 	*(u_short *)&sa = sa.sa_family;
3755c8919adSAlexander Leidinger 
3765c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
3775c8919adSAlexander Leidinger 
3785c8919adSAlexander Leidinger 	return (error);
3795c8919adSAlexander Leidinger }
3805c8919adSAlexander Leidinger 
3815c8919adSAlexander Leidinger static int
3825c8919adSAlexander Leidinger linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
3835c8919adSAlexander Leidinger {
3845c8919adSAlexander Leidinger 	struct sockaddr sa;
3855c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
3865c8919adSAlexander Leidinger 	int error;
3875c8919adSAlexander Leidinger 
3885c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
3895c8919adSAlexander Leidinger 		return (error);
3905c8919adSAlexander Leidinger 
3915c8919adSAlexander Leidinger 	sa.sa_family = *(sa_family_t *)&sa;
3925c8919adSAlexander Leidinger 	sa.sa_len = len;
3935c8919adSAlexander Leidinger 
3945c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
3955c8919adSAlexander Leidinger 
3965c8919adSAlexander Leidinger 	return (error);
3975c8919adSAlexander Leidinger }
3985c8919adSAlexander Leidinger 
3995c8919adSAlexander Leidinger 
400ca26842eSHajimu UMEMOTO static int
401ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa)
402ca26842eSHajimu UMEMOTO {
403ca26842eSHajimu UMEMOTO 	struct osockaddr sa;
404ca26842eSHajimu UMEMOTO 	int error, bdom;
405ca26842eSHajimu UMEMOTO 
406ca26842eSHajimu UMEMOTO 	/*
407ca26842eSHajimu UMEMOTO 	 * Only read/write the osockaddr family part, the rest is
408ca26842eSHajimu UMEMOTO 	 * not changed.
409ca26842eSHajimu UMEMOTO 	 */
4104b7ef73dSDag-Erling Smørgrav 	error = copyin(osa, &sa, sizeof(sa.sa_family));
411ca26842eSHajimu UMEMOTO 	if (error)
412ca26842eSHajimu UMEMOTO 		return (error);
413ca26842eSHajimu UMEMOTO 
414ca26842eSHajimu UMEMOTO 	bdom = bsd_to_linux_domain(sa.sa_family);
415ca26842eSHajimu UMEMOTO 	if (bdom == -1)
416ca26842eSHajimu UMEMOTO 		return (EINVAL);
417ca26842eSHajimu UMEMOTO 
418ca26842eSHajimu UMEMOTO 	sa.sa_family = bdom;
419ca26842eSHajimu UMEMOTO 	error = copyout(&sa, osa, sizeof(sa.sa_family));
420ca26842eSHajimu UMEMOTO 	if (error)
421ca26842eSHajimu UMEMOTO 		return (error);
422ca26842eSHajimu UMEMOTO 
423ca26842eSHajimu UMEMOTO 	return (0);
424ca26842eSHajimu UMEMOTO }
425ca26842eSHajimu UMEMOTO 
4265a8a13e0SDavid Malone static int
42774f5d680SKonstantin Belousov linux_to_bsd_cmsg_type(int cmsg_type)
4285a8a13e0SDavid Malone {
42974f5d680SKonstantin Belousov 
43074f5d680SKonstantin Belousov 	switch (cmsg_type) {
43174f5d680SKonstantin Belousov 	case LINUX_SCM_RIGHTS:
43274f5d680SKonstantin Belousov 		return (SCM_RIGHTS);
43374f5d680SKonstantin Belousov 	}
43474f5d680SKonstantin Belousov 	return (-1);
43574f5d680SKonstantin Belousov }
43674f5d680SKonstantin Belousov 
43774f5d680SKonstantin Belousov static int
43874f5d680SKonstantin Belousov bsd_to_linux_cmsg_type(int cmsg_type)
43974f5d680SKonstantin Belousov {
44074f5d680SKonstantin Belousov 
44174f5d680SKonstantin Belousov 	switch (cmsg_type) {
44274f5d680SKonstantin Belousov 	case SCM_RIGHTS:
44374f5d680SKonstantin Belousov 		return (LINUX_SCM_RIGHTS);
44474f5d680SKonstantin Belousov 	}
44574f5d680SKonstantin Belousov 	return (-1);
44674f5d680SKonstantin Belousov }
44774f5d680SKonstantin Belousov 
44874f5d680SKonstantin Belousov 
44974f5d680SKonstantin Belousov 
45074f5d680SKonstantin Belousov static int
45174f5d680SKonstantin Belousov linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
45274f5d680SKonstantin Belousov {
45374f5d680SKonstantin Belousov 	if (lhdr->msg_controllen > INT_MAX)
45474f5d680SKonstantin Belousov 		return (ENOBUFS);
45574f5d680SKonstantin Belousov 
45674f5d680SKonstantin Belousov 	bhdr->msg_name		= PTRIN(lhdr->msg_name);
45774f5d680SKonstantin Belousov 	bhdr->msg_namelen	= lhdr->msg_namelen;
45874f5d680SKonstantin Belousov 	bhdr->msg_iov		= PTRIN(lhdr->msg_iov);
45974f5d680SKonstantin Belousov 	bhdr->msg_iovlen	= lhdr->msg_iovlen;
46074f5d680SKonstantin Belousov 	bhdr->msg_control	= PTRIN(lhdr->msg_control);
46174f5d680SKonstantin Belousov 	bhdr->msg_controllen	= lhdr->msg_controllen;
46274f5d680SKonstantin Belousov 	bhdr->msg_flags		= linux_to_bsd_msg_flags(lhdr->msg_flags);
46374f5d680SKonstantin Belousov 	return (0);
46474f5d680SKonstantin Belousov }
46574f5d680SKonstantin Belousov 
46674f5d680SKonstantin Belousov static int
46774f5d680SKonstantin Belousov bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
46874f5d680SKonstantin Belousov {
46974f5d680SKonstantin Belousov 	lhdr->msg_name		= PTROUT(bhdr->msg_name);
47074f5d680SKonstantin Belousov 	lhdr->msg_namelen	= bhdr->msg_namelen;
47174f5d680SKonstantin Belousov 	lhdr->msg_iov		= PTROUT(bhdr->msg_iov);
47274f5d680SKonstantin Belousov 	lhdr->msg_iovlen	= bhdr->msg_iovlen;
47374f5d680SKonstantin Belousov 	lhdr->msg_control	= PTROUT(bhdr->msg_control);
47474f5d680SKonstantin Belousov 	lhdr->msg_controllen	= bhdr->msg_controllen;
47574f5d680SKonstantin Belousov 	/* msg_flags skipped */
47674f5d680SKonstantin Belousov 	return (0);
47774f5d680SKonstantin Belousov }
47874f5d680SKonstantin Belousov 
47974f5d680SKonstantin Belousov static int
48074f5d680SKonstantin Belousov linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
48174f5d680SKonstantin Belousov     struct mbuf *control, enum uio_seg segflg)
48274f5d680SKonstantin Belousov {
4835a8a13e0SDavid Malone 	struct sockaddr *to;
4845a8a13e0SDavid Malone 	int error;
4855a8a13e0SDavid Malone 
4865a8a13e0SDavid Malone 	if (mp->msg_name != NULL) {
4875a8a13e0SDavid Malone 		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
4885a8a13e0SDavid Malone 		if (error)
4895a8a13e0SDavid Malone 			return (error);
4905a8a13e0SDavid Malone 		mp->msg_name = to;
4915a8a13e0SDavid Malone 	} else
4925a8a13e0SDavid Malone 		to = NULL;
4935a8a13e0SDavid Malone 
494a6886ef1SMaxim Sobolev 	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
495a6886ef1SMaxim Sobolev 	    segflg);
4965a8a13e0SDavid Malone 
4975a8a13e0SDavid Malone 	if (to)
4981ede983cSDag-Erling Smørgrav 		free(to, M_SONAME);
4995a8a13e0SDavid Malone 	return (error);
5005a8a13e0SDavid Malone }
5015a8a13e0SDavid Malone 
5023f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
503f2477ae1SMike Smith static int
504e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s)
505f2477ae1SMike Smith {
5063db2a843SBruce Evans 	int error, optval, size_val;
507f2477ae1SMike Smith 
508e140eb43SDavid Malone 	size_val = sizeof(optval);
509e140eb43SDavid Malone 	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
510e140eb43SDavid Malone 	    &optval, UIO_SYSSPACE, &size_val);
511e140eb43SDavid Malone 	if (error)
5123f3a4815SMarcel Moolenaar 		return (error);
5133f3a4815SMarcel Moolenaar 
5143f3a4815SMarcel Moolenaar 	return (optval == 0);
515f2477ae1SMike Smith }
516f2477ae1SMike Smith 
5175a8a13e0SDavid Malone struct linux_sendto_args {
5185a8a13e0SDavid Malone 	int s;
5194af27623STim J. Robbins 	l_uintptr_t msg;
5205a8a13e0SDavid Malone 	int len;
5215a8a13e0SDavid Malone 	int flags;
5224af27623STim J. Robbins 	l_uintptr_t to;
5235a8a13e0SDavid Malone 	int tolen;
5245a8a13e0SDavid Malone };
5255a8a13e0SDavid Malone 
526f2477ae1SMike Smith /*
527f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
528f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
529f2477ae1SMike Smith  */
530f2477ae1SMike Smith static int
53138da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
532f2477ae1SMike Smith {
533f2477ae1SMike Smith /*
534f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
535f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
536a6886ef1SMaxim Sobolev  * It should include all the fields we modify (ip_len and ip_off).
537f2477ae1SMike Smith  */
538f2477ae1SMike Smith #define linux_ip_copysize	8
539f2477ae1SMike Smith 
540f2477ae1SMike Smith 	struct ip *packet;
5415a8a13e0SDavid Malone 	struct msghdr msg;
542a6886ef1SMaxim Sobolev 	struct iovec aiov[1];
543f2477ae1SMike Smith 	int error;
544f2477ae1SMike Smith 
545aa675b57SDavid Schultz 	/* Check that the packet isn't too big or too small. */
546aa675b57SDavid Schultz 	if (linux_args->len < linux_ip_copysize ||
547aa675b57SDavid Schultz 	    linux_args->len > IP_MAXPACKET)
5483f3a4815SMarcel Moolenaar 		return (EINVAL);
549f2477ae1SMike Smith 
550a6886ef1SMaxim Sobolev 	packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
551f2477ae1SMike Smith 
552a6886ef1SMaxim Sobolev 	/* Make kernel copy of the packet to be sent */
5534af27623STim J. Robbins 	if ((error = copyin(PTRIN(linux_args->msg), packet,
554a6886ef1SMaxim Sobolev 	    linux_args->len)))
555a6886ef1SMaxim Sobolev 		goto goout;
556f2477ae1SMike Smith 
557f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
5585a8a13e0SDavid Malone 	packet->ip_len = linux_args->len;
559f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
560f2477ae1SMike Smith 
561f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
5624af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args->to);
5635a8a13e0SDavid Malone 	msg.msg_namelen = linux_args->tolen;
5645a8a13e0SDavid Malone 	msg.msg_iov = aiov;
565a6886ef1SMaxim Sobolev 	msg.msg_iovlen = 1;
5665a8a13e0SDavid Malone 	msg.msg_control = NULL;
5675a8a13e0SDavid Malone 	msg.msg_flags = 0;
5685a8a13e0SDavid Malone 	aiov[0].iov_base = (char *)packet;
569a6886ef1SMaxim Sobolev 	aiov[0].iov_len = linux_args->len;
570a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
57174f5d680SKonstantin Belousov 	    NULL, UIO_SYSSPACE);
572a6886ef1SMaxim Sobolev goout:
573a6886ef1SMaxim Sobolev 	free(packet, M_TEMP);
5745a8a13e0SDavid Malone 	return (error);
575f2477ae1SMike Smith }
576f2477ae1SMike Smith 
577c21dee17SSøren Schmidt struct linux_socket_args {
578c21dee17SSøren Schmidt 	int domain;
579c21dee17SSøren Schmidt 	int type;
580c21dee17SSøren Schmidt 	int protocol;
581c21dee17SSøren Schmidt };
582c21dee17SSøren Schmidt 
583c21dee17SSøren Schmidt static int
584b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
585c21dee17SSøren Schmidt {
5868b615593SMarko Zec #ifdef INET6
587093f25f8SMarko Zec #ifndef KLD_MODULE
5888b615593SMarko Zec 	INIT_VNET_INET6(curvnet);
5898b615593SMarko Zec #endif
590093f25f8SMarko Zec #endif
591ef04503dSPeter Wemm 	struct socket_args /* {
592c21dee17SSøren Schmidt 		int domain;
593c21dee17SSøren Schmidt 		int type;
594c21dee17SSøren Schmidt 		int protocol;
595ef04503dSPeter Wemm 	} */ bsd_args;
5963933bde2SDmitry Chagin 	int retval_socket, socket_flags;
597c21dee17SSøren Schmidt 
598745aaef5SKonstantin Belousov 	bsd_args.protocol = args->protocol;
5993933bde2SDmitry Chagin 	socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK;
6003933bde2SDmitry Chagin 	if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
6013933bde2SDmitry Chagin 		return (EINVAL);
6023933bde2SDmitry Chagin 	bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
603eeb63e51SDmitry Chagin 	if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
604eeb63e51SDmitry Chagin 		return (EINVAL);
605745aaef5SKonstantin Belousov 	bsd_args.domain = linux_to_bsd_domain(args->domain);
606c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
607d9b063ccSDmitry Chagin 		return (EAFNOSUPPORT);
608f2477ae1SMike Smith 
609b40ce416SJulian Elischer 	retval_socket = socket(td, &bsd_args);
6106994ea54SDmitry Chagin 	if (retval_socket)
6116994ea54SDmitry Chagin 		return (retval_socket);
6126994ea54SDmitry Chagin 
6133933bde2SDmitry Chagin 	if (socket_flags & LINUX_SOCK_NONBLOCK) {
6143933bde2SDmitry Chagin 		retval_socket = kern_fcntl(td, td->td_retval[0],
6153933bde2SDmitry Chagin 		    F_SETFL, O_NONBLOCK);
6163933bde2SDmitry Chagin 		if (retval_socket) {
6173933bde2SDmitry Chagin 			(void)kern_close(td, td->td_retval[0]);
6183933bde2SDmitry Chagin 			goto out;
6193933bde2SDmitry Chagin 		}
6203933bde2SDmitry Chagin 	}
6213933bde2SDmitry Chagin 	if (socket_flags & LINUX_SOCK_CLOEXEC) {
6223933bde2SDmitry Chagin 		retval_socket = kern_fcntl(td, td->td_retval[0],
6233933bde2SDmitry Chagin 		    F_SETFD, FD_CLOEXEC);
6243933bde2SDmitry Chagin 		if (retval_socket) {
6253933bde2SDmitry Chagin 			(void)kern_close(td, td->td_retval[0]);
6263933bde2SDmitry Chagin 			goto out;
6273933bde2SDmitry Chagin 		}
6283933bde2SDmitry Chagin 	}
6293933bde2SDmitry Chagin 
630f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
631f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
6326994ea54SDmitry Chagin 	    && bsd_args.domain == PF_INET) {
633f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
634e140eb43SDavid Malone 		int hdrincl;
635f2477ae1SMike Smith 
636e140eb43SDavid Malone 		hdrincl = 1;
637e140eb43SDavid Malone 		/* We ignore any error returned by kern_setsockopt() */
638e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
639e140eb43SDavid Malone 		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
640f2477ae1SMike Smith 	}
641ca26842eSHajimu UMEMOTO #ifdef INET6
642ca26842eSHajimu UMEMOTO 	/*
643ca26842eSHajimu UMEMOTO 	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
644ca26842eSHajimu UMEMOTO 	 * default and some apps depend on this. So, set V6ONLY to 0
645ca26842eSHajimu UMEMOTO 	 * for Linux apps if the sysctl value is set to 1.
646ca26842eSHajimu UMEMOTO 	 */
6476994ea54SDmitry Chagin 	if (bsd_args.domain == PF_INET6
64837e7a5a2SHajimu UMEMOTO #ifndef KLD_MODULE
64937e7a5a2SHajimu UMEMOTO 	    /*
65037e7a5a2SHajimu UMEMOTO 	     * XXX: Avoid undefined symbol error with an IPv4 only
65137e7a5a2SHajimu UMEMOTO 	     * kernel.
65237e7a5a2SHajimu UMEMOTO 	     */
653603724d3SBjoern A. Zeeb 	    && V_ip6_v6only
65437e7a5a2SHajimu UMEMOTO #endif
65537e7a5a2SHajimu UMEMOTO 	    ) {
656e140eb43SDavid Malone 		int v6only;
657ca26842eSHajimu UMEMOTO 
658e140eb43SDavid Malone 		v6only = 0;
659ca26842eSHajimu UMEMOTO 		/* We ignore any error returned by setsockopt() */
660e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
661e140eb43SDavid Malone 		    &v6only, UIO_SYSSPACE, sizeof(v6only));
662ca26842eSHajimu UMEMOTO 	}
663ca26842eSHajimu UMEMOTO #endif
6643f3a4815SMarcel Moolenaar 
6653933bde2SDmitry Chagin out:
6663f3a4815SMarcel Moolenaar 	return (retval_socket);
667c21dee17SSøren Schmidt }
668c21dee17SSøren Schmidt 
669c21dee17SSøren Schmidt struct linux_bind_args {
670c21dee17SSøren Schmidt 	int s;
6714af27623STim J. Robbins 	l_uintptr_t name;
672c21dee17SSøren Schmidt 	int namelen;
673c21dee17SSøren Schmidt };
674c21dee17SSøren Schmidt 
675c21dee17SSøren Schmidt static int
676b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
677c21dee17SSøren Schmidt {
678ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
679c21dee17SSøren Schmidt 	int error;
680c21dee17SSøren Schmidt 
681745aaef5SKonstantin Belousov 	error = linux_getsockaddr(&sa, PTRIN(args->name),
682745aaef5SKonstantin Belousov 	    args->namelen);
683ca26842eSHajimu UMEMOTO 	if (error)
684ca26842eSHajimu UMEMOTO 		return (error);
685ca26842eSHajimu UMEMOTO 
686745aaef5SKonstantin Belousov 	error = kern_bind(td, args->s, sa);
687b33887eaSJohn Baldwin 	free(sa, M_SONAME);
688745aaef5SKonstantin Belousov 	if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
689d4b7423fSAlexander Leidinger 	   	return (EINVAL);
690b33887eaSJohn Baldwin 	return (error);
691c21dee17SSøren Schmidt }
692c21dee17SSøren Schmidt 
69301e0ffbaSAlexander Leidinger struct linux_connect_args {
694c21dee17SSøren Schmidt 	int s;
6954af27623STim J. Robbins 	l_uintptr_t name;
696c21dee17SSøren Schmidt 	int namelen;
697c21dee17SSøren Schmidt };
698b40ce416SJulian Elischer int linux_connect(struct thread *, struct linux_connect_args *);
699c21dee17SSøren Schmidt 
700930a65feSAndrew Gallatin int
701b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
702c21dee17SSøren Schmidt {
7030bf301c0SJonathan Lemon 	struct socket *so;
704ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
70539c95b83SMatthew Dillon 	u_int fflag;
706c21dee17SSøren Schmidt 	int error;
707c21dee17SSøren Schmidt 
708745aaef5SKonstantin Belousov 	error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
709745aaef5SKonstantin Belousov 	    args->namelen);
710ca26842eSHajimu UMEMOTO 	if (error)
711ca26842eSHajimu UMEMOTO 		return (error);
712ca26842eSHajimu UMEMOTO 
713745aaef5SKonstantin Belousov 	error = kern_connect(td, args->s, sa);
714b33887eaSJohn Baldwin 	free(sa, M_SONAME);
7150bf301c0SJonathan Lemon 	if (error != EISCONN)
7160bf301c0SJonathan Lemon 		return (error);
7170bf301c0SJonathan Lemon 
718dad3b88aSMike Smith 	/*
719dad3b88aSMike Smith 	 * Linux doesn't return EISCONN the first time it occurs,
720dad3b88aSMike Smith 	 * when on a non-blocking socket. Instead it returns the
721dad3b88aSMike Smith 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
722f7f45ac8SRobert Watson 	 *
723f7f45ac8SRobert Watson 	 * XXXRW: Instead of using fgetsock(), check that it is a
724f7f45ac8SRobert Watson 	 * socket and use the file descriptor reference instead of
725f7f45ac8SRobert Watson 	 * creating a new one.
726dad3b88aSMike Smith 	 */
727745aaef5SKonstantin Belousov 	error = fgetsock(td, args->s, &so, &fflag);
7284641373fSJohn Baldwin 	if (error == 0) {
7290bf301c0SJonathan Lemon 		error = EISCONN;
73039c95b83SMatthew Dillon 		if (fflag & FNONBLOCK) {
7314641373fSJohn Baldwin 			SOCK_LOCK(so);
7325002a60fSMarcel Moolenaar 			if (so->so_emuldata == 0)
7330bf301c0SJonathan Lemon 				error = so->so_error;
7340bf301c0SJonathan Lemon 			so->so_emuldata = (void *)1;
7354641373fSJohn Baldwin 			SOCK_UNLOCK(so);
736dad3b88aSMike Smith 		}
73739c95b83SMatthew Dillon 		fputsock(so);
7384641373fSJohn Baldwin 	}
7393f3a4815SMarcel Moolenaar 	return (error);
740c21dee17SSøren Schmidt }
741c21dee17SSøren Schmidt 
742c21dee17SSøren Schmidt struct linux_listen_args {
743c21dee17SSøren Schmidt 	int s;
744c21dee17SSøren Schmidt 	int backlog;
745c21dee17SSøren Schmidt };
746c21dee17SSøren Schmidt 
747c21dee17SSøren Schmidt static int
748b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
749c21dee17SSøren Schmidt {
750ef04503dSPeter Wemm 	struct listen_args /* {
751c21dee17SSøren Schmidt 		int s;
752c21dee17SSøren Schmidt 		int backlog;
753ef04503dSPeter Wemm 	} */ bsd_args;
754c21dee17SSøren Schmidt 
755745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
756745aaef5SKonstantin Belousov 	bsd_args.backlog = args->backlog;
757b40ce416SJulian Elischer 	return (listen(td, &bsd_args));
758c21dee17SSøren Schmidt }
759c21dee17SSøren Schmidt 
76001e0ffbaSAlexander Leidinger struct linux_accept_args {
761c21dee17SSøren Schmidt 	int s;
7624af27623STim J. Robbins 	l_uintptr_t addr;
7634af27623STim J. Robbins 	l_uintptr_t namelen;
764c21dee17SSøren Schmidt };
765c21dee17SSøren Schmidt 
76601e0ffbaSAlexander Leidinger static int
767b40ce416SJulian Elischer linux_accept(struct thread *td, struct linux_accept_args *args)
768c21dee17SSøren Schmidt {
769ef04503dSPeter Wemm 	struct accept_args /* {
770c21dee17SSøren Schmidt 		int	s;
7713db2a843SBruce Evans 		struct sockaddr * __restrict name;
7723db2a843SBruce Evans 		socklen_t * __restrict anamelen;
773ef04503dSPeter Wemm 	} */ bsd_args;
7742ca25ab5SJohn Baldwin 	int error, fd;
775c21dee17SSøren Schmidt 
776745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
7773db2a843SBruce Evans 	/* XXX: */
778745aaef5SKonstantin Belousov 	bsd_args.name = (struct sockaddr * __restrict)PTRIN(args->addr);
779745aaef5SKonstantin Belousov 	bsd_args.anamelen = PTRIN(args->namelen);/* XXX */
7805c8919adSAlexander Leidinger 	error = accept(td, &bsd_args);
7815c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
782d4b7423fSAlexander Leidinger 	if (error) {
783745aaef5SKonstantin Belousov 		if (error == EFAULT && args->namelen != sizeof(struct sockaddr_in))
784d4b7423fSAlexander Leidinger 			return (EINVAL);
785dba5ab66SMarcel Moolenaar 		return (error);
786d4b7423fSAlexander Leidinger 	}
787745aaef5SKonstantin Belousov 	if (args->addr) {
788745aaef5SKonstantin Belousov 		error = linux_sa_put(PTRIN(args->addr));
789ca26842eSHajimu UMEMOTO 		if (error) {
790c1cccebeSJohn Baldwin 			(void)kern_close(td, td->td_retval[0]);
791ca26842eSHajimu UMEMOTO 			return (error);
792ca26842eSHajimu UMEMOTO 		}
793ca26842eSHajimu UMEMOTO 	}
794dba5ab66SMarcel Moolenaar 
795dba5ab66SMarcel Moolenaar 	/*
796dba5ab66SMarcel Moolenaar 	 * linux appears not to copy flags from the parent socket to the
797dba5ab66SMarcel Moolenaar 	 * accepted one, so we must clear the flags in the new descriptor.
798dba5ab66SMarcel Moolenaar 	 * Ignore any errors, because we already have an open fd.
799dba5ab66SMarcel Moolenaar 	 */
8002ca25ab5SJohn Baldwin 	fd = td->td_retval[0];
8012ca25ab5SJohn Baldwin 	(void)kern_fcntl(td, fd, F_SETFL, 0);
8022ca25ab5SJohn Baldwin 	td->td_retval[0] = fd;
803dba5ab66SMarcel Moolenaar 	return (0);
804c21dee17SSøren Schmidt }
805c21dee17SSøren Schmidt 
80601e0ffbaSAlexander Leidinger struct linux_getsockname_args {
807c21dee17SSøren Schmidt 	int s;
8084af27623STim J. Robbins 	l_uintptr_t addr;
8094af27623STim J. Robbins 	l_uintptr_t namelen;
810c21dee17SSøren Schmidt };
811c21dee17SSøren Schmidt 
81201e0ffbaSAlexander Leidinger static int
813b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
814c21dee17SSøren Schmidt {
815ef04503dSPeter Wemm 	struct getsockname_args /* {
816c21dee17SSøren Schmidt 		int	fdes;
8173db2a843SBruce Evans 		struct sockaddr * __restrict asa;
8183db2a843SBruce Evans 		socklen_t * __restrict alen;
819ef04503dSPeter Wemm 	} */ bsd_args;
820c21dee17SSøren Schmidt 	int error;
821c21dee17SSøren Schmidt 
822745aaef5SKonstantin Belousov 	bsd_args.fdes = args->s;
8233db2a843SBruce Evans 	/* XXX: */
824745aaef5SKonstantin Belousov 	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
825745aaef5SKonstantin Belousov 	bsd_args.alen = PTRIN(args->namelen);	/* XXX */
8265c8919adSAlexander Leidinger 	error = getsockname(td, &bsd_args);
8275c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
828ca26842eSHajimu UMEMOTO 	if (error)
829ca26842eSHajimu UMEMOTO 		return (error);
830745aaef5SKonstantin Belousov 	error = linux_sa_put(PTRIN(args->addr));
831ca26842eSHajimu UMEMOTO 	if (error)
832ca26842eSHajimu UMEMOTO 		return (error);
833ca26842eSHajimu UMEMOTO 	return (0);
834c21dee17SSøren Schmidt }
835c21dee17SSøren Schmidt 
83601e0ffbaSAlexander Leidinger struct linux_getpeername_args {
837c21dee17SSøren Schmidt 	int s;
8384af27623STim J. Robbins 	l_uintptr_t addr;
8394af27623STim J. Robbins 	l_uintptr_t namelen;
840c21dee17SSøren Schmidt };
841c21dee17SSøren Schmidt 
84201e0ffbaSAlexander Leidinger static int
843b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
844c21dee17SSøren Schmidt {
8455c8919adSAlexander Leidinger 	struct getpeername_args /* {
846c21dee17SSøren Schmidt 		int fdes;
847c21dee17SSøren Schmidt 		caddr_t asa;
848c21dee17SSøren Schmidt 		int *alen;
849ef04503dSPeter Wemm 	} */ bsd_args;
850c21dee17SSøren Schmidt 	int error;
851c21dee17SSøren Schmidt 
852745aaef5SKonstantin Belousov 	bsd_args.fdes = args->s;
853745aaef5SKonstantin Belousov 	bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
854745aaef5SKonstantin Belousov 	bsd_args.alen = (int *)PTRIN(args->namelen);
8555c8919adSAlexander Leidinger 	error = getpeername(td, &bsd_args);
8565c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
857ca26842eSHajimu UMEMOTO 	if (error)
858ca26842eSHajimu UMEMOTO 		return (error);
859745aaef5SKonstantin Belousov 	error = linux_sa_put(PTRIN(args->addr));
860ca26842eSHajimu UMEMOTO 	if (error)
861ca26842eSHajimu UMEMOTO 		return (error);
862ca26842eSHajimu UMEMOTO 	return (0);
863c21dee17SSøren Schmidt }
864c21dee17SSøren Schmidt 
86501e0ffbaSAlexander Leidinger struct linux_socketpair_args {
866c21dee17SSøren Schmidt 	int domain;
867c21dee17SSøren Schmidt 	int type;
868c21dee17SSøren Schmidt 	int protocol;
8694af27623STim J. Robbins 	l_uintptr_t rsv;
870c21dee17SSøren Schmidt };
871c21dee17SSøren Schmidt 
87201e0ffbaSAlexander Leidinger static int
873b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
874c21dee17SSøren Schmidt {
875ef04503dSPeter Wemm 	struct socketpair_args /* {
876c21dee17SSøren Schmidt 		int domain;
877c21dee17SSøren Schmidt 		int type;
878c21dee17SSøren Schmidt 		int protocol;
879c21dee17SSøren Schmidt 		int *rsv;
880ef04503dSPeter Wemm 	} */ bsd_args;
881c21dee17SSøren Schmidt 
882745aaef5SKonstantin Belousov 	bsd_args.domain = linux_to_bsd_domain(args->domain);
8831a52a4abSDmitry Chagin 	if (bsd_args.domain != PF_LOCAL)
8841a52a4abSDmitry Chagin 		return (EAFNOSUPPORT);
8853f3a4815SMarcel Moolenaar 
886745aaef5SKonstantin Belousov 	bsd_args.type = args->type;
8871a52a4abSDmitry Chagin 	if (args->protocol != 0 && args->protocol != PF_UNIX)
8881a52a4abSDmitry Chagin 
8891a52a4abSDmitry Chagin 		/*
8901a52a4abSDmitry Chagin 		 * Use of PF_UNIX as protocol argument is not right,
8911a52a4abSDmitry Chagin 		 * but Linux does it.
8921a52a4abSDmitry Chagin 		 * Do not map PF_UNIX as its Linux value is identical
8931a52a4abSDmitry Chagin 		 * to FreeBSD one.
8941a52a4abSDmitry Chagin 		 */
8951a52a4abSDmitry Chagin 		return (EPROTONOSUPPORT);
89640092d93SDmitry Chagin 	else
8971a52a4abSDmitry Chagin 		bsd_args.protocol = 0;
898745aaef5SKonstantin Belousov 	bsd_args.rsv = (int *)PTRIN(args->rsv);
899b40ce416SJulian Elischer 	return (socketpair(td, &bsd_args));
900c21dee17SSøren Schmidt }
901c21dee17SSøren Schmidt 
90201e0ffbaSAlexander Leidinger struct linux_send_args {
903c21dee17SSøren Schmidt 	int s;
9044af27623STim J. Robbins 	l_uintptr_t msg;
905c21dee17SSøren Schmidt 	int len;
906c21dee17SSøren Schmidt 	int flags;
907c21dee17SSøren Schmidt };
908c21dee17SSøren Schmidt 
90901e0ffbaSAlexander Leidinger static int
910b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
911c21dee17SSøren Schmidt {
91287d72a8fSPoul-Henning Kamp 	struct sendto_args /* {
913c21dee17SSøren Schmidt 		int s;
914c21dee17SSøren Schmidt 		caddr_t buf;
915044af7c3SJonathan Mini 		int len;
916c21dee17SSøren Schmidt 		int flags;
91787d72a8fSPoul-Henning Kamp 		caddr_t to;
91887d72a8fSPoul-Henning Kamp 		int tolen;
919ef04503dSPeter Wemm 	} */ bsd_args;
920c21dee17SSøren Schmidt 
921745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
922745aaef5SKonstantin Belousov 	bsd_args.buf = (caddr_t)PTRIN(args->msg);
923745aaef5SKonstantin Belousov 	bsd_args.len = args->len;
924745aaef5SKonstantin Belousov 	bsd_args.flags = args->flags;
92587d72a8fSPoul-Henning Kamp 	bsd_args.to = NULL;
92687d72a8fSPoul-Henning Kamp 	bsd_args.tolen = 0;
9278d6e40c3SMaxim Sobolev 	return sendto(td, &bsd_args);
928c21dee17SSøren Schmidt }
929c21dee17SSøren Schmidt 
93001e0ffbaSAlexander Leidinger struct linux_recv_args {
931c21dee17SSøren Schmidt 	int s;
9324af27623STim J. Robbins 	l_uintptr_t msg;
933c21dee17SSøren Schmidt 	int len;
934c21dee17SSøren Schmidt 	int flags;
935c21dee17SSøren Schmidt };
936c21dee17SSøren Schmidt 
93701e0ffbaSAlexander Leidinger static int
938b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
939c21dee17SSøren Schmidt {
94087d72a8fSPoul-Henning Kamp 	struct recvfrom_args /* {
941c21dee17SSøren Schmidt 		int s;
942c21dee17SSøren Schmidt 		caddr_t buf;
943c21dee17SSøren Schmidt 		int len;
944c21dee17SSøren Schmidt 		int flags;
94587d72a8fSPoul-Henning Kamp 		struct sockaddr *from;
94687d72a8fSPoul-Henning Kamp 		socklen_t fromlenaddr;
947ef04503dSPeter Wemm 	} */ bsd_args;
948c21dee17SSøren Schmidt 
949745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
950745aaef5SKonstantin Belousov 	bsd_args.buf = (caddr_t)PTRIN(args->msg);
951745aaef5SKonstantin Belousov 	bsd_args.len = args->len;
9523980a435SDmitry Chagin 	bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
95387d72a8fSPoul-Henning Kamp 	bsd_args.from = NULL;
95487d72a8fSPoul-Henning Kamp 	bsd_args.fromlenaddr = 0;
95587d72a8fSPoul-Henning Kamp 	return (recvfrom(td, &bsd_args));
956c21dee17SSøren Schmidt }
957c21dee17SSøren Schmidt 
958c21dee17SSøren Schmidt static int
959b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
960c21dee17SSøren Schmidt {
9615a8a13e0SDavid Malone 	struct msghdr msg;
9625a8a13e0SDavid Malone 	struct iovec aiov;
9635a8a13e0SDavid Malone 	int error;
964c21dee17SSøren Schmidt 
965745aaef5SKonstantin Belousov 	if (linux_check_hdrincl(td, args->s) == 0)
966f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
967745aaef5SKonstantin Belousov 		return (linux_sendto_hdrincl(td, args));
968f2477ae1SMike Smith 
969745aaef5SKonstantin Belousov 	msg.msg_name = PTRIN(args->to);
970745aaef5SKonstantin Belousov 	msg.msg_namelen = args->tolen;
9715a8a13e0SDavid Malone 	msg.msg_iov = &aiov;
9725a8a13e0SDavid Malone 	msg.msg_iovlen = 1;
9735a8a13e0SDavid Malone 	msg.msg_control = NULL;
9745a8a13e0SDavid Malone 	msg.msg_flags = 0;
975745aaef5SKonstantin Belousov 	aiov.iov_base = PTRIN(args->msg);
976745aaef5SKonstantin Belousov 	aiov.iov_len = args->len;
97774f5d680SKonstantin Belousov 	error = linux_sendit(td, args->s, &msg, args->flags, NULL,
97874f5d680SKonstantin Belousov 	    UIO_USERSPACE);
9795a8a13e0SDavid Malone 	return (error);
980c21dee17SSøren Schmidt }
981c21dee17SSøren Schmidt 
98201e0ffbaSAlexander Leidinger struct linux_recvfrom_args {
983c21dee17SSøren Schmidt 	int s;
9844af27623STim J. Robbins 	l_uintptr_t buf;
985c21dee17SSøren Schmidt 	int len;
986c21dee17SSøren Schmidt 	int flags;
9874af27623STim J. Robbins 	l_uintptr_t from;
9884af27623STim J. Robbins 	l_uintptr_t fromlen;
989c21dee17SSøren Schmidt };
990c21dee17SSøren Schmidt 
99101e0ffbaSAlexander Leidinger static int
992b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
993c21dee17SSøren Schmidt {
994ef04503dSPeter Wemm 	struct recvfrom_args /* {
995c21dee17SSøren Schmidt 		int	s;
996c21dee17SSøren Schmidt 		caddr_t	buf;
997c21dee17SSøren Schmidt 		size_t	len;
998c21dee17SSøren Schmidt 		int	flags;
9993db2a843SBruce Evans 		struct sockaddr * __restrict from;
10003db2a843SBruce Evans 		socklen_t * __restrict fromlenaddr;
1001ef04503dSPeter Wemm 	} */ bsd_args;
10025c8919adSAlexander Leidinger 	size_t len;
1003c21dee17SSøren Schmidt 	int error;
1004c21dee17SSøren Schmidt 
1005745aaef5SKonstantin Belousov 	if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t))))
10063f3a4815SMarcel Moolenaar 		return (error);
10073f3a4815SMarcel Moolenaar 
1008745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1009745aaef5SKonstantin Belousov 	bsd_args.buf = PTRIN(args->buf);
1010745aaef5SKonstantin Belousov 	bsd_args.len = args->len;
1011745aaef5SKonstantin Belousov 	bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
10123db2a843SBruce Evans 	/* XXX: */
1013745aaef5SKonstantin Belousov 	bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from);
1014745aaef5SKonstantin Belousov 	bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */
10155c8919adSAlexander Leidinger 
10165c8919adSAlexander Leidinger 	linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
10175c8919adSAlexander Leidinger 	error = recvfrom(td, &bsd_args);
10185c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
10195c8919adSAlexander Leidinger 
1020ca26842eSHajimu UMEMOTO 	if (error)
1021ca26842eSHajimu UMEMOTO 		return (error);
1022745aaef5SKonstantin Belousov 	if (args->from) {
10234af27623STim J. Robbins 		error = linux_sa_put((struct osockaddr *)
1024745aaef5SKonstantin Belousov 		    PTRIN(args->from));
1025ca26842eSHajimu UMEMOTO 		if (error)
1026ca26842eSHajimu UMEMOTO 			return (error);
1027ca26842eSHajimu UMEMOTO 	}
1028ca26842eSHajimu UMEMOTO 	return (0);
1029ca26842eSHajimu UMEMOTO }
1030ca26842eSHajimu UMEMOTO 
103101e0ffbaSAlexander Leidinger struct linux_sendmsg_args {
1032ca26842eSHajimu UMEMOTO 	int s;
10334af27623STim J. Robbins 	l_uintptr_t msg;
1034ca26842eSHajimu UMEMOTO 	int flags;
1035ca26842eSHajimu UMEMOTO };
1036ca26842eSHajimu UMEMOTO 
103701e0ffbaSAlexander Leidinger static int
1038ca26842eSHajimu UMEMOTO linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1039ca26842eSHajimu UMEMOTO {
104074f5d680SKonstantin Belousov 	struct cmsghdr *cmsg;
104174f5d680SKonstantin Belousov 	struct mbuf *control;
1042ca26842eSHajimu UMEMOTO 	struct msghdr msg;
104374f5d680SKonstantin Belousov 	struct l_cmsghdr linux_cmsg;
104474f5d680SKonstantin Belousov 	struct l_cmsghdr *ptr_cmsg;
104574f5d680SKonstantin Belousov 	struct l_msghdr linux_msg;
1046552afd9cSPoul-Henning Kamp 	struct iovec *iov;
104774f5d680SKonstantin Belousov 	socklen_t datalen;
104874f5d680SKonstantin Belousov 	void *data;
1049ca26842eSHajimu UMEMOTO 	int error;
1050ca26842eSHajimu UMEMOTO 
105174f5d680SKonstantin Belousov 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
105274f5d680SKonstantin Belousov 	if (error)
105374f5d680SKonstantin Belousov 		return (error);
105474f5d680SKonstantin Belousov 	error = linux_to_bsd_msghdr(&msg, &linux_msg);
1055ca26842eSHajimu UMEMOTO 	if (error)
1056ca26842eSHajimu UMEMOTO 		return (error);
1057d72a6158SRobert Watson 
1058d72a6158SRobert Watson 	/*
1059d72a6158SRobert Watson 	 * Some Linux applications (ping) define a non-NULL control data
1060d72a6158SRobert Watson 	 * pointer, but a msg_controllen of 0, which is not allowed in the
1061d72a6158SRobert Watson 	 * FreeBSD system call interface.  NULL the msg_control pointer in
1062d72a6158SRobert Watson 	 * order to handle this case.  This should be checked, but allows the
1063d72a6158SRobert Watson 	 * Linux ping to work.
1064d72a6158SRobert Watson 	 */
1065d72a6158SRobert Watson 	if (msg.msg_control != NULL && msg.msg_controllen == 0)
1066d72a6158SRobert Watson 		msg.msg_control = NULL;
106774f5d680SKonstantin Belousov 
106874f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32
106974f5d680SKonstantin Belousov 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
107074f5d680SKonstantin Belousov 	    &iov, EMSGSIZE);
107174f5d680SKonstantin Belousov #else
1072552afd9cSPoul-Henning Kamp 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
107374f5d680SKonstantin Belousov #endif
1074552afd9cSPoul-Henning Kamp 	if (error)
1075552afd9cSPoul-Henning Kamp 		return (error);
107674f5d680SKonstantin Belousov 
107774f5d680SKonstantin Belousov 	if (msg.msg_control != NULL) {
107874f5d680SKonstantin Belousov 		error = ENOBUFS;
107974f5d680SKonstantin Belousov 		cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
108074f5d680SKonstantin Belousov 		control = m_get(M_WAIT, MT_CONTROL);
108174f5d680SKonstantin Belousov 		if (control == NULL)
108274f5d680SKonstantin Belousov 			goto bad;
108374f5d680SKonstantin Belousov 		ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg);
108474f5d680SKonstantin Belousov 
108574f5d680SKonstantin Belousov 		do {
108674f5d680SKonstantin Belousov 			error = copyin(ptr_cmsg, &linux_cmsg,
108774f5d680SKonstantin Belousov 			    sizeof(struct l_cmsghdr));
108874f5d680SKonstantin Belousov 			if (error)
108974f5d680SKonstantin Belousov 				goto bad;
109074f5d680SKonstantin Belousov 
109174f5d680SKonstantin Belousov 			error = EINVAL;
109274f5d680SKonstantin Belousov 			if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr))
109374f5d680SKonstantin Belousov 				goto bad;
109474f5d680SKonstantin Belousov 
109574f5d680SKonstantin Belousov 			/*
109674f5d680SKonstantin Belousov 			 * Now we support only SCM_RIGHTS, so return EINVAL
109774f5d680SKonstantin Belousov 			 * in any other cmsg_type
109874f5d680SKonstantin Belousov 			 */
109974f5d680SKonstantin Belousov 			if ((cmsg->cmsg_type =
110074f5d680SKonstantin Belousov 			    linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1)
110174f5d680SKonstantin Belousov 				goto bad;
110274f5d680SKonstantin Belousov 			cmsg->cmsg_level =
110374f5d680SKonstantin Belousov 			    linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
110474f5d680SKonstantin Belousov 
110574f5d680SKonstantin Belousov 			datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
110674f5d680SKonstantin Belousov 			cmsg->cmsg_len = CMSG_LEN(datalen);
110774f5d680SKonstantin Belousov 			data = LINUX_CMSG_DATA(ptr_cmsg);
110874f5d680SKonstantin Belousov 
110974f5d680SKonstantin Belousov 			error = ENOBUFS;
111074f5d680SKonstantin Belousov 			if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
111174f5d680SKonstantin Belousov 				goto bad;
111274f5d680SKonstantin Belousov 			if (!m_append(control, datalen, (c_caddr_t) data))
111374f5d680SKonstantin Belousov 				goto bad;
111474f5d680SKonstantin Belousov 		} while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg)));
111574f5d680SKonstantin Belousov 	} else {
111674f5d680SKonstantin Belousov 		control = NULL;
111774f5d680SKonstantin Belousov 		cmsg = NULL;
111874f5d680SKonstantin Belousov 	}
111974f5d680SKonstantin Belousov 
11205a8a13e0SDavid Malone 	msg.msg_iov = iov;
11215a8a13e0SDavid Malone 	msg.msg_flags = 0;
112274f5d680SKonstantin Belousov 	error = linux_sendit(td, args->s, &msg, args->flags, control,
112374f5d680SKonstantin Belousov 	    UIO_USERSPACE);
112474f5d680SKonstantin Belousov 
112574f5d680SKonstantin Belousov bad:
1126552afd9cSPoul-Henning Kamp 	free(iov, M_IOV);
112774f5d680SKonstantin Belousov 	if (cmsg)
112874f5d680SKonstantin Belousov 		free(cmsg, M_TEMP);
1129ca26842eSHajimu UMEMOTO 	return (error);
1130c21dee17SSøren Schmidt }
1131c21dee17SSøren Schmidt 
113201e0ffbaSAlexander Leidinger struct linux_recvmsg_args {
113340dbba57SAssar Westerlund 	int s;
11344af27623STim J. Robbins 	l_uintptr_t msg;
113540dbba57SAssar Westerlund 	int flags;
113640dbba57SAssar Westerlund };
113740dbba57SAssar Westerlund 
113801e0ffbaSAlexander Leidinger static int
1139b40ce416SJulian Elischer linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
114040dbba57SAssar Westerlund {
114174f5d680SKonstantin Belousov 	struct cmsghdr *cm;
1142ca26842eSHajimu UMEMOTO 	struct msghdr msg;
114374f5d680SKonstantin Belousov 	struct l_cmsghdr *linux_cmsg = NULL;
114474f5d680SKonstantin Belousov 	socklen_t datalen, outlen, clen;
114574f5d680SKonstantin Belousov 	struct l_msghdr linux_msg;
114674f5d680SKonstantin Belousov 	struct iovec *iov, *uiov;
114774f5d680SKonstantin Belousov 	struct mbuf *control = NULL;
114874f5d680SKonstantin Belousov 	struct mbuf **controlp;
114974f5d680SKonstantin Belousov 	caddr_t outbuf;
115074f5d680SKonstantin Belousov 	void *data;
115140dbba57SAssar Westerlund 	int error;
115240dbba57SAssar Westerlund 
115374f5d680SKonstantin Belousov 	error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
1154ca26842eSHajimu UMEMOTO 	if (error)
1155ca26842eSHajimu UMEMOTO 		return (error);
1156ca26842eSHajimu UMEMOTO 
115774f5d680SKonstantin Belousov 	error = linux_to_bsd_msghdr(&msg, &linux_msg);
115874f5d680SKonstantin Belousov 	if (error)
115974f5d680SKonstantin Belousov 		return (error);
116074f5d680SKonstantin Belousov 
116174f5d680SKonstantin Belousov #ifdef COMPAT_LINUX32
116274f5d680SKonstantin Belousov 	error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
116374f5d680SKonstantin Belousov 	    &iov, EMSGSIZE);
116474f5d680SKonstantin Belousov #else
116574f5d680SKonstantin Belousov 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
116674f5d680SKonstantin Belousov #endif
116774f5d680SKonstantin Belousov 	if (error)
116874f5d680SKonstantin Belousov 		return (error);
116974f5d680SKonstantin Belousov 
117074f5d680SKonstantin Belousov 	if (msg.msg_name) {
117174f5d680SKonstantin Belousov 		error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
117274f5d680SKonstantin Belousov 		    msg.msg_namelen);
117374f5d680SKonstantin Belousov 		if (error)
117474f5d680SKonstantin Belousov 			goto bad;
117584b11cd8SMitsuru IWASAKI 	}
117684b11cd8SMitsuru IWASAKI 
117774f5d680SKonstantin Belousov 	uiov = msg.msg_iov;
117874f5d680SKonstantin Belousov 	msg.msg_iov = iov;
117974f5d680SKonstantin Belousov 	controlp = (msg.msg_control != NULL) ? &control : NULL;
118074f5d680SKonstantin Belousov 	error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp);
118174f5d680SKonstantin Belousov 	msg.msg_iov = uiov;
1182ca26842eSHajimu UMEMOTO 	if (error)
118374f5d680SKonstantin Belousov 		goto bad;
118474f5d680SKonstantin Belousov 
118574f5d680SKonstantin Belousov 	error = bsd_to_linux_msghdr(&msg, &linux_msg);
118674f5d680SKonstantin Belousov 	if (error)
118774f5d680SKonstantin Belousov 		goto bad;
118874f5d680SKonstantin Belousov 
118974f5d680SKonstantin Belousov 	if (linux_msg.msg_name) {
119074f5d680SKonstantin Belousov 		error = bsd_to_linux_sockaddr((struct sockaddr *)
119174f5d680SKonstantin Belousov 		    PTRIN(linux_msg.msg_name));
119274f5d680SKonstantin Belousov 		if (error)
119374f5d680SKonstantin Belousov 			goto bad;
119474f5d680SKonstantin Belousov 	}
119574f5d680SKonstantin Belousov 	if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
119674f5d680SKonstantin Belousov 		error = linux_sa_put(PTRIN(linux_msg.msg_name));
119774f5d680SKonstantin Belousov 		if (error)
119874f5d680SKonstantin Belousov 			goto bad;
119974f5d680SKonstantin Belousov 	}
120074f5d680SKonstantin Belousov 
120174f5d680SKonstantin Belousov 	if (control) {
120274f5d680SKonstantin Belousov 
120374f5d680SKonstantin Belousov 		linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
120474f5d680SKonstantin Belousov 		outbuf = PTRIN(linux_msg.msg_control);
120574f5d680SKonstantin Belousov 		cm = mtod(control, struct cmsghdr *);
120674f5d680SKonstantin Belousov 		outlen = 0;
120774f5d680SKonstantin Belousov 		clen = control->m_len;
120874f5d680SKonstantin Belousov 
120974f5d680SKonstantin Belousov 		while (cm != NULL) {
121074f5d680SKonstantin Belousov 
121174f5d680SKonstantin Belousov 			if ((linux_cmsg->cmsg_type =
121274f5d680SKonstantin Belousov 			    bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1)
121374f5d680SKonstantin Belousov 			{
121474f5d680SKonstantin Belousov 				error = EINVAL;
121574f5d680SKonstantin Belousov 				goto bad;
121674f5d680SKonstantin Belousov 			}
121774f5d680SKonstantin Belousov 			data = CMSG_DATA(cm);
121874f5d680SKonstantin Belousov 			datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
121974f5d680SKonstantin Belousov 
122074f5d680SKonstantin Belousov 			if (outlen + LINUX_CMSG_LEN(datalen) >
122174f5d680SKonstantin Belousov 			    linux_msg.msg_controllen) {
122274f5d680SKonstantin Belousov 				if (outlen == 0) {
122374f5d680SKonstantin Belousov 					error = EMSGSIZE;
122474f5d680SKonstantin Belousov 					goto bad;
122574f5d680SKonstantin Belousov 				} else {
122674f5d680SKonstantin Belousov 					linux_msg.msg_flags |= LINUX_MSG_CTRUNC;
122774f5d680SKonstantin Belousov 					goto out;
122874f5d680SKonstantin Belousov 				}
122974f5d680SKonstantin Belousov 			}
123074f5d680SKonstantin Belousov 
123174f5d680SKonstantin Belousov 			linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
123274f5d680SKonstantin Belousov 			linux_cmsg->cmsg_level =
123374f5d680SKonstantin Belousov 			    bsd_to_linux_sockopt_level(cm->cmsg_level);
123474f5d680SKonstantin Belousov 
123574f5d680SKonstantin Belousov 			error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
123674f5d680SKonstantin Belousov 			if (error)
123774f5d680SKonstantin Belousov 				goto bad;
123874f5d680SKonstantin Belousov 			outbuf += L_CMSG_HDRSZ;
123974f5d680SKonstantin Belousov 
124074f5d680SKonstantin Belousov 			error = copyout(data, outbuf, datalen);
124174f5d680SKonstantin Belousov 			if (error)
124274f5d680SKonstantin Belousov 				goto bad;
124374f5d680SKonstantin Belousov 
124474f5d680SKonstantin Belousov 			outbuf += LINUX_CMSG_ALIGN(datalen);
124574f5d680SKonstantin Belousov 			outlen += LINUX_CMSG_LEN(datalen);
124674f5d680SKonstantin Belousov 			linux_msg.msg_controllen = outlen;
124774f5d680SKonstantin Belousov 
124874f5d680SKonstantin Belousov 			if (CMSG_SPACE(datalen) < clen) {
124974f5d680SKonstantin Belousov 				clen -= CMSG_SPACE(datalen);
125074f5d680SKonstantin Belousov 				cm = (struct cmsghdr *)
125174f5d680SKonstantin Belousov 				    ((caddr_t)cm + CMSG_SPACE(datalen));
125274f5d680SKonstantin Belousov 			} else
125374f5d680SKonstantin Belousov 				cm = NULL;
125474f5d680SKonstantin Belousov 		}
125574f5d680SKonstantin Belousov 	}
125674f5d680SKonstantin Belousov 
125774f5d680SKonstantin Belousov out:
125874f5d680SKonstantin Belousov 	error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
125974f5d680SKonstantin Belousov 
126074f5d680SKonstantin Belousov bad:
126174f5d680SKonstantin Belousov 	free(iov, M_IOV);
126274f5d680SKonstantin Belousov 	if (control != NULL)
126374f5d680SKonstantin Belousov 		m_freem(control);
126474f5d680SKonstantin Belousov 	if (linux_cmsg != NULL)
126574f5d680SKonstantin Belousov 		free(linux_cmsg, M_TEMP);
126674f5d680SKonstantin Belousov 
1267ca26842eSHajimu UMEMOTO 	return (error);
126840dbba57SAssar Westerlund }
126940dbba57SAssar Westerlund 
1270c21dee17SSøren Schmidt struct linux_shutdown_args {
1271c21dee17SSøren Schmidt 	int s;
1272c21dee17SSøren Schmidt 	int how;
1273c21dee17SSøren Schmidt };
1274c21dee17SSøren Schmidt 
1275c21dee17SSøren Schmidt static int
1276b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1277c21dee17SSøren Schmidt {
1278ef04503dSPeter Wemm 	struct shutdown_args /* {
1279c21dee17SSøren Schmidt 		int s;
1280c21dee17SSøren Schmidt 		int how;
1281ef04503dSPeter Wemm 	} */ bsd_args;
1282c21dee17SSøren Schmidt 
1283745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1284745aaef5SKonstantin Belousov 	bsd_args.how = args->how;
1285b40ce416SJulian Elischer 	return (shutdown(td, &bsd_args));
1286c21dee17SSøren Schmidt }
1287c21dee17SSøren Schmidt 
1288c21dee17SSøren Schmidt struct linux_setsockopt_args {
1289c21dee17SSøren Schmidt 	int s;
1290c21dee17SSøren Schmidt 	int level;
1291c21dee17SSøren Schmidt 	int optname;
12924af27623STim J. Robbins 	l_uintptr_t optval;
1293c21dee17SSøren Schmidt 	int optlen;
1294c21dee17SSøren Schmidt };
1295c21dee17SSøren Schmidt 
1296c21dee17SSøren Schmidt static int
1297b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1298c21dee17SSøren Schmidt {
1299ef04503dSPeter Wemm 	struct setsockopt_args /* {
1300c21dee17SSøren Schmidt 		int s;
1301c21dee17SSøren Schmidt 		int level;
1302c21dee17SSøren Schmidt 		int name;
1303c21dee17SSøren Schmidt 		caddr_t val;
1304c21dee17SSøren Schmidt 		int valsize;
1305ef04503dSPeter Wemm 	} */ bsd_args;
130603cc95d2SDmitry Chagin 	l_timeval linux_tv;
130703cc95d2SDmitry Chagin 	struct timeval tv;
1308c21dee17SSøren Schmidt 	int error, name;
1309c21dee17SSøren Schmidt 
1310745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1311745aaef5SKonstantin Belousov 	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1312c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1313c21dee17SSøren Schmidt 	case SOL_SOCKET:
1314745aaef5SKonstantin Belousov 		name = linux_to_bsd_so_sockopt(args->optname);
131503cc95d2SDmitry Chagin 		switch (name) {
131603cc95d2SDmitry Chagin 		case SO_RCVTIMEO:
131703cc95d2SDmitry Chagin 			/* FALLTHROUGH */
131803cc95d2SDmitry Chagin 		case SO_SNDTIMEO:
131903cc95d2SDmitry Chagin 			error = copyin(PTRIN(args->optval), &linux_tv,
132003cc95d2SDmitry Chagin 			    sizeof(linux_tv));
132103cc95d2SDmitry Chagin 			if (error)
132203cc95d2SDmitry Chagin 				return (error);
132303cc95d2SDmitry Chagin 			tv.tv_sec = linux_tv.tv_sec;
132403cc95d2SDmitry Chagin 			tv.tv_usec = linux_tv.tv_usec;
132503cc95d2SDmitry Chagin 			return (kern_setsockopt(td, args->s, bsd_args.level,
132603cc95d2SDmitry Chagin 			    name, &tv, UIO_SYSSPACE, sizeof(tv)));
132703cc95d2SDmitry Chagin 			/* NOTREACHED */
132803cc95d2SDmitry Chagin 			break;
132903cc95d2SDmitry Chagin 		default:
133003cc95d2SDmitry Chagin 			break;
133103cc95d2SDmitry Chagin 		}
1332c21dee17SSøren Schmidt 		break;
1333c21dee17SSøren Schmidt 	case IPPROTO_IP:
1334745aaef5SKonstantin Belousov 		name = linux_to_bsd_ip_sockopt(args->optname);
1335c21dee17SSøren Schmidt 		break;
1336dad3b88aSMike Smith 	case IPPROTO_TCP:
1337dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1338745aaef5SKonstantin Belousov 		name = args->optname;
1339dad3b88aSMike Smith 		break;
1340c21dee17SSøren Schmidt 	default:
13413f3a4815SMarcel Moolenaar 		name = -1;
13423f3a4815SMarcel Moolenaar 		break;
1343c21dee17SSøren Schmidt 	}
1344c21dee17SSøren Schmidt 	if (name == -1)
1345d4b7423fSAlexander Leidinger 		return (ENOPROTOOPT);
13463f3a4815SMarcel Moolenaar 
1347c21dee17SSøren Schmidt 	bsd_args.name = name;
1348745aaef5SKonstantin Belousov 	bsd_args.val = PTRIN(args->optval);
1349745aaef5SKonstantin Belousov 	bsd_args.valsize = args->optlen;
13505c8919adSAlexander Leidinger 
13515c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
13525c8919adSAlexander Leidinger 		linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
13535c8919adSAlexander Leidinger 			bsd_args.valsize);
13545c8919adSAlexander Leidinger 		error = setsockopt(td, &bsd_args);
13555c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
13565c8919adSAlexander Leidinger 	} else
13575c8919adSAlexander Leidinger 		error = setsockopt(td, &bsd_args);
13585c8919adSAlexander Leidinger 
13595c8919adSAlexander Leidinger 	return (error);
1360c21dee17SSøren Schmidt }
1361c21dee17SSøren Schmidt 
1362c21dee17SSøren Schmidt struct linux_getsockopt_args {
1363c21dee17SSøren Schmidt 	int s;
1364c21dee17SSøren Schmidt 	int level;
1365c21dee17SSøren Schmidt 	int optname;
13664af27623STim J. Robbins 	l_uintptr_t optval;
13674af27623STim J. Robbins 	l_uintptr_t optlen;
1368c21dee17SSøren Schmidt };
1369c21dee17SSøren Schmidt 
1370c21dee17SSøren Schmidt static int
1371b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1372c21dee17SSøren Schmidt {
1373ef04503dSPeter Wemm 	struct getsockopt_args /* {
1374c21dee17SSøren Schmidt 		int s;
1375c21dee17SSøren Schmidt 		int level;
1376c21dee17SSøren Schmidt 		int name;
1377c21dee17SSøren Schmidt 		caddr_t val;
1378c21dee17SSøren Schmidt 		int *avalsize;
1379ef04503dSPeter Wemm 	} */ bsd_args;
138003cc95d2SDmitry Chagin 	l_timeval linux_tv;
138103cc95d2SDmitry Chagin 	struct timeval tv;
1382d4dd69c4SDmitry Chagin 	socklen_t tv_len, xulen;
1383d4dd69c4SDmitry Chagin 	struct xucred xu;
1384d4dd69c4SDmitry Chagin 	struct l_ucred lxu;
1385c21dee17SSøren Schmidt 	int error, name;
1386c21dee17SSøren Schmidt 
1387745aaef5SKonstantin Belousov 	bsd_args.s = args->s;
1388745aaef5SKonstantin Belousov 	bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1389c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1390c21dee17SSøren Schmidt 	case SOL_SOCKET:
1391745aaef5SKonstantin Belousov 		name = linux_to_bsd_so_sockopt(args->optname);
139203cc95d2SDmitry Chagin 		switch (name) {
139303cc95d2SDmitry Chagin 		case SO_RCVTIMEO:
139403cc95d2SDmitry Chagin 			/* FALLTHROUGH */
139503cc95d2SDmitry Chagin 		case SO_SNDTIMEO:
139603cc95d2SDmitry Chagin 			tv_len = sizeof(tv);
139703cc95d2SDmitry Chagin 			error = kern_getsockopt(td, args->s, bsd_args.level,
139803cc95d2SDmitry Chagin 			    name, &tv, UIO_SYSSPACE, &tv_len);
139903cc95d2SDmitry Chagin 			if (error)
140003cc95d2SDmitry Chagin 				return (error);
140103cc95d2SDmitry Chagin 			linux_tv.tv_sec = tv.tv_sec;
140203cc95d2SDmitry Chagin 			linux_tv.tv_usec = tv.tv_usec;
140303cc95d2SDmitry Chagin 			return (copyout(&linux_tv, PTRIN(args->optval),
140403cc95d2SDmitry Chagin 			    sizeof(linux_tv)));
140503cc95d2SDmitry Chagin 			/* NOTREACHED */
140603cc95d2SDmitry Chagin 			break;
1407d4dd69c4SDmitry Chagin 		case LOCAL_PEERCRED:
1408d4dd69c4SDmitry Chagin 			if (args->optlen != sizeof(lxu))
1409d4dd69c4SDmitry Chagin 				return (EINVAL);
1410d4dd69c4SDmitry Chagin 			xulen = sizeof(xu);
1411d4dd69c4SDmitry Chagin 			error = kern_getsockopt(td, args->s, bsd_args.level,
1412d4dd69c4SDmitry Chagin 			    name, &xu, UIO_SYSSPACE, &xulen);
1413d4dd69c4SDmitry Chagin 			if (error)
1414d4dd69c4SDmitry Chagin 				return (error);
1415d4dd69c4SDmitry Chagin 			/*
1416d4dd69c4SDmitry Chagin 			 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1417d4dd69c4SDmitry Chagin 			 */
1418d4dd69c4SDmitry Chagin 			lxu.pid = 0;
1419d4dd69c4SDmitry Chagin 			lxu.uid = xu.cr_uid;
1420d4dd69c4SDmitry Chagin 			lxu.gid = xu.cr_gid;
1421d4dd69c4SDmitry Chagin 			return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
1422d4dd69c4SDmitry Chagin 			/* NOTREACHED */
1423d4dd69c4SDmitry Chagin 			break;
142403cc95d2SDmitry Chagin 		default:
142503cc95d2SDmitry Chagin 			break;
142603cc95d2SDmitry Chagin 		}
1427c21dee17SSøren Schmidt 		break;
1428c21dee17SSøren Schmidt 	case IPPROTO_IP:
1429745aaef5SKonstantin Belousov 		name = linux_to_bsd_ip_sockopt(args->optname);
1430c21dee17SSøren Schmidt 		break;
1431dad3b88aSMike Smith 	case IPPROTO_TCP:
1432dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1433745aaef5SKonstantin Belousov 		name = args->optname;
1434dad3b88aSMike Smith 		break;
1435c21dee17SSøren Schmidt 	default:
14363f3a4815SMarcel Moolenaar 		name = -1;
14373f3a4815SMarcel Moolenaar 		break;
1438c21dee17SSøren Schmidt 	}
1439c21dee17SSøren Schmidt 	if (name == -1)
14403f3a4815SMarcel Moolenaar 		return (EINVAL);
14413f3a4815SMarcel Moolenaar 
1442f2477ae1SMike Smith 	bsd_args.name = name;
1443745aaef5SKonstantin Belousov 	bsd_args.val = PTRIN(args->optval);
1444745aaef5SKonstantin Belousov 	bsd_args.avalsize = PTRIN(args->optlen);
14455c8919adSAlexander Leidinger 
14465c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
14475c8919adSAlexander Leidinger 		error = getsockopt(td, &bsd_args);
14485c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
14495c8919adSAlexander Leidinger 	} else
14505c8919adSAlexander Leidinger 		error = getsockopt(td, &bsd_args);
14515c8919adSAlexander Leidinger 
14525c8919adSAlexander Leidinger 	return (error);
1453c21dee17SSøren Schmidt }
1454c21dee17SSøren Schmidt 
1455c21dee17SSøren Schmidt int
1456b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1457c21dee17SSøren Schmidt {
14584af27623STim J. Robbins 	void *arg = (void *)(intptr_t)args->args;
14593f3a4815SMarcel Moolenaar 
1460c21dee17SSøren Schmidt 	switch (args->what) {
1461c21dee17SSøren Schmidt 	case LINUX_SOCKET:
1462b40ce416SJulian Elischer 		return (linux_socket(td, arg));
1463c21dee17SSøren Schmidt 	case LINUX_BIND:
1464b40ce416SJulian Elischer 		return (linux_bind(td, arg));
1465c21dee17SSøren Schmidt 	case LINUX_CONNECT:
1466b40ce416SJulian Elischer 		return (linux_connect(td, arg));
1467c21dee17SSøren Schmidt 	case LINUX_LISTEN:
1468b40ce416SJulian Elischer 		return (linux_listen(td, arg));
1469c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
1470b40ce416SJulian Elischer 		return (linux_accept(td, arg));
1471c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
1472b40ce416SJulian Elischer 		return (linux_getsockname(td, arg));
1473c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
1474b40ce416SJulian Elischer 		return (linux_getpeername(td, arg));
1475c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
1476b40ce416SJulian Elischer 		return (linux_socketpair(td, arg));
1477c21dee17SSøren Schmidt 	case LINUX_SEND:
1478b40ce416SJulian Elischer 		return (linux_send(td, arg));
1479c21dee17SSøren Schmidt 	case LINUX_RECV:
1480b40ce416SJulian Elischer 		return (linux_recv(td, arg));
1481c21dee17SSøren Schmidt 	case LINUX_SENDTO:
1482b40ce416SJulian Elischer 		return (linux_sendto(td, arg));
1483c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
1484b40ce416SJulian Elischer 		return (linux_recvfrom(td, arg));
1485c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
1486b40ce416SJulian Elischer 		return (linux_shutdown(td, arg));
1487c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
1488b40ce416SJulian Elischer 		return (linux_setsockopt(td, arg));
1489c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
1490b40ce416SJulian Elischer 		return (linux_getsockopt(td, arg));
1491e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
1492ca26842eSHajimu UMEMOTO 		return (linux_sendmsg(td, arg));
1493e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
1494b40ce416SJulian Elischer 		return (linux_recvmsg(td, arg));
1495c21dee17SSøren Schmidt 	}
14963f3a4815SMarcel Moolenaar 
14973f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
14983f3a4815SMarcel Moolenaar 	return (ENOSYS);
1499c21dee17SSøren Schmidt }
1500