xref: /freebsd/sys/compat/linux/linux_socket.c (revision d72a615878a201f13441e5bb02542e34bfe28c78)
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>
531f3dad5aSBruce Evans 
54c21dee17SSøren Schmidt #include <netinet/in.h>
55f2477ae1SMike Smith #include <netinet/in_systm.h>
56f2477ae1SMike Smith #include <netinet/ip.h>
57ca26842eSHajimu UMEMOTO #ifdef INET6
58ca26842eSHajimu UMEMOTO #include <netinet/ip6.h>
59ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h>
60ca26842eSHajimu UMEMOTO #endif
61c21dee17SSøren Schmidt 
621997c537SDavid E. O'Brien #ifdef COMPAT_LINUX32
634af27623STim J. Robbins #include <machine/../linux32/linux.h>
644af27623STim J. Robbins #include <machine/../linux32/linux32_proto.h>
651997c537SDavid E. O'Brien #else
661997c537SDavid E. O'Brien #include <machine/../linux/linux.h>
671997c537SDavid E. O'Brien #include <machine/../linux/linux_proto.h>
684af27623STim J. Robbins #endif
6940dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
70ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
71c21dee17SSøren Schmidt 
72ca26842eSHajimu UMEMOTO static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
73ca26842eSHajimu UMEMOTO     struct malloc_type *);
74ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int);
75ca26842eSHajimu UMEMOTO 
764730796cSBill Fenner /*
77ca26842eSHajimu UMEMOTO  * Reads a linux sockaddr and does any necessary translation.
78ca26842eSHajimu UMEMOTO  * Linux sockaddrs don't have a length field, only a family.
794730796cSBill Fenner  */
804730796cSBill Fenner static int
81ca26842eSHajimu UMEMOTO linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
824730796cSBill Fenner {
83ca26842eSHajimu UMEMOTO 	int osalen = len;
844730796cSBill Fenner 
85ca26842eSHajimu UMEMOTO 	return (do_sa_get(sap, osa, &osalen, M_SONAME));
864730796cSBill Fenner }
874730796cSBill Fenner 
88ca26842eSHajimu UMEMOTO /*
89ca26842eSHajimu UMEMOTO  * Copy the osockaddr structure pointed to by osa to kernel, adjust
90ca26842eSHajimu UMEMOTO  * family and convert to sockaddr.
91ca26842eSHajimu UMEMOTO  */
92ca26842eSHajimu UMEMOTO static int
93ca26842eSHajimu UMEMOTO do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
94ca26842eSHajimu UMEMOTO     struct malloc_type *mtype)
95ca26842eSHajimu UMEMOTO {
96ca26842eSHajimu UMEMOTO 	int error=0, bdom;
97ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
98ca26842eSHajimu UMEMOTO 	struct osockaddr *kosa;
99ca26842eSHajimu UMEMOTO 	int alloclen;
100ca26842eSHajimu UMEMOTO #ifdef INET6
101ca26842eSHajimu UMEMOTO 	int oldv6size;
102ca26842eSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
103ca26842eSHajimu UMEMOTO #endif
104ca26842eSHajimu UMEMOTO 
105ca26842eSHajimu UMEMOTO 	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
106ca26842eSHajimu UMEMOTO 		return (EINVAL);
107ca26842eSHajimu UMEMOTO 
108ca26842eSHajimu UMEMOTO 	alloclen = *osalen;
109ca26842eSHajimu UMEMOTO #ifdef INET6
110ca26842eSHajimu UMEMOTO 	oldv6size = 0;
111ca26842eSHajimu UMEMOTO 	/*
112ca26842eSHajimu UMEMOTO 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
113ca26842eSHajimu UMEMOTO 	 * if it's a v4-mapped address, so reserve the proper space
114ca26842eSHajimu UMEMOTO 	 * for it.
115ca26842eSHajimu UMEMOTO 	 */
116ca26842eSHajimu UMEMOTO 	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
117ca26842eSHajimu UMEMOTO 		alloclen = sizeof (struct sockaddr_in6);
118ca26842eSHajimu UMEMOTO 		oldv6size = 1;
119ca26842eSHajimu UMEMOTO 	}
120ca26842eSHajimu UMEMOTO #endif
121ca26842eSHajimu UMEMOTO 
1225b13e781SHajimu UMEMOTO 	MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
123ca26842eSHajimu UMEMOTO 
1244b7ef73dSDag-Erling Smørgrav 	if ((error = copyin(osa, kosa, *osalen)))
125ca26842eSHajimu UMEMOTO 		goto out;
126ca26842eSHajimu UMEMOTO 
127ca26842eSHajimu UMEMOTO 	bdom = linux_to_bsd_domain(kosa->sa_family);
128ca26842eSHajimu UMEMOTO 	if (bdom == -1) {
129ca26842eSHajimu UMEMOTO 		error = EINVAL;
130ca26842eSHajimu UMEMOTO 		goto out;
131ca26842eSHajimu UMEMOTO 	}
132ca26842eSHajimu UMEMOTO 
133ca26842eSHajimu UMEMOTO #ifdef INET6
134ca26842eSHajimu UMEMOTO 	/*
135ca26842eSHajimu UMEMOTO 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
136ca26842eSHajimu UMEMOTO 	 * which lacks the scope id compared with RFC2553 one. If we detect
137ca26842eSHajimu UMEMOTO 	 * the situation, reject the address and write a message to system log.
138ca26842eSHajimu UMEMOTO 	 *
139ca26842eSHajimu UMEMOTO 	 * Still accept addresses for which the scope id is not used.
140ca26842eSHajimu UMEMOTO 	 */
141ca26842eSHajimu UMEMOTO 	if (oldv6size && bdom == AF_INET6) {
142ca26842eSHajimu UMEMOTO 		sin6 = (struct sockaddr_in6 *)kosa;
143ca26842eSHajimu UMEMOTO 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
144ca26842eSHajimu UMEMOTO 		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
145ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
146ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
147ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
148ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
149ca26842eSHajimu UMEMOTO 			sin6->sin6_scope_id = 0;
150ca26842eSHajimu UMEMOTO 		} else {
151ca26842eSHajimu UMEMOTO 			log(LOG_DEBUG,
1523c616032SGleb Smirnoff 			    "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
153ca26842eSHajimu UMEMOTO 			error = EINVAL;
154ca26842eSHajimu UMEMOTO 			goto out;
155ca26842eSHajimu UMEMOTO 		}
156ca26842eSHajimu UMEMOTO 	} else
157ca26842eSHajimu UMEMOTO #endif
158ca26842eSHajimu UMEMOTO 	if (bdom == AF_INET)
159ca26842eSHajimu UMEMOTO 		alloclen = sizeof(struct sockaddr_in);
160ca26842eSHajimu UMEMOTO 
161ca26842eSHajimu UMEMOTO 	sa = (struct sockaddr *) kosa;
162ca26842eSHajimu UMEMOTO 	sa->sa_family = bdom;
163ca26842eSHajimu UMEMOTO 	sa->sa_len = alloclen;
164ca26842eSHajimu UMEMOTO 
165ca26842eSHajimu UMEMOTO 	*sap = sa;
166ca26842eSHajimu UMEMOTO 	*osalen = alloclen;
167ca26842eSHajimu UMEMOTO 	return (0);
168ca26842eSHajimu UMEMOTO 
169ca26842eSHajimu UMEMOTO out:
170ca26842eSHajimu UMEMOTO 	FREE(kosa, mtype);
171ca26842eSHajimu UMEMOTO 	return (error);
172ca26842eSHajimu UMEMOTO }
173ca26842eSHajimu UMEMOTO 
174c21dee17SSøren Schmidt static int
175c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
176c21dee17SSøren Schmidt {
1773f3a4815SMarcel Moolenaar 
178c21dee17SSøren Schmidt 	switch (domain) {
179c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
1803f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
181c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
1823f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
183c21dee17SSøren Schmidt 	case LINUX_AF_INET:
1843f3a4815SMarcel Moolenaar 		return (AF_INET);
185ca26842eSHajimu UMEMOTO 	case LINUX_AF_INET6:
186ca26842eSHajimu UMEMOTO 		return (AF_INET6);
187c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
1883f3a4815SMarcel Moolenaar 		return (AF_CCITT);
189c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
1903f3a4815SMarcel Moolenaar 		return (AF_IPX);
191c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
1923f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
193c21dee17SSøren Schmidt 	}
1943f3a4815SMarcel Moolenaar 	return (-1);
195c21dee17SSøren Schmidt }
196c21dee17SSøren Schmidt 
197ca26842eSHajimu UMEMOTO static int
198ca26842eSHajimu UMEMOTO bsd_to_linux_domain(int domain)
199ca26842eSHajimu UMEMOTO {
200ca26842eSHajimu UMEMOTO 
201ca26842eSHajimu UMEMOTO 	switch (domain) {
202ca26842eSHajimu UMEMOTO 	case AF_UNSPEC:
203ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNSPEC);
204ca26842eSHajimu UMEMOTO 	case AF_LOCAL:
205ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNIX);
206ca26842eSHajimu UMEMOTO 	case AF_INET:
207ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET);
208ca26842eSHajimu UMEMOTO 	case AF_INET6:
209ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET6);
210ca26842eSHajimu UMEMOTO 	case AF_CCITT:
211ca26842eSHajimu UMEMOTO 		return (LINUX_AF_AX25);
212ca26842eSHajimu UMEMOTO 	case AF_IPX:
213ca26842eSHajimu UMEMOTO 		return (LINUX_AF_IPX);
214ca26842eSHajimu UMEMOTO 	case AF_APPLETALK:
215ca26842eSHajimu UMEMOTO 		return (LINUX_AF_APPLETALK);
216ca26842eSHajimu UMEMOTO 	}
217ca26842eSHajimu UMEMOTO 	return (-1);
218ca26842eSHajimu UMEMOTO }
219ca26842eSHajimu UMEMOTO 
220c21dee17SSøren Schmidt static int
221c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
222c21dee17SSøren Schmidt {
2233f3a4815SMarcel Moolenaar 
224c21dee17SSøren Schmidt 	switch (level) {
225c21dee17SSøren Schmidt 	case LINUX_SOL_SOCKET:
2263f3a4815SMarcel Moolenaar 		return (SOL_SOCKET);
227c21dee17SSøren Schmidt 	}
2283f3a4815SMarcel Moolenaar 	return (level);
229c21dee17SSøren Schmidt }
230c21dee17SSøren Schmidt 
2313f3a4815SMarcel Moolenaar static int
23284b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level)
23384b11cd8SMitsuru IWASAKI {
23484b11cd8SMitsuru IWASAKI 
23584b11cd8SMitsuru IWASAKI 	switch (level) {
23684b11cd8SMitsuru IWASAKI 	case SOL_SOCKET:
23784b11cd8SMitsuru IWASAKI 		return (LINUX_SOL_SOCKET);
23884b11cd8SMitsuru IWASAKI 	}
23984b11cd8SMitsuru IWASAKI 	return (level);
24084b11cd8SMitsuru IWASAKI }
24184b11cd8SMitsuru IWASAKI 
24284b11cd8SMitsuru IWASAKI static int
2433f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
244c21dee17SSøren Schmidt {
2453f3a4815SMarcel Moolenaar 
246c21dee17SSøren Schmidt 	switch (opt) {
247c21dee17SSøren Schmidt 	case LINUX_IP_TOS:
2483f3a4815SMarcel Moolenaar 		return (IP_TOS);
249c21dee17SSøren Schmidt 	case LINUX_IP_TTL:
2503f3a4815SMarcel Moolenaar 		return (IP_TTL);
25166ff6a3cSBill Fenner 	case LINUX_IP_OPTIONS:
2523f3a4815SMarcel Moolenaar 		return (IP_OPTIONS);
25366ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_IF:
2543f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_IF);
25566ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_TTL:
2563f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_TTL);
25766ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_LOOP:
2583f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_LOOP);
25966ff6a3cSBill Fenner 	case LINUX_IP_ADD_MEMBERSHIP:
2603f3a4815SMarcel Moolenaar 		return (IP_ADD_MEMBERSHIP);
26166ff6a3cSBill Fenner 	case LINUX_IP_DROP_MEMBERSHIP:
2623f3a4815SMarcel Moolenaar 		return (IP_DROP_MEMBERSHIP);
26366ff6a3cSBill Fenner 	case LINUX_IP_HDRINCL:
2643f3a4815SMarcel Moolenaar 		return (IP_HDRINCL);
265c21dee17SSøren Schmidt 	}
2663f3a4815SMarcel Moolenaar 	return (-1);
267c21dee17SSøren Schmidt }
268c21dee17SSøren Schmidt 
269c21dee17SSøren Schmidt static int
270c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
271c21dee17SSøren Schmidt {
2723f3a4815SMarcel Moolenaar 
273c21dee17SSøren Schmidt 	switch (opt) {
274c21dee17SSøren Schmidt 	case LINUX_SO_DEBUG:
2753f3a4815SMarcel Moolenaar 		return (SO_DEBUG);
276c21dee17SSøren Schmidt 	case LINUX_SO_REUSEADDR:
2773f3a4815SMarcel Moolenaar 		return (SO_REUSEADDR);
278c21dee17SSøren Schmidt 	case LINUX_SO_TYPE:
2793f3a4815SMarcel Moolenaar 		return (SO_TYPE);
280c21dee17SSøren Schmidt 	case LINUX_SO_ERROR:
2813f3a4815SMarcel Moolenaar 		return (SO_ERROR);
282c21dee17SSøren Schmidt 	case LINUX_SO_DONTROUTE:
2833f3a4815SMarcel Moolenaar 		return (SO_DONTROUTE);
284c21dee17SSøren Schmidt 	case LINUX_SO_BROADCAST:
2853f3a4815SMarcel Moolenaar 		return (SO_BROADCAST);
286c21dee17SSøren Schmidt 	case LINUX_SO_SNDBUF:
2873f3a4815SMarcel Moolenaar 		return (SO_SNDBUF);
288c21dee17SSøren Schmidt 	case LINUX_SO_RCVBUF:
2893f3a4815SMarcel Moolenaar 		return (SO_RCVBUF);
290c21dee17SSøren Schmidt 	case LINUX_SO_KEEPALIVE:
2913f3a4815SMarcel Moolenaar 		return (SO_KEEPALIVE);
292c21dee17SSøren Schmidt 	case LINUX_SO_OOBINLINE:
2933f3a4815SMarcel Moolenaar 		return (SO_OOBINLINE);
294c21dee17SSøren Schmidt 	case LINUX_SO_LINGER:
2953f3a4815SMarcel Moolenaar 		return (SO_LINGER);
296d0b2365eSKonstantin Belousov 	case LINUX_SO_PEERCRED:
297d0b2365eSKonstantin Belousov 		return (LOCAL_PEERCRED);
298d0b2365eSKonstantin Belousov 	case LINUX_SO_RCVLOWAT:
299d0b2365eSKonstantin Belousov 		return (SO_RCVLOWAT);
300d0b2365eSKonstantin Belousov 	case LINUX_SO_SNDLOWAT:
301d0b2365eSKonstantin Belousov 		return (SO_SNDLOWAT);
302d0b2365eSKonstantin Belousov 	case LINUX_SO_RCVTIMEO:
303d0b2365eSKonstantin Belousov 		return (SO_RCVTIMEO);
304d0b2365eSKonstantin Belousov 	case LINUX_SO_SNDTIMEO:
305d0b2365eSKonstantin Belousov 		return (SO_SNDTIMEO);
306d0b2365eSKonstantin Belousov 	case LINUX_SO_TIMESTAMP:
307d0b2365eSKonstantin Belousov 		return (SO_TIMESTAMP);
308d0b2365eSKonstantin Belousov 	case LINUX_SO_ACCEPTCONN:
309d0b2365eSKonstantin Belousov 		return (SO_ACCEPTCONN);
310c21dee17SSøren Schmidt 	}
3113f3a4815SMarcel Moolenaar 	return (-1);
312c21dee17SSøren Schmidt }
313c21dee17SSøren Schmidt 
31440dbba57SAssar Westerlund static int
31540dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
31640dbba57SAssar Westerlund {
31740dbba57SAssar Westerlund 	int ret_flags = 0;
31840dbba57SAssar Westerlund 
31940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
32040dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
32140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
32240dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
32340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
32440dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
32540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
32640dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
32740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
32840dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
32940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
33040dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
33140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
33240dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
33340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
33440dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
3358d6e40c3SMaxim Sobolev 	if (flags & LINUX_MSG_NOSIGNAL)
3368d6e40c3SMaxim Sobolev 		ret_flags |= MSG_NOSIGNAL;
33740dbba57SAssar Westerlund #if 0 /* not handled */
33840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
33940dbba57SAssar Westerlund 		;
34040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
34140dbba57SAssar Westerlund 		;
34240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
34340dbba57SAssar Westerlund 		;
34440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
34540dbba57SAssar Westerlund 		;
34640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
34740dbba57SAssar Westerlund 		;
34840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
34940dbba57SAssar Westerlund 		;
35040dbba57SAssar Westerlund #endif
35140dbba57SAssar Westerlund 	return ret_flags;
35240dbba57SAssar Westerlund }
35340dbba57SAssar Westerlund 
3545c8919adSAlexander Leidinger /*
3555c8919adSAlexander Leidinger * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
3565c8919adSAlexander Leidinger * native syscall will fault.  Thus, we don't really need to check the
3575c8919adSAlexander Leidinger * return values for these functions.
3585c8919adSAlexander Leidinger */
3595c8919adSAlexander Leidinger 
3605c8919adSAlexander Leidinger static int
3615c8919adSAlexander Leidinger bsd_to_linux_sockaddr(struct sockaddr *arg)
3625c8919adSAlexander Leidinger {
3635c8919adSAlexander Leidinger 	struct sockaddr sa;
3645c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
3655c8919adSAlexander Leidinger 	int error;
3665c8919adSAlexander Leidinger 
3675c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
3685c8919adSAlexander Leidinger 		return (error);
3695c8919adSAlexander Leidinger 
3705c8919adSAlexander Leidinger 	*(u_short *)&sa = sa.sa_family;
3715c8919adSAlexander Leidinger 
3725c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
3735c8919adSAlexander Leidinger 
3745c8919adSAlexander Leidinger 	return (error);
3755c8919adSAlexander Leidinger }
3765c8919adSAlexander Leidinger 
3775c8919adSAlexander Leidinger static int
3785c8919adSAlexander Leidinger linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
3795c8919adSAlexander Leidinger {
3805c8919adSAlexander Leidinger 	struct sockaddr sa;
3815c8919adSAlexander Leidinger 	size_t sa_len = sizeof(struct sockaddr);
3825c8919adSAlexander Leidinger 	int error;
3835c8919adSAlexander Leidinger 
3845c8919adSAlexander Leidinger 	if ((error = copyin(arg, &sa, sa_len)))
3855c8919adSAlexander Leidinger 		return (error);
3865c8919adSAlexander Leidinger 
3875c8919adSAlexander Leidinger 	sa.sa_family = *(sa_family_t *)&sa;
3885c8919adSAlexander Leidinger 	sa.sa_len = len;
3895c8919adSAlexander Leidinger 
3905c8919adSAlexander Leidinger 	error = copyout(&sa, arg, sa_len);
3915c8919adSAlexander Leidinger 
3925c8919adSAlexander Leidinger 	return (error);
3935c8919adSAlexander Leidinger }
3945c8919adSAlexander Leidinger 
3955c8919adSAlexander Leidinger 
396ca26842eSHajimu UMEMOTO static int
397ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa)
398ca26842eSHajimu UMEMOTO {
399ca26842eSHajimu UMEMOTO 	struct osockaddr sa;
400ca26842eSHajimu UMEMOTO 	int error, bdom;
401ca26842eSHajimu UMEMOTO 
402ca26842eSHajimu UMEMOTO 	/*
403ca26842eSHajimu UMEMOTO 	 * Only read/write the osockaddr family part, the rest is
404ca26842eSHajimu UMEMOTO 	 * not changed.
405ca26842eSHajimu UMEMOTO 	 */
4064b7ef73dSDag-Erling Smørgrav 	error = copyin(osa, &sa, sizeof(sa.sa_family));
407ca26842eSHajimu UMEMOTO 	if (error)
408ca26842eSHajimu UMEMOTO 		return (error);
409ca26842eSHajimu UMEMOTO 
410ca26842eSHajimu UMEMOTO 	bdom = bsd_to_linux_domain(sa.sa_family);
411ca26842eSHajimu UMEMOTO 	if (bdom == -1)
412ca26842eSHajimu UMEMOTO 		return (EINVAL);
413ca26842eSHajimu UMEMOTO 
414ca26842eSHajimu UMEMOTO 	sa.sa_family = bdom;
415ca26842eSHajimu UMEMOTO 	error = copyout(&sa, osa, sizeof(sa.sa_family));
416ca26842eSHajimu UMEMOTO 	if (error)
417ca26842eSHajimu UMEMOTO 		return (error);
418ca26842eSHajimu UMEMOTO 
419ca26842eSHajimu UMEMOTO 	return (0);
420ca26842eSHajimu UMEMOTO }
421ca26842eSHajimu UMEMOTO 
4225a8a13e0SDavid Malone static int
423a6886ef1SMaxim Sobolev linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
424a6886ef1SMaxim Sobolev     enum uio_seg segflg)
4255a8a13e0SDavid Malone {
4265a8a13e0SDavid Malone 	struct mbuf *control;
4275a8a13e0SDavid Malone 	struct sockaddr *to;
4285a8a13e0SDavid Malone 	int error;
4295a8a13e0SDavid Malone 
4305a8a13e0SDavid Malone 	if (mp->msg_name != NULL) {
4315a8a13e0SDavid Malone 		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
4325a8a13e0SDavid Malone 		if (error)
4335a8a13e0SDavid Malone 			return (error);
4345a8a13e0SDavid Malone 		mp->msg_name = to;
4355a8a13e0SDavid Malone 	} else
4365a8a13e0SDavid Malone 		to = NULL;
4375a8a13e0SDavid Malone 
4385a8a13e0SDavid Malone 	if (mp->msg_control != NULL) {
4395a8a13e0SDavid Malone 		struct cmsghdr *cmsg;
4405a8a13e0SDavid Malone 
4415a8a13e0SDavid Malone 		if (mp->msg_controllen < sizeof(struct cmsghdr)) {
4425a8a13e0SDavid Malone 			error = EINVAL;
4435a8a13e0SDavid Malone 			goto bad;
4445a8a13e0SDavid Malone 		}
4455a8a13e0SDavid Malone 		error = sockargs(&control, mp->msg_control,
4465a8a13e0SDavid Malone 		    mp->msg_controllen, MT_CONTROL);
4475a8a13e0SDavid Malone 		if (error)
4485a8a13e0SDavid Malone 			goto bad;
4495a8a13e0SDavid Malone 
4505a8a13e0SDavid Malone 		cmsg = mtod(control, struct cmsghdr *);
4515a8a13e0SDavid Malone 		cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level);
4525a8a13e0SDavid Malone 	} else
4535a8a13e0SDavid Malone 		control = NULL;
4545a8a13e0SDavid Malone 
455a6886ef1SMaxim Sobolev 	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
456a6886ef1SMaxim Sobolev 	    segflg);
4575a8a13e0SDavid Malone 
4585a8a13e0SDavid Malone bad:
4595a8a13e0SDavid Malone 	if (to)
4605a8a13e0SDavid Malone 		FREE(to, M_SONAME);
4615a8a13e0SDavid Malone 	return (error);
4625a8a13e0SDavid Malone }
4635a8a13e0SDavid Malone 
4643f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
465f2477ae1SMike Smith static int
466e140eb43SDavid Malone linux_check_hdrincl(struct thread *td, int s)
467f2477ae1SMike Smith {
4683db2a843SBruce Evans 	int error, optval, size_val;
469f2477ae1SMike Smith 
470e140eb43SDavid Malone 	size_val = sizeof(optval);
471e140eb43SDavid Malone 	error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
472e140eb43SDavid Malone 	    &optval, UIO_SYSSPACE, &size_val);
473e140eb43SDavid Malone 	if (error)
4743f3a4815SMarcel Moolenaar 		return (error);
4753f3a4815SMarcel Moolenaar 
4763f3a4815SMarcel Moolenaar 	return (optval == 0);
477f2477ae1SMike Smith }
478f2477ae1SMike Smith 
4795a8a13e0SDavid Malone struct linux_sendto_args {
4805a8a13e0SDavid Malone 	int s;
4814af27623STim J. Robbins 	l_uintptr_t msg;
4825a8a13e0SDavid Malone 	int len;
4835a8a13e0SDavid Malone 	int flags;
4844af27623STim J. Robbins 	l_uintptr_t to;
4855a8a13e0SDavid Malone 	int tolen;
4865a8a13e0SDavid Malone };
4875a8a13e0SDavid Malone 
488f2477ae1SMike Smith /*
489f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
490f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
491f2477ae1SMike Smith  */
492f2477ae1SMike Smith static int
49338da2381SRobert Watson linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
494f2477ae1SMike Smith {
495f2477ae1SMike Smith /*
496f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
497f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
498a6886ef1SMaxim Sobolev  * It should include all the fields we modify (ip_len and ip_off).
499f2477ae1SMike Smith  */
500f2477ae1SMike Smith #define linux_ip_copysize	8
501f2477ae1SMike Smith 
502f2477ae1SMike Smith 	struct ip *packet;
5035a8a13e0SDavid Malone 	struct msghdr msg;
504a6886ef1SMaxim Sobolev 	struct iovec aiov[1];
505f2477ae1SMike Smith 	int error;
506f2477ae1SMike Smith 
507aa675b57SDavid Schultz 	/* Check that the packet isn't too big or too small. */
508aa675b57SDavid Schultz 	if (linux_args->len < linux_ip_copysize ||
509aa675b57SDavid Schultz 	    linux_args->len > IP_MAXPACKET)
5103f3a4815SMarcel Moolenaar 		return (EINVAL);
511f2477ae1SMike Smith 
512a6886ef1SMaxim Sobolev 	packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
513f2477ae1SMike Smith 
514a6886ef1SMaxim Sobolev 	/* Make kernel copy of the packet to be sent */
5154af27623STim J. Robbins 	if ((error = copyin(PTRIN(linux_args->msg), packet,
516a6886ef1SMaxim Sobolev 	    linux_args->len)))
517a6886ef1SMaxim Sobolev 		goto goout;
518f2477ae1SMike Smith 
519f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
5205a8a13e0SDavid Malone 	packet->ip_len = linux_args->len;
521f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
522f2477ae1SMike Smith 
523f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
5244af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args->to);
5255a8a13e0SDavid Malone 	msg.msg_namelen = linux_args->tolen;
5265a8a13e0SDavid Malone 	msg.msg_iov = aiov;
527a6886ef1SMaxim Sobolev 	msg.msg_iovlen = 1;
5285a8a13e0SDavid Malone 	msg.msg_control = NULL;
5295a8a13e0SDavid Malone 	msg.msg_flags = 0;
5305a8a13e0SDavid Malone 	aiov[0].iov_base = (char *)packet;
531a6886ef1SMaxim Sobolev 	aiov[0].iov_len = linux_args->len;
532a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
533a6886ef1SMaxim Sobolev 	    UIO_SYSSPACE);
534a6886ef1SMaxim Sobolev goout:
535a6886ef1SMaxim Sobolev 	free(packet, M_TEMP);
5365a8a13e0SDavid Malone 	return (error);
537f2477ae1SMike Smith }
538f2477ae1SMike Smith 
539c21dee17SSøren Schmidt struct linux_socket_args {
540c21dee17SSøren Schmidt 	int domain;
541c21dee17SSøren Schmidt 	int type;
542c21dee17SSøren Schmidt 	int protocol;
543c21dee17SSøren Schmidt };
544c21dee17SSøren Schmidt 
545c21dee17SSøren Schmidt static int
546b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
547c21dee17SSøren Schmidt {
548c21dee17SSøren Schmidt 	struct linux_socket_args linux_args;
549ef04503dSPeter Wemm 	struct socket_args /* {
550c21dee17SSøren Schmidt 		int domain;
551c21dee17SSøren Schmidt 		int type;
552c21dee17SSøren Schmidt 		int protocol;
553ef04503dSPeter Wemm 	} */ bsd_args;
554c21dee17SSøren Schmidt 	int error;
555f2477ae1SMike Smith 	int retval_socket;
556c21dee17SSøren Schmidt 
5573f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5583f3a4815SMarcel Moolenaar 		return (error);
5593f3a4815SMarcel Moolenaar 
560c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
561c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
562c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
563c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
5643f3a4815SMarcel Moolenaar 		return (EINVAL);
565f2477ae1SMike Smith 
566b40ce416SJulian Elischer 	retval_socket = socket(td, &bsd_args);
567f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
568f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
569f2477ae1SMike Smith 	    && bsd_args.domain == AF_INET
570f2477ae1SMike Smith 	    && retval_socket >= 0) {
571f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
572e140eb43SDavid Malone 		int hdrincl;
573f2477ae1SMike Smith 
574e140eb43SDavid Malone 		hdrincl = 1;
575e140eb43SDavid Malone 		/* We ignore any error returned by kern_setsockopt() */
576e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
577e140eb43SDavid Malone 		    &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
578f2477ae1SMike Smith 	}
579ca26842eSHajimu UMEMOTO #ifdef INET6
580ca26842eSHajimu UMEMOTO 	/*
581ca26842eSHajimu UMEMOTO 	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
582ca26842eSHajimu UMEMOTO 	 * default and some apps depend on this. So, set V6ONLY to 0
583ca26842eSHajimu UMEMOTO 	 * for Linux apps if the sysctl value is set to 1.
584ca26842eSHajimu UMEMOTO 	 */
58537e7a5a2SHajimu UMEMOTO 	if (bsd_args.domain == PF_INET6 && retval_socket >= 0
58637e7a5a2SHajimu UMEMOTO #ifndef KLD_MODULE
58737e7a5a2SHajimu UMEMOTO 	    /*
58837e7a5a2SHajimu UMEMOTO 	     * XXX: Avoid undefined symbol error with an IPv4 only
58937e7a5a2SHajimu UMEMOTO 	     * kernel.
59037e7a5a2SHajimu UMEMOTO 	     */
59137e7a5a2SHajimu UMEMOTO 	    && ip6_v6only
59237e7a5a2SHajimu UMEMOTO #endif
59337e7a5a2SHajimu UMEMOTO 	    ) {
594e140eb43SDavid Malone 		int v6only;
595ca26842eSHajimu UMEMOTO 
596e140eb43SDavid Malone 		v6only = 0;
597ca26842eSHajimu UMEMOTO 		/* We ignore any error returned by setsockopt() */
598e140eb43SDavid Malone 		kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
599e140eb43SDavid Malone 		    &v6only, UIO_SYSSPACE, sizeof(v6only));
600ca26842eSHajimu UMEMOTO 	}
601ca26842eSHajimu UMEMOTO #endif
6023f3a4815SMarcel Moolenaar 
6033f3a4815SMarcel Moolenaar 	return (retval_socket);
604c21dee17SSøren Schmidt }
605c21dee17SSøren Schmidt 
606c21dee17SSøren Schmidt struct linux_bind_args {
607c21dee17SSøren Schmidt 	int s;
6084af27623STim J. Robbins 	l_uintptr_t name;
609c21dee17SSøren Schmidt 	int namelen;
610c21dee17SSøren Schmidt };
611c21dee17SSøren Schmidt 
612c21dee17SSøren Schmidt static int
613b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
614c21dee17SSøren Schmidt {
615c21dee17SSøren Schmidt 	struct linux_bind_args linux_args;
616ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
617c21dee17SSøren Schmidt 	int error;
618c21dee17SSøren Schmidt 
6193f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6203f3a4815SMarcel Moolenaar 		return (error);
6213f3a4815SMarcel Moolenaar 
6224af27623STim J. Robbins 	error = linux_getsockaddr(&sa, PTRIN(linux_args.name),
6234af27623STim J. Robbins 	    linux_args.namelen);
624ca26842eSHajimu UMEMOTO 	if (error)
625ca26842eSHajimu UMEMOTO 		return (error);
626ca26842eSHajimu UMEMOTO 
627b33887eaSJohn Baldwin 	error = kern_bind(td, linux_args.s, sa);
628b33887eaSJohn Baldwin 	free(sa, M_SONAME);
629d4b7423fSAlexander Leidinger 	if (error == EADDRNOTAVAIL && linux_args.namelen != sizeof(struct sockaddr_in))
630d4b7423fSAlexander Leidinger 	   	return (EINVAL);
631b33887eaSJohn Baldwin 	return (error);
632c21dee17SSøren Schmidt }
633c21dee17SSøren Schmidt 
63401e0ffbaSAlexander Leidinger struct linux_connect_args {
635c21dee17SSøren Schmidt 	int s;
6364af27623STim J. Robbins 	l_uintptr_t name;
637c21dee17SSøren Schmidt 	int namelen;
638c21dee17SSøren Schmidt };
639b40ce416SJulian Elischer int linux_connect(struct thread *, struct linux_connect_args *);
640c21dee17SSøren Schmidt 
641930a65feSAndrew Gallatin int
642b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
643c21dee17SSøren Schmidt {
64401e0ffbaSAlexander Leidinger 	struct linux_connect_args linux_args;
6450bf301c0SJonathan Lemon 	struct socket *so;
646ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
64739c95b83SMatthew Dillon 	u_int fflag;
648c21dee17SSøren Schmidt 	int error;
649c21dee17SSøren Schmidt 
6503f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6513f3a4815SMarcel Moolenaar 		return (error);
6523f3a4815SMarcel Moolenaar 
6534af27623STim J. Robbins 	error = linux_getsockaddr(&sa,
6544af27623STim J. Robbins 	    (struct osockaddr *)PTRIN(linux_args.name),
6554d45de74SDavid Malone 	    linux_args.namelen);
656ca26842eSHajimu UMEMOTO 	if (error)
657ca26842eSHajimu UMEMOTO 		return (error);
658ca26842eSHajimu UMEMOTO 
659ca26842eSHajimu UMEMOTO 	error = kern_connect(td, linux_args.s, sa);
660b33887eaSJohn Baldwin 	free(sa, M_SONAME);
6610bf301c0SJonathan Lemon 	if (error != EISCONN)
6620bf301c0SJonathan Lemon 		return (error);
6630bf301c0SJonathan Lemon 
664dad3b88aSMike Smith 	/*
665dad3b88aSMike Smith 	 * Linux doesn't return EISCONN the first time it occurs,
666dad3b88aSMike Smith 	 * when on a non-blocking socket. Instead it returns the
667dad3b88aSMike Smith 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
668f7f45ac8SRobert Watson 	 *
669f7f45ac8SRobert Watson 	 * XXXRW: Instead of using fgetsock(), check that it is a
670f7f45ac8SRobert Watson 	 * socket and use the file descriptor reference instead of
671f7f45ac8SRobert Watson 	 * creating a new one.
672dad3b88aSMike Smith 	 */
6734641373fSJohn Baldwin 	NET_LOCK_GIANT();
6744641373fSJohn Baldwin 	error = fgetsock(td, linux_args.s, &so, &fflag);
6754641373fSJohn Baldwin 	if (error == 0) {
6760bf301c0SJonathan Lemon 		error = EISCONN;
67739c95b83SMatthew Dillon 		if (fflag & FNONBLOCK) {
6784641373fSJohn Baldwin 			SOCK_LOCK(so);
6795002a60fSMarcel Moolenaar 			if (so->so_emuldata == 0)
6800bf301c0SJonathan Lemon 				error = so->so_error;
6810bf301c0SJonathan Lemon 			so->so_emuldata = (void *)1;
6824641373fSJohn Baldwin 			SOCK_UNLOCK(so);
683dad3b88aSMike Smith 		}
68439c95b83SMatthew Dillon 		fputsock(so);
6854641373fSJohn Baldwin 	}
6864641373fSJohn Baldwin 	NET_UNLOCK_GIANT();
6873f3a4815SMarcel Moolenaar 	return (error);
688c21dee17SSøren Schmidt }
689c21dee17SSøren Schmidt 
690c21dee17SSøren Schmidt struct linux_listen_args {
691c21dee17SSøren Schmidt 	int s;
692c21dee17SSøren Schmidt 	int backlog;
693c21dee17SSøren Schmidt };
694c21dee17SSøren Schmidt 
695c21dee17SSøren Schmidt static int
696b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
697c21dee17SSøren Schmidt {
698c21dee17SSøren Schmidt 	struct linux_listen_args linux_args;
699ef04503dSPeter Wemm 	struct listen_args /* {
700c21dee17SSøren Schmidt 		int s;
701c21dee17SSøren Schmidt 		int backlog;
702ef04503dSPeter Wemm 	} */ bsd_args;
703c21dee17SSøren Schmidt 	int error;
704c21dee17SSøren Schmidt 
7053f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7063f3a4815SMarcel Moolenaar 		return (error);
7073f3a4815SMarcel Moolenaar 
708c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
709c21dee17SSøren Schmidt 	bsd_args.backlog = linux_args.backlog;
710b40ce416SJulian Elischer 	return (listen(td, &bsd_args));
711c21dee17SSøren Schmidt }
712c21dee17SSøren Schmidt 
71301e0ffbaSAlexander Leidinger struct linux_accept_args {
714c21dee17SSøren Schmidt 	int s;
7154af27623STim J. Robbins 	l_uintptr_t addr;
7164af27623STim J. Robbins 	l_uintptr_t namelen;
717c21dee17SSøren Schmidt };
718c21dee17SSøren Schmidt 
71901e0ffbaSAlexander Leidinger static int
720b40ce416SJulian Elischer linux_accept(struct thread *td, struct linux_accept_args *args)
721c21dee17SSøren Schmidt {
72201e0ffbaSAlexander Leidinger 	struct linux_accept_args linux_args;
723ef04503dSPeter Wemm 	struct accept_args /* {
724c21dee17SSøren Schmidt 		int	s;
7253db2a843SBruce Evans 		struct sockaddr * __restrict name;
7263db2a843SBruce Evans 		socklen_t * __restrict anamelen;
727ef04503dSPeter Wemm 	} */ bsd_args;
7282ca25ab5SJohn Baldwin 	int error, fd;
729c21dee17SSøren Schmidt 
7303f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7313f3a4815SMarcel Moolenaar 		return (error);
7323f3a4815SMarcel Moolenaar 
733c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
7343db2a843SBruce Evans 	/* XXX: */
7354af27623STim J. Robbins 	bsd_args.name = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
7364af27623STim J. Robbins 	bsd_args.anamelen = PTRIN(linux_args.namelen);/* XXX */
7375c8919adSAlexander Leidinger 	error = accept(td, &bsd_args);
7385c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
739d4b7423fSAlexander Leidinger 	if (error) {
740d4b7423fSAlexander Leidinger 	   	if (error == EFAULT && linux_args.namelen != sizeof(struct sockaddr_in))
741d4b7423fSAlexander Leidinger 		   	return (EINVAL);
742dba5ab66SMarcel Moolenaar 		return (error);
743d4b7423fSAlexander Leidinger 	}
744ca26842eSHajimu UMEMOTO 	if (linux_args.addr) {
7454af27623STim J. Robbins 		error = linux_sa_put(PTRIN(linux_args.addr));
746ca26842eSHajimu UMEMOTO 		if (error) {
747c1cccebeSJohn Baldwin 			(void)kern_close(td, td->td_retval[0]);
748ca26842eSHajimu UMEMOTO 			return (error);
749ca26842eSHajimu UMEMOTO 		}
750ca26842eSHajimu UMEMOTO 	}
751dba5ab66SMarcel Moolenaar 
752dba5ab66SMarcel Moolenaar 	/*
753dba5ab66SMarcel Moolenaar 	 * linux appears not to copy flags from the parent socket to the
754dba5ab66SMarcel Moolenaar 	 * accepted one, so we must clear the flags in the new descriptor.
755dba5ab66SMarcel Moolenaar 	 * Ignore any errors, because we already have an open fd.
756dba5ab66SMarcel Moolenaar 	 */
7572ca25ab5SJohn Baldwin 	fd = td->td_retval[0];
7582ca25ab5SJohn Baldwin 	(void)kern_fcntl(td, fd, F_SETFL, 0);
7592ca25ab5SJohn Baldwin 	td->td_retval[0] = fd;
760dba5ab66SMarcel Moolenaar 	return (0);
761c21dee17SSøren Schmidt }
762c21dee17SSøren Schmidt 
76301e0ffbaSAlexander Leidinger struct linux_getsockname_args {
764c21dee17SSøren Schmidt 	int s;
7654af27623STim J. Robbins 	l_uintptr_t addr;
7664af27623STim J. Robbins 	l_uintptr_t namelen;
767c21dee17SSøren Schmidt };
768c21dee17SSøren Schmidt 
76901e0ffbaSAlexander Leidinger static int
770b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
771c21dee17SSøren Schmidt {
77201e0ffbaSAlexander Leidinger 	struct linux_getsockname_args linux_args;
773ef04503dSPeter Wemm 	struct getsockname_args /* {
774c21dee17SSøren Schmidt 		int	fdes;
7753db2a843SBruce Evans 		struct sockaddr * __restrict asa;
7763db2a843SBruce Evans 		socklen_t * __restrict alen;
777ef04503dSPeter Wemm 	} */ bsd_args;
778c21dee17SSøren Schmidt 	int error;
779c21dee17SSøren Schmidt 
7803f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7813f3a4815SMarcel Moolenaar 		return (error);
7823f3a4815SMarcel Moolenaar 
783c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
7843db2a843SBruce Evans 	/* XXX: */
7854af27623STim J. Robbins 	bsd_args.asa = (struct sockaddr * __restrict)PTRIN(linux_args.addr);
7864af27623STim J. Robbins 	bsd_args.alen = PTRIN(linux_args.namelen);	/* XXX */
7875c8919adSAlexander Leidinger 	error = getsockname(td, &bsd_args);
7885c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
789ca26842eSHajimu UMEMOTO 	if (error)
790ca26842eSHajimu UMEMOTO 		return (error);
7914af27623STim J. Robbins 	error = linux_sa_put(PTRIN(linux_args.addr));
792ca26842eSHajimu UMEMOTO 	if (error)
793ca26842eSHajimu UMEMOTO 		return (error);
794ca26842eSHajimu UMEMOTO 	return (0);
795c21dee17SSøren Schmidt }
796c21dee17SSøren Schmidt 
79701e0ffbaSAlexander Leidinger struct linux_getpeername_args {
798c21dee17SSøren Schmidt 	int s;
7994af27623STim J. Robbins 	l_uintptr_t addr;
8004af27623STim J. Robbins 	l_uintptr_t namelen;
801c21dee17SSøren Schmidt };
802c21dee17SSøren Schmidt 
80301e0ffbaSAlexander Leidinger static int
804b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
805c21dee17SSøren Schmidt {
80601e0ffbaSAlexander Leidinger 	struct linux_getpeername_args linux_args;
8075c8919adSAlexander Leidinger 	struct getpeername_args /* {
808c21dee17SSøren Schmidt 		int fdes;
809c21dee17SSøren Schmidt 		caddr_t asa;
810c21dee17SSøren Schmidt 		int *alen;
811ef04503dSPeter Wemm 	} */ bsd_args;
812c21dee17SSøren Schmidt 	int error;
813c21dee17SSøren Schmidt 
8143f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8153f3a4815SMarcel Moolenaar 		return (error);
8163f3a4815SMarcel Moolenaar 
817c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
8185c8919adSAlexander Leidinger 	bsd_args.asa = (struct sockaddr *)PTRIN(linux_args.addr);
8194af27623STim J. Robbins 	bsd_args.alen = (int *)PTRIN(linux_args.namelen);
8205c8919adSAlexander Leidinger 	error = getpeername(td, &bsd_args);
8215c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
822ca26842eSHajimu UMEMOTO 	if (error)
823ca26842eSHajimu UMEMOTO 		return (error);
8244af27623STim J. Robbins 	error = linux_sa_put(PTRIN(linux_args.addr));
825ca26842eSHajimu UMEMOTO 	if (error)
826ca26842eSHajimu UMEMOTO 		return (error);
827ca26842eSHajimu UMEMOTO 	return (0);
828c21dee17SSøren Schmidt }
829c21dee17SSøren Schmidt 
83001e0ffbaSAlexander Leidinger struct linux_socketpair_args {
831c21dee17SSøren Schmidt 	int domain;
832c21dee17SSøren Schmidt 	int type;
833c21dee17SSøren Schmidt 	int protocol;
8344af27623STim J. Robbins 	l_uintptr_t rsv;
835c21dee17SSøren Schmidt };
836c21dee17SSøren Schmidt 
83701e0ffbaSAlexander Leidinger static int
838b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
839c21dee17SSøren Schmidt {
84001e0ffbaSAlexander Leidinger 	struct linux_socketpair_args linux_args;
841ef04503dSPeter Wemm 	struct socketpair_args /* {
842c21dee17SSøren Schmidt 		int domain;
843c21dee17SSøren Schmidt 		int type;
844c21dee17SSøren Schmidt 		int protocol;
845c21dee17SSøren Schmidt 		int *rsv;
846ef04503dSPeter Wemm 	} */ bsd_args;
847c21dee17SSøren Schmidt 	int error;
848c21dee17SSøren Schmidt 
8493f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8503f3a4815SMarcel Moolenaar 		return (error);
8513f3a4815SMarcel Moolenaar 
852c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
853c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
8543f3a4815SMarcel Moolenaar 		return (EINVAL);
8553f3a4815SMarcel Moolenaar 
856c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
857c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
8584af27623STim J. Robbins 	bsd_args.rsv = (int *)PTRIN(linux_args.rsv);
859b40ce416SJulian Elischer 	return (socketpair(td, &bsd_args));
860c21dee17SSøren Schmidt }
861c21dee17SSøren Schmidt 
86201e0ffbaSAlexander Leidinger struct linux_send_args {
863c21dee17SSøren Schmidt 	int s;
8644af27623STim J. Robbins 	l_uintptr_t msg;
865c21dee17SSøren Schmidt 	int len;
866c21dee17SSøren Schmidt 	int flags;
867c21dee17SSøren Schmidt };
868c21dee17SSøren Schmidt 
86901e0ffbaSAlexander Leidinger static int
870b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
871c21dee17SSøren Schmidt {
87201e0ffbaSAlexander Leidinger 	struct linux_send_args linux_args;
87387d72a8fSPoul-Henning Kamp 	struct sendto_args /* {
874c21dee17SSøren Schmidt 		int s;
875c21dee17SSøren Schmidt 		caddr_t buf;
876044af7c3SJonathan Mini 		int len;
877c21dee17SSøren Schmidt 		int flags;
87887d72a8fSPoul-Henning Kamp 		caddr_t to;
87987d72a8fSPoul-Henning Kamp 		int tolen;
880ef04503dSPeter Wemm 	} */ bsd_args;
8818d6e40c3SMaxim Sobolev 	int error;
882c21dee17SSøren Schmidt 
8833f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8843f3a4815SMarcel Moolenaar 		return (error);
8853f3a4815SMarcel Moolenaar 
886c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
8874af27623STim J. Robbins 	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
888c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
889c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
89087d72a8fSPoul-Henning Kamp 	bsd_args.to = NULL;
89187d72a8fSPoul-Henning Kamp 	bsd_args.tolen = 0;
8928d6e40c3SMaxim Sobolev 	return sendto(td, &bsd_args);
893c21dee17SSøren Schmidt }
894c21dee17SSøren Schmidt 
89501e0ffbaSAlexander Leidinger struct linux_recv_args {
896c21dee17SSøren Schmidt 	int s;
8974af27623STim J. Robbins 	l_uintptr_t msg;
898c21dee17SSøren Schmidt 	int len;
899c21dee17SSøren Schmidt 	int flags;
900c21dee17SSøren Schmidt };
901c21dee17SSøren Schmidt 
90201e0ffbaSAlexander Leidinger static int
903b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
904c21dee17SSøren Schmidt {
90501e0ffbaSAlexander Leidinger 	struct linux_recv_args linux_args;
90687d72a8fSPoul-Henning Kamp 	struct recvfrom_args /* {
907c21dee17SSøren Schmidt 		int s;
908c21dee17SSøren Schmidt 		caddr_t buf;
909c21dee17SSøren Schmidt 		int len;
910c21dee17SSøren Schmidt 		int flags;
91187d72a8fSPoul-Henning Kamp 		struct sockaddr *from;
91287d72a8fSPoul-Henning Kamp 		socklen_t fromlenaddr;
913ef04503dSPeter Wemm 	} */ bsd_args;
914c21dee17SSøren Schmidt 	int error;
915c21dee17SSøren Schmidt 
9163f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
9173f3a4815SMarcel Moolenaar 		return (error);
9183f3a4815SMarcel Moolenaar 
919c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
9204af27623STim J. Robbins 	bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
921c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
922c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
92387d72a8fSPoul-Henning Kamp 	bsd_args.from = NULL;
92487d72a8fSPoul-Henning Kamp 	bsd_args.fromlenaddr = 0;
92587d72a8fSPoul-Henning Kamp 	return (recvfrom(td, &bsd_args));
926c21dee17SSøren Schmidt }
927c21dee17SSøren Schmidt 
928c21dee17SSøren Schmidt static int
929b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
930c21dee17SSøren Schmidt {
931c21dee17SSøren Schmidt 	struct linux_sendto_args linux_args;
9325a8a13e0SDavid Malone 	struct msghdr msg;
9335a8a13e0SDavid Malone 	struct iovec aiov;
9345a8a13e0SDavid Malone 	int error;
935c21dee17SSøren Schmidt 
9363f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
9373f3a4815SMarcel Moolenaar 		return (error);
9383f3a4815SMarcel Moolenaar 
939e140eb43SDavid Malone 	if (linux_check_hdrincl(td, linux_args.s) == 0)
940f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
941e140eb43SDavid Malone 		return (linux_sendto_hdrincl(td, &linux_args));
942f2477ae1SMike Smith 
9434af27623STim J. Robbins 	msg.msg_name = PTRIN(linux_args.to);
9445a8a13e0SDavid Malone 	msg.msg_namelen = linux_args.tolen;
9455a8a13e0SDavid Malone 	msg.msg_iov = &aiov;
9465a8a13e0SDavid Malone 	msg.msg_iovlen = 1;
9475a8a13e0SDavid Malone 	msg.msg_control = NULL;
9485a8a13e0SDavid Malone 	msg.msg_flags = 0;
9494af27623STim J. Robbins 	aiov.iov_base = PTRIN(linux_args.msg);
9505a8a13e0SDavid Malone 	aiov.iov_len = linux_args.len;
951a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
952a6886ef1SMaxim Sobolev 	    UIO_USERSPACE);
9535a8a13e0SDavid Malone 	return (error);
954c21dee17SSøren Schmidt }
955c21dee17SSøren Schmidt 
95601e0ffbaSAlexander Leidinger struct linux_recvfrom_args {
957c21dee17SSøren Schmidt 	int s;
9584af27623STim J. Robbins 	l_uintptr_t buf;
959c21dee17SSøren Schmidt 	int len;
960c21dee17SSøren Schmidt 	int flags;
9614af27623STim J. Robbins 	l_uintptr_t from;
9624af27623STim J. Robbins 	l_uintptr_t fromlen;
963c21dee17SSøren Schmidt };
964c21dee17SSøren Schmidt 
96501e0ffbaSAlexander Leidinger static int
966b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
967c21dee17SSøren Schmidt {
96801e0ffbaSAlexander Leidinger 	struct linux_recvfrom_args linux_args;
969ef04503dSPeter Wemm 	struct recvfrom_args /* {
970c21dee17SSøren Schmidt 		int	s;
971c21dee17SSøren Schmidt 		caddr_t	buf;
972c21dee17SSøren Schmidt 		size_t	len;
973c21dee17SSøren Schmidt 		int	flags;
9743db2a843SBruce Evans 		struct sockaddr * __restrict from;
9753db2a843SBruce Evans 		socklen_t * __restrict fromlenaddr;
976ef04503dSPeter Wemm 	} */ bsd_args;
9775c8919adSAlexander Leidinger 	size_t len;
978c21dee17SSøren Schmidt 	int error;
979c21dee17SSøren Schmidt 
9803f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
9813f3a4815SMarcel Moolenaar 		return (error);
9823f3a4815SMarcel Moolenaar 
9835c8919adSAlexander Leidinger 	if ((error = copyin(PTRIN(linux_args.fromlen), &len, sizeof(size_t))))
9845c8919adSAlexander Leidinger 		return (error);
9855c8919adSAlexander Leidinger 
986c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
9874af27623STim J. Robbins 	bsd_args.buf = PTRIN(linux_args.buf);
988c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
98940dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
9903db2a843SBruce Evans 	/* XXX: */
9914af27623STim J. Robbins 	bsd_args.from = (struct sockaddr * __restrict)PTRIN(linux_args.from);
9924af27623STim J. Robbins 	bsd_args.fromlenaddr = PTRIN(linux_args.fromlen);/* XXX */
9935c8919adSAlexander Leidinger 
9945c8919adSAlexander Leidinger 	linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
9955c8919adSAlexander Leidinger 	error = recvfrom(td, &bsd_args);
9965c8919adSAlexander Leidinger 	bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
9975c8919adSAlexander Leidinger 
998ca26842eSHajimu UMEMOTO 	if (error)
999ca26842eSHajimu UMEMOTO 		return (error);
1000ca26842eSHajimu UMEMOTO 	if (linux_args.from) {
10014af27623STim J. Robbins 		error = linux_sa_put((struct osockaddr *)
10024af27623STim J. Robbins 		    PTRIN(linux_args.from));
1003ca26842eSHajimu UMEMOTO 		if (error)
1004ca26842eSHajimu UMEMOTO 			return (error);
1005ca26842eSHajimu UMEMOTO 	}
1006ca26842eSHajimu UMEMOTO 	return (0);
1007ca26842eSHajimu UMEMOTO }
1008ca26842eSHajimu UMEMOTO 
100901e0ffbaSAlexander Leidinger struct linux_sendmsg_args {
1010ca26842eSHajimu UMEMOTO 	int s;
10114af27623STim J. Robbins 	l_uintptr_t msg;
1012ca26842eSHajimu UMEMOTO 	int flags;
1013ca26842eSHajimu UMEMOTO };
1014ca26842eSHajimu UMEMOTO 
101501e0ffbaSAlexander Leidinger static int
1016ca26842eSHajimu UMEMOTO linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1017ca26842eSHajimu UMEMOTO {
101801e0ffbaSAlexander Leidinger 	struct linux_sendmsg_args linux_args;
1019ca26842eSHajimu UMEMOTO 	struct msghdr msg;
1020552afd9cSPoul-Henning Kamp 	struct iovec *iov;
1021ca26842eSHajimu UMEMOTO 	int error;
1022ca26842eSHajimu UMEMOTO 
10234af27623STim J. Robbins 	/* XXXTJR sendmsg is broken on amd64 */
10244af27623STim J. Robbins 
1025552afd9cSPoul-Henning Kamp 	error = copyin(args, &linux_args, sizeof(linux_args));
1026552afd9cSPoul-Henning Kamp 	if (error)
1027ca26842eSHajimu UMEMOTO 		return (error);
10284af27623STim J. Robbins 	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1029ca26842eSHajimu UMEMOTO 	if (error)
1030ca26842eSHajimu UMEMOTO 		return (error);
1031d72a6158SRobert Watson 
1032d72a6158SRobert Watson 	/*
1033d72a6158SRobert Watson 	 * Some Linux applications (ping) define a non-NULL control data
1034d72a6158SRobert Watson 	 * pointer, but a msg_controllen of 0, which is not allowed in the
1035d72a6158SRobert Watson 	 * FreeBSD system call interface.  NULL the msg_control pointer in
1036d72a6158SRobert Watson 	 * order to handle this case.  This should be checked, but allows the
1037d72a6158SRobert Watson 	 * Linux ping to work.
1038d72a6158SRobert Watson 	 */
1039d72a6158SRobert Watson 	if (msg.msg_control != NULL && msg.msg_controllen == 0)
1040d72a6158SRobert Watson 		msg.msg_control = NULL;
1041552afd9cSPoul-Henning Kamp 	error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1042552afd9cSPoul-Henning Kamp 	if (error)
1043552afd9cSPoul-Henning Kamp 		return (error);
10445a8a13e0SDavid Malone 	msg.msg_iov = iov;
10455a8a13e0SDavid Malone 	msg.msg_flags = 0;
1046a6886ef1SMaxim Sobolev 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags,
1047a6886ef1SMaxim Sobolev 	    UIO_USERSPACE);
1048552afd9cSPoul-Henning Kamp 	free(iov, M_IOV);
1049ca26842eSHajimu UMEMOTO 	return (error);
1050c21dee17SSøren Schmidt }
1051c21dee17SSøren Schmidt 
105201e0ffbaSAlexander Leidinger struct linux_recvmsg_args {
105340dbba57SAssar Westerlund 	int s;
10544af27623STim J. Robbins 	l_uintptr_t msg;
105540dbba57SAssar Westerlund 	int flags;
105640dbba57SAssar Westerlund };
105740dbba57SAssar Westerlund 
105801e0ffbaSAlexander Leidinger static int
1059b40ce416SJulian Elischer linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
106040dbba57SAssar Westerlund {
106101e0ffbaSAlexander Leidinger 	struct linux_recvmsg_args linux_args;
106240dbba57SAssar Westerlund 	struct recvmsg_args /* {
106340dbba57SAssar Westerlund 		int	s;
106440dbba57SAssar Westerlund 		struct	msghdr *msg;
106540dbba57SAssar Westerlund 		int	flags;
106640dbba57SAssar Westerlund 	} */ bsd_args;
1067ca26842eSHajimu UMEMOTO 	struct msghdr msg;
106884b11cd8SMitsuru IWASAKI 	struct cmsghdr *cmsg;
106940dbba57SAssar Westerlund 	int error;
107040dbba57SAssar Westerlund 
10714af27623STim J. Robbins 	/* XXXTJR recvmsg is broken on amd64 */
10724af27623STim J. Robbins 
107340dbba57SAssar Westerlund 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
107440dbba57SAssar Westerlund 		return (error);
107540dbba57SAssar Westerlund 
1076d0b2365eSKonstantin Belousov 	if ((error = copyin(PTRIN(args->msg), &msg, sizeof (msg))))
1077d0b2365eSKonstantin Belousov 		return (error);
1078d0b2365eSKonstantin Belousov 
107940dbba57SAssar Westerlund 	bsd_args.s = linux_args.s;
10804af27623STim J. Robbins 	bsd_args.msg = PTRIN(linux_args.msg);
108140dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
10825c8919adSAlexander Leidinger 	if (msg.msg_name) {
10835c8919adSAlexander Leidinger 	   	linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
10845c8919adSAlexander Leidinger 		      msg.msg_namelen);
10855c8919adSAlexander Leidinger 		error = recvmsg(td, &bsd_args);
10865c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)msg.msg_name);
10875c8919adSAlexander Leidinger 	} else
1088ca26842eSHajimu UMEMOTO 	   	error = recvmsg(td, &bsd_args);
1089ca26842eSHajimu UMEMOTO 	if (error)
1090ca26842eSHajimu UMEMOTO 		return (error);
1091ca26842eSHajimu UMEMOTO 
109272261b9fSDag-Erling Smørgrav 	if (bsd_args.msg->msg_control != NULL &&
109372261b9fSDag-Erling Smørgrav 	    bsd_args.msg->msg_controllen > 0) {
109484b11cd8SMitsuru IWASAKI 		cmsg = (struct cmsghdr*)bsd_args.msg->msg_control;
109584b11cd8SMitsuru IWASAKI 		cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level);
109684b11cd8SMitsuru IWASAKI 	}
109784b11cd8SMitsuru IWASAKI 
10984af27623STim J. Robbins 	error = copyin(PTRIN(linux_args.msg), &msg, sizeof(msg));
1099ca26842eSHajimu UMEMOTO 	if (error)
1100ca26842eSHajimu UMEMOTO 		return (error);
1101ca26842eSHajimu UMEMOTO 	if (msg.msg_name && msg.msg_namelen > 2)
1102ca26842eSHajimu UMEMOTO 		error = linux_sa_put(msg.msg_name);
1103ca26842eSHajimu UMEMOTO 	return (error);
110440dbba57SAssar Westerlund }
110540dbba57SAssar Westerlund 
1106c21dee17SSøren Schmidt struct linux_shutdown_args {
1107c21dee17SSøren Schmidt 	int s;
1108c21dee17SSøren Schmidt 	int how;
1109c21dee17SSøren Schmidt };
1110c21dee17SSøren Schmidt 
1111c21dee17SSøren Schmidt static int
1112b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1113c21dee17SSøren Schmidt {
1114c21dee17SSøren Schmidt 	struct linux_shutdown_args linux_args;
1115ef04503dSPeter Wemm 	struct shutdown_args /* {
1116c21dee17SSøren Schmidt 		int s;
1117c21dee17SSøren Schmidt 		int how;
1118ef04503dSPeter Wemm 	} */ bsd_args;
1119c21dee17SSøren Schmidt 	int error;
1120c21dee17SSøren Schmidt 
11213f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
11223f3a4815SMarcel Moolenaar 		return (error);
11233f3a4815SMarcel Moolenaar 
1124c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1125c21dee17SSøren Schmidt 	bsd_args.how = linux_args.how;
1126b40ce416SJulian Elischer 	return (shutdown(td, &bsd_args));
1127c21dee17SSøren Schmidt }
1128c21dee17SSøren Schmidt 
1129c21dee17SSøren Schmidt struct linux_setsockopt_args {
1130c21dee17SSøren Schmidt 	int s;
1131c21dee17SSøren Schmidt 	int level;
1132c21dee17SSøren Schmidt 	int optname;
11334af27623STim J. Robbins 	l_uintptr_t optval;
1134c21dee17SSøren Schmidt 	int optlen;
1135c21dee17SSøren Schmidt };
1136c21dee17SSøren Schmidt 
1137c21dee17SSøren Schmidt static int
1138b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1139c21dee17SSøren Schmidt {
1140c21dee17SSøren Schmidt 	struct linux_setsockopt_args linux_args;
1141ef04503dSPeter Wemm 	struct setsockopt_args /* {
1142c21dee17SSøren Schmidt 		int s;
1143c21dee17SSøren Schmidt 		int level;
1144c21dee17SSøren Schmidt 		int name;
1145c21dee17SSøren Schmidt 		caddr_t val;
1146c21dee17SSøren Schmidt 		int valsize;
1147ef04503dSPeter Wemm 	} */ bsd_args;
1148c21dee17SSøren Schmidt 	int error, name;
1149c21dee17SSøren Schmidt 
11503f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
11513f3a4815SMarcel Moolenaar 		return (error);
11523f3a4815SMarcel Moolenaar 
1153c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1154c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1155c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1156c21dee17SSøren Schmidt 	case SOL_SOCKET:
1157c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1158c21dee17SSøren Schmidt 		break;
1159c21dee17SSøren Schmidt 	case IPPROTO_IP:
1160c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1161c21dee17SSøren Schmidt 		break;
1162dad3b88aSMike Smith 	case IPPROTO_TCP:
1163dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1164dad3b88aSMike Smith 		name = linux_args.optname;
1165dad3b88aSMike Smith 		break;
1166c21dee17SSøren Schmidt 	default:
11673f3a4815SMarcel Moolenaar 		name = -1;
11683f3a4815SMarcel Moolenaar 		break;
1169c21dee17SSøren Schmidt 	}
1170c21dee17SSøren Schmidt 	if (name == -1)
1171d4b7423fSAlexander Leidinger 		return (ENOPROTOOPT);
11723f3a4815SMarcel Moolenaar 
1173c21dee17SSøren Schmidt 	bsd_args.name = name;
11744af27623STim J. Robbins 	bsd_args.val = PTRIN(linux_args.optval);
1175c21dee17SSøren Schmidt 	bsd_args.valsize = linux_args.optlen;
11765c8919adSAlexander Leidinger 
11775c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
11785c8919adSAlexander Leidinger 		linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
11795c8919adSAlexander Leidinger 			bsd_args.valsize);
11805c8919adSAlexander Leidinger 		error = setsockopt(td, &bsd_args);
11815c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
11825c8919adSAlexander Leidinger 	} else
11835c8919adSAlexander Leidinger 		error = setsockopt(td, &bsd_args);
11845c8919adSAlexander Leidinger 
11855c8919adSAlexander Leidinger 	return (error);
1186c21dee17SSøren Schmidt }
1187c21dee17SSøren Schmidt 
1188c21dee17SSøren Schmidt struct linux_getsockopt_args {
1189c21dee17SSøren Schmidt 	int s;
1190c21dee17SSøren Schmidt 	int level;
1191c21dee17SSøren Schmidt 	int optname;
11924af27623STim J. Robbins 	l_uintptr_t optval;
11934af27623STim J. Robbins 	l_uintptr_t optlen;
1194c21dee17SSøren Schmidt };
1195c21dee17SSøren Schmidt 
1196c21dee17SSøren Schmidt static int
1197b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1198c21dee17SSøren Schmidt {
1199c21dee17SSøren Schmidt 	struct linux_getsockopt_args linux_args;
1200ef04503dSPeter Wemm 	struct getsockopt_args /* {
1201c21dee17SSøren Schmidt 		int s;
1202c21dee17SSøren Schmidt 		int level;
1203c21dee17SSøren Schmidt 		int name;
1204c21dee17SSøren Schmidt 		caddr_t val;
1205c21dee17SSøren Schmidt 		int *avalsize;
1206ef04503dSPeter Wemm 	} */ bsd_args;
1207c21dee17SSøren Schmidt 	int error, name;
1208c21dee17SSøren Schmidt 
12093f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
12103f3a4815SMarcel Moolenaar 		return (error);
12113f3a4815SMarcel Moolenaar 
1212c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1213c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1214c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1215c21dee17SSøren Schmidt 	case SOL_SOCKET:
1216c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1217c21dee17SSøren Schmidt 		break;
1218c21dee17SSøren Schmidt 	case IPPROTO_IP:
1219c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1220c21dee17SSøren Schmidt 		break;
1221dad3b88aSMike Smith 	case IPPROTO_TCP:
1222dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1223dad3b88aSMike Smith 		name = linux_args.optname;
1224dad3b88aSMike Smith 		break;
1225c21dee17SSøren Schmidt 	default:
12263f3a4815SMarcel Moolenaar 		name = -1;
12273f3a4815SMarcel Moolenaar 		break;
1228c21dee17SSøren Schmidt 	}
1229c21dee17SSøren Schmidt 	if (name == -1)
12303f3a4815SMarcel Moolenaar 		return (EINVAL);
12313f3a4815SMarcel Moolenaar 
1232f2477ae1SMike Smith 	bsd_args.name = name;
12334af27623STim J. Robbins 	bsd_args.val = PTRIN(linux_args.optval);
12344af27623STim J. Robbins 	bsd_args.avalsize = PTRIN(linux_args.optlen);
12355c8919adSAlexander Leidinger 
12365c8919adSAlexander Leidinger 	if (name == IPV6_NEXTHOP) {
12375c8919adSAlexander Leidinger 		error = getsockopt(td, &bsd_args);
12385c8919adSAlexander Leidinger 		bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
12395c8919adSAlexander Leidinger 	} else
12405c8919adSAlexander Leidinger 		error = getsockopt(td, &bsd_args);
12415c8919adSAlexander Leidinger 
12425c8919adSAlexander Leidinger 	return (error);
1243c21dee17SSøren Schmidt }
1244c21dee17SSøren Schmidt 
1245c21dee17SSøren Schmidt int
1246b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1247c21dee17SSøren Schmidt {
12484af27623STim J. Robbins 	void *arg = (void *)(intptr_t)args->args;
12493f3a4815SMarcel Moolenaar 
1250c21dee17SSøren Schmidt 	switch (args->what) {
1251c21dee17SSøren Schmidt 	case LINUX_SOCKET:
1252b40ce416SJulian Elischer 		return (linux_socket(td, arg));
1253c21dee17SSøren Schmidt 	case LINUX_BIND:
1254b40ce416SJulian Elischer 		return (linux_bind(td, arg));
1255c21dee17SSøren Schmidt 	case LINUX_CONNECT:
1256b40ce416SJulian Elischer 		return (linux_connect(td, arg));
1257c21dee17SSøren Schmidt 	case LINUX_LISTEN:
1258b40ce416SJulian Elischer 		return (linux_listen(td, arg));
1259c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
1260b40ce416SJulian Elischer 		return (linux_accept(td, arg));
1261c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
1262b40ce416SJulian Elischer 		return (linux_getsockname(td, arg));
1263c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
1264b40ce416SJulian Elischer 		return (linux_getpeername(td, arg));
1265c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
1266b40ce416SJulian Elischer 		return (linux_socketpair(td, arg));
1267c21dee17SSøren Schmidt 	case LINUX_SEND:
1268b40ce416SJulian Elischer 		return (linux_send(td, arg));
1269c21dee17SSøren Schmidt 	case LINUX_RECV:
1270b40ce416SJulian Elischer 		return (linux_recv(td, arg));
1271c21dee17SSøren Schmidt 	case LINUX_SENDTO:
1272b40ce416SJulian Elischer 		return (linux_sendto(td, arg));
1273c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
1274b40ce416SJulian Elischer 		return (linux_recvfrom(td, arg));
1275c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
1276b40ce416SJulian Elischer 		return (linux_shutdown(td, arg));
1277c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
1278b40ce416SJulian Elischer 		return (linux_setsockopt(td, arg));
1279c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
1280b40ce416SJulian Elischer 		return (linux_getsockopt(td, arg));
1281e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
1282ca26842eSHajimu UMEMOTO 		return (linux_sendmsg(td, arg));
1283e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
1284b40ce416SJulian Elischer 		return (linux_recvmsg(td, arg));
1285c21dee17SSøren Schmidt 	}
12863f3a4815SMarcel Moolenaar 
12873f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
12883f3a4815SMarcel Moolenaar 	return (ENOSYS);
1289c21dee17SSøren Schmidt }
1290