xref: /freebsd/sys/compat/linux/linux_socket.c (revision 5a8a13e0fc8cb7ec0ee919168bd98fdbe6f3d88e)
1c21dee17SSøren Schmidt /*-
2c21dee17SSøren Schmidt  * Copyright (c) 1995 S�ren Schmidt
3c21dee17SSøren Schmidt  * All rights reserved.
4c21dee17SSøren Schmidt  *
5c21dee17SSøren Schmidt  * Redistribution and use in source and binary forms, with or without
6c21dee17SSøren Schmidt  * modification, are permitted provided that the following conditions
7c21dee17SSøren Schmidt  * are met:
8c21dee17SSøren Schmidt  * 1. Redistributions of source code must retain the above copyright
9c21dee17SSøren Schmidt  *    notice, this list of conditions and the following disclaimer
10c21dee17SSøren Schmidt  *    in this position and unchanged.
11c21dee17SSøren Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
12c21dee17SSøren Schmidt  *    notice, this list of conditions and the following disclaimer in the
13c21dee17SSøren Schmidt  *    documentation and/or other materials provided with the distribution.
14c21dee17SSøren Schmidt  * 3. The name of the author may not be used to endorse or promote products
1521dc7d4fSJens Schweikhardt  *    derived from this software without specific prior written permission
16c21dee17SSøren Schmidt  *
17c21dee17SSøren Schmidt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18c21dee17SSøren Schmidt  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19c21dee17SSøren Schmidt  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20c21dee17SSøren Schmidt  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21c21dee17SSøren Schmidt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22c21dee17SSøren Schmidt  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23c21dee17SSøren Schmidt  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24c21dee17SSøren Schmidt  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25c21dee17SSøren Schmidt  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26c21dee17SSøren Schmidt  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27c21dee17SSøren Schmidt  */
28c21dee17SSøren Schmidt 
2916dbc7f2SDavid E. O'Brien #include <sys/cdefs.h>
3016dbc7f2SDavid E. O'Brien __FBSDID("$FreeBSD$");
3116dbc7f2SDavid E. O'Brien 
321f3dad5aSBruce Evans /* XXX we use functions that might not exist. */
335591b823SEivind Eklund #include "opt_compat.h"
34ca26842eSHajimu UMEMOTO #include "opt_inet6.h"
355591b823SEivind Eklund 
365591b823SEivind Eklund #ifndef COMPAT_43
375591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
385591b823SEivind Eklund #endif
391f3dad5aSBruce Evans 
40c21dee17SSøren Schmidt #include <sys/param.h>
41f2477ae1SMike Smith #include <sys/proc.h>
42c21dee17SSøren Schmidt #include <sys/systm.h>
431f3dad5aSBruce Evans #include <sys/sysproto.h>
44dad3b88aSMike Smith #include <sys/fcntl.h>
450bf301c0SJonathan Lemon #include <sys/file.h>
46104a9b7eSAlexander Kabaev #include <sys/limits.h>
47ca26842eSHajimu UMEMOTO #include <sys/malloc.h>
485a8a13e0SDavid Malone #include <sys/mbuf.h>
49c21dee17SSøren Schmidt #include <sys/socket.h>
500bf301c0SJonathan Lemon #include <sys/socketvar.h>
51ca26842eSHajimu UMEMOTO #include <sys/syscallsubr.h>
5208637435SBruce Evans #include <sys/uio.h>
53ca26842eSHajimu UMEMOTO #include <sys/syslog.h>
541f3dad5aSBruce Evans 
55c21dee17SSøren Schmidt #include <netinet/in.h>
56f2477ae1SMike Smith #include <netinet/in_systm.h>
57f2477ae1SMike Smith #include <netinet/ip.h>
58ca26842eSHajimu UMEMOTO #ifdef INET6
59ca26842eSHajimu UMEMOTO #include <netinet/ip6.h>
60ca26842eSHajimu UMEMOTO #include <netinet6/ip6_var.h>
61ca26842eSHajimu UMEMOTO #endif
62c21dee17SSøren Schmidt 
63ac951e62SMarcel Moolenaar #include <machine/../linux/linux.h>
64ebea8660SMarcel Moolenaar #include <machine/../linux/linux_proto.h>
6540dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
66ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
67c21dee17SSøren Schmidt 
68ca26842eSHajimu UMEMOTO static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
69ca26842eSHajimu UMEMOTO     struct malloc_type *);
70ca26842eSHajimu UMEMOTO static int linux_to_bsd_domain(int);
71ca26842eSHajimu UMEMOTO 
724730796cSBill Fenner /*
73ca26842eSHajimu UMEMOTO  * Reads a linux sockaddr and does any necessary translation.
74ca26842eSHajimu UMEMOTO  * Linux sockaddrs don't have a length field, only a family.
754730796cSBill Fenner  */
764730796cSBill Fenner static int
77ca26842eSHajimu UMEMOTO linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
784730796cSBill Fenner {
79ca26842eSHajimu UMEMOTO 	int osalen = len;
804730796cSBill Fenner 
81ca26842eSHajimu UMEMOTO 	return (do_sa_get(sap, osa, &osalen, M_SONAME));
824730796cSBill Fenner }
834730796cSBill Fenner 
84ca26842eSHajimu UMEMOTO /*
85ca26842eSHajimu UMEMOTO  * Copy the osockaddr structure pointed to by osa to kernel, adjust
86ca26842eSHajimu UMEMOTO  * family and convert to sockaddr.
87ca26842eSHajimu UMEMOTO  */
88ca26842eSHajimu UMEMOTO static int
89ca26842eSHajimu UMEMOTO do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
90ca26842eSHajimu UMEMOTO     struct malloc_type *mtype)
91ca26842eSHajimu UMEMOTO {
92ca26842eSHajimu UMEMOTO 	int error=0, bdom;
93ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
94ca26842eSHajimu UMEMOTO 	struct osockaddr *kosa;
95ca26842eSHajimu UMEMOTO 	int alloclen;
96ca26842eSHajimu UMEMOTO #ifdef INET6
97ca26842eSHajimu UMEMOTO 	int oldv6size;
98ca26842eSHajimu UMEMOTO 	struct sockaddr_in6 *sin6;
99ca26842eSHajimu UMEMOTO #endif
100ca26842eSHajimu UMEMOTO 
101ca26842eSHajimu UMEMOTO 	if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
102ca26842eSHajimu UMEMOTO 		return (EINVAL);
103ca26842eSHajimu UMEMOTO 
104ca26842eSHajimu UMEMOTO 	alloclen = *osalen;
105ca26842eSHajimu UMEMOTO #ifdef INET6
106ca26842eSHajimu UMEMOTO 	oldv6size = 0;
107ca26842eSHajimu UMEMOTO 	/*
108ca26842eSHajimu UMEMOTO 	 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
109ca26842eSHajimu UMEMOTO 	 * if it's a v4-mapped address, so reserve the proper space
110ca26842eSHajimu UMEMOTO 	 * for it.
111ca26842eSHajimu UMEMOTO 	 */
112ca26842eSHajimu UMEMOTO 	if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
113ca26842eSHajimu UMEMOTO 		alloclen = sizeof (struct sockaddr_in6);
114ca26842eSHajimu UMEMOTO 		oldv6size = 1;
115ca26842eSHajimu UMEMOTO 	}
116ca26842eSHajimu UMEMOTO #endif
117ca26842eSHajimu UMEMOTO 
1185b13e781SHajimu UMEMOTO 	MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
119ca26842eSHajimu UMEMOTO 
1204b7ef73dSDag-Erling Smørgrav 	if ((error = copyin(osa, kosa, *osalen)))
121ca26842eSHajimu UMEMOTO 		goto out;
122ca26842eSHajimu UMEMOTO 
123ca26842eSHajimu UMEMOTO 	bdom = linux_to_bsd_domain(kosa->sa_family);
124ca26842eSHajimu UMEMOTO 	if (bdom == -1) {
125ca26842eSHajimu UMEMOTO 		error = EINVAL;
126ca26842eSHajimu UMEMOTO 		goto out;
127ca26842eSHajimu UMEMOTO 	}
128ca26842eSHajimu UMEMOTO 
129ca26842eSHajimu UMEMOTO #ifdef INET6
130ca26842eSHajimu UMEMOTO 	/*
131ca26842eSHajimu UMEMOTO 	 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
132ca26842eSHajimu UMEMOTO 	 * which lacks the scope id compared with RFC2553 one. If we detect
133ca26842eSHajimu UMEMOTO 	 * the situation, reject the address and write a message to system log.
134ca26842eSHajimu UMEMOTO 	 *
135ca26842eSHajimu UMEMOTO 	 * Still accept addresses for which the scope id is not used.
136ca26842eSHajimu UMEMOTO 	 */
137ca26842eSHajimu UMEMOTO 	if (oldv6size && bdom == AF_INET6) {
138ca26842eSHajimu UMEMOTO 		sin6 = (struct sockaddr_in6 *)kosa;
139ca26842eSHajimu UMEMOTO 		if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
140ca26842eSHajimu UMEMOTO 		    (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
141ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
142ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
143ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
144ca26842eSHajimu UMEMOTO 		     !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
145ca26842eSHajimu UMEMOTO 			sin6->sin6_scope_id = 0;
146ca26842eSHajimu UMEMOTO 		} else {
147ca26842eSHajimu UMEMOTO 			log(LOG_DEBUG,
148ca26842eSHajimu UMEMOTO 			    "obsolete pre-RFC2553 sockaddr_in6 rejected");
149ca26842eSHajimu UMEMOTO 			error = EINVAL;
150ca26842eSHajimu UMEMOTO 			goto out;
151ca26842eSHajimu UMEMOTO 		}
152ca26842eSHajimu UMEMOTO 	} else
153ca26842eSHajimu UMEMOTO #endif
154ca26842eSHajimu UMEMOTO 	if (bdom == AF_INET)
155ca26842eSHajimu UMEMOTO 		alloclen = sizeof(struct sockaddr_in);
156ca26842eSHajimu UMEMOTO 
157ca26842eSHajimu UMEMOTO 	sa = (struct sockaddr *) kosa;
158ca26842eSHajimu UMEMOTO 	sa->sa_family = bdom;
159ca26842eSHajimu UMEMOTO 	sa->sa_len = alloclen;
160ca26842eSHajimu UMEMOTO 
161ca26842eSHajimu UMEMOTO 	*sap = sa;
162ca26842eSHajimu UMEMOTO 	*osalen = alloclen;
163ca26842eSHajimu UMEMOTO 	return (0);
164ca26842eSHajimu UMEMOTO 
165ca26842eSHajimu UMEMOTO out:
166ca26842eSHajimu UMEMOTO 	FREE(kosa, mtype);
167ca26842eSHajimu UMEMOTO 	return (error);
168ca26842eSHajimu UMEMOTO }
169ca26842eSHajimu UMEMOTO 
170c21dee17SSøren Schmidt static int
171c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
172c21dee17SSøren Schmidt {
1733f3a4815SMarcel Moolenaar 
174c21dee17SSøren Schmidt 	switch (domain) {
175c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
1763f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
177c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
1783f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
179c21dee17SSøren Schmidt 	case LINUX_AF_INET:
1803f3a4815SMarcel Moolenaar 		return (AF_INET);
181ca26842eSHajimu UMEMOTO 	case LINUX_AF_INET6:
182ca26842eSHajimu UMEMOTO 		return (AF_INET6);
183c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
1843f3a4815SMarcel Moolenaar 		return (AF_CCITT);
185c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
1863f3a4815SMarcel Moolenaar 		return (AF_IPX);
187c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
1883f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
189c21dee17SSøren Schmidt 	}
1903f3a4815SMarcel Moolenaar 	return (-1);
191c21dee17SSøren Schmidt }
192c21dee17SSøren Schmidt 
193ca26842eSHajimu UMEMOTO #ifndef __alpha__
194ca26842eSHajimu UMEMOTO static int
195ca26842eSHajimu UMEMOTO bsd_to_linux_domain(int domain)
196ca26842eSHajimu UMEMOTO {
197ca26842eSHajimu UMEMOTO 
198ca26842eSHajimu UMEMOTO 	switch (domain) {
199ca26842eSHajimu UMEMOTO 	case AF_UNSPEC:
200ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNSPEC);
201ca26842eSHajimu UMEMOTO 	case AF_LOCAL:
202ca26842eSHajimu UMEMOTO 		return (LINUX_AF_UNIX);
203ca26842eSHajimu UMEMOTO 	case AF_INET:
204ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET);
205ca26842eSHajimu UMEMOTO 	case AF_INET6:
206ca26842eSHajimu UMEMOTO 		return (LINUX_AF_INET6);
207ca26842eSHajimu UMEMOTO 	case AF_CCITT:
208ca26842eSHajimu UMEMOTO 		return (LINUX_AF_AX25);
209ca26842eSHajimu UMEMOTO 	case AF_IPX:
210ca26842eSHajimu UMEMOTO 		return (LINUX_AF_IPX);
211ca26842eSHajimu UMEMOTO 	case AF_APPLETALK:
212ca26842eSHajimu UMEMOTO 		return (LINUX_AF_APPLETALK);
213ca26842eSHajimu UMEMOTO 	}
214ca26842eSHajimu UMEMOTO 	return (-1);
215ca26842eSHajimu UMEMOTO }
216ca26842eSHajimu UMEMOTO 
217c21dee17SSøren Schmidt static int
218c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
219c21dee17SSøren Schmidt {
2203f3a4815SMarcel Moolenaar 
221c21dee17SSøren Schmidt 	switch (level) {
222c21dee17SSøren Schmidt 	case LINUX_SOL_SOCKET:
2233f3a4815SMarcel Moolenaar 		return (SOL_SOCKET);
224c21dee17SSøren Schmidt 	}
2253f3a4815SMarcel Moolenaar 	return (level);
226c21dee17SSøren Schmidt }
227c21dee17SSøren Schmidt 
2283f3a4815SMarcel Moolenaar static int
22984b11cd8SMitsuru IWASAKI bsd_to_linux_sockopt_level(int level)
23084b11cd8SMitsuru IWASAKI {
23184b11cd8SMitsuru IWASAKI 
23284b11cd8SMitsuru IWASAKI 	switch (level) {
23384b11cd8SMitsuru IWASAKI 	case SOL_SOCKET:
23484b11cd8SMitsuru IWASAKI 		return (LINUX_SOL_SOCKET);
23584b11cd8SMitsuru IWASAKI 	}
23684b11cd8SMitsuru IWASAKI 	return (level);
23784b11cd8SMitsuru IWASAKI }
23884b11cd8SMitsuru IWASAKI 
23984b11cd8SMitsuru IWASAKI static int
2403f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
241c21dee17SSøren Schmidt {
2423f3a4815SMarcel Moolenaar 
243c21dee17SSøren Schmidt 	switch (opt) {
244c21dee17SSøren Schmidt 	case LINUX_IP_TOS:
2453f3a4815SMarcel Moolenaar 		return (IP_TOS);
246c21dee17SSøren Schmidt 	case LINUX_IP_TTL:
2473f3a4815SMarcel Moolenaar 		return (IP_TTL);
24866ff6a3cSBill Fenner 	case LINUX_IP_OPTIONS:
2493f3a4815SMarcel Moolenaar 		return (IP_OPTIONS);
25066ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_IF:
2513f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_IF);
25266ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_TTL:
2533f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_TTL);
25466ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_LOOP:
2553f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_LOOP);
25666ff6a3cSBill Fenner 	case LINUX_IP_ADD_MEMBERSHIP:
2573f3a4815SMarcel Moolenaar 		return (IP_ADD_MEMBERSHIP);
25866ff6a3cSBill Fenner 	case LINUX_IP_DROP_MEMBERSHIP:
2593f3a4815SMarcel Moolenaar 		return (IP_DROP_MEMBERSHIP);
26066ff6a3cSBill Fenner 	case LINUX_IP_HDRINCL:
2613f3a4815SMarcel Moolenaar 		return (IP_HDRINCL);
262c21dee17SSøren Schmidt 	}
2633f3a4815SMarcel Moolenaar 	return (-1);
264c21dee17SSøren Schmidt }
265c21dee17SSøren Schmidt 
266c21dee17SSøren Schmidt static int
267c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
268c21dee17SSøren Schmidt {
2693f3a4815SMarcel Moolenaar 
270c21dee17SSøren Schmidt 	switch (opt) {
271c21dee17SSøren Schmidt 	case LINUX_SO_DEBUG:
2723f3a4815SMarcel Moolenaar 		return (SO_DEBUG);
273c21dee17SSøren Schmidt 	case LINUX_SO_REUSEADDR:
2743f3a4815SMarcel Moolenaar 		return (SO_REUSEADDR);
275c21dee17SSøren Schmidt 	case LINUX_SO_TYPE:
2763f3a4815SMarcel Moolenaar 		return (SO_TYPE);
277c21dee17SSøren Schmidt 	case LINUX_SO_ERROR:
2783f3a4815SMarcel Moolenaar 		return (SO_ERROR);
279c21dee17SSøren Schmidt 	case LINUX_SO_DONTROUTE:
2803f3a4815SMarcel Moolenaar 		return (SO_DONTROUTE);
281c21dee17SSøren Schmidt 	case LINUX_SO_BROADCAST:
2823f3a4815SMarcel Moolenaar 		return (SO_BROADCAST);
283c21dee17SSøren Schmidt 	case LINUX_SO_SNDBUF:
2843f3a4815SMarcel Moolenaar 		return (SO_SNDBUF);
285c21dee17SSøren Schmidt 	case LINUX_SO_RCVBUF:
2863f3a4815SMarcel Moolenaar 		return (SO_RCVBUF);
287c21dee17SSøren Schmidt 	case LINUX_SO_KEEPALIVE:
2883f3a4815SMarcel Moolenaar 		return (SO_KEEPALIVE);
289c21dee17SSøren Schmidt 	case LINUX_SO_OOBINLINE:
2903f3a4815SMarcel Moolenaar 		return (SO_OOBINLINE);
291c21dee17SSøren Schmidt 	case LINUX_SO_LINGER:
2923f3a4815SMarcel Moolenaar 		return (SO_LINGER);
293c21dee17SSøren Schmidt 	}
2943f3a4815SMarcel Moolenaar 	return (-1);
295c21dee17SSøren Schmidt }
296c21dee17SSøren Schmidt 
29740dbba57SAssar Westerlund static int
29840dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
29940dbba57SAssar Westerlund {
30040dbba57SAssar Westerlund 	int ret_flags = 0;
30140dbba57SAssar Westerlund 
30240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
30340dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
30440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
30540dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
30640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
30740dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
30840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
30940dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
31040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
31140dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
31240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
31340dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
31440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
31540dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
31640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
31740dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
31840dbba57SAssar Westerlund #if 0 /* not handled */
31940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
32040dbba57SAssar Westerlund 		;
32140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
32240dbba57SAssar Westerlund 		;
32340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
32440dbba57SAssar Westerlund 		;
32540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
32640dbba57SAssar Westerlund 		;
32740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
32840dbba57SAssar Westerlund 		;
32940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
33040dbba57SAssar Westerlund 		;
33140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_NOSIGNAL)
33240dbba57SAssar Westerlund 		;
33340dbba57SAssar Westerlund #endif
33440dbba57SAssar Westerlund 	return ret_flags;
33540dbba57SAssar Westerlund }
33640dbba57SAssar Westerlund 
337ca26842eSHajimu UMEMOTO static int
338ca26842eSHajimu UMEMOTO linux_sa_put(struct osockaddr *osa)
339ca26842eSHajimu UMEMOTO {
340ca26842eSHajimu UMEMOTO 	struct osockaddr sa;
341ca26842eSHajimu UMEMOTO 	int error, bdom;
342ca26842eSHajimu UMEMOTO 
343ca26842eSHajimu UMEMOTO 	/*
344ca26842eSHajimu UMEMOTO 	 * Only read/write the osockaddr family part, the rest is
345ca26842eSHajimu UMEMOTO 	 * not changed.
346ca26842eSHajimu UMEMOTO 	 */
3474b7ef73dSDag-Erling Smørgrav 	error = copyin(osa, &sa, sizeof(sa.sa_family));
348ca26842eSHajimu UMEMOTO 	if (error)
349ca26842eSHajimu UMEMOTO 		return (error);
350ca26842eSHajimu UMEMOTO 
351ca26842eSHajimu UMEMOTO 	bdom = bsd_to_linux_domain(sa.sa_family);
352ca26842eSHajimu UMEMOTO 	if (bdom == -1)
353ca26842eSHajimu UMEMOTO 		return (EINVAL);
354ca26842eSHajimu UMEMOTO 
355ca26842eSHajimu UMEMOTO 	sa.sa_family = bdom;
356ca26842eSHajimu UMEMOTO 	error = copyout(&sa, osa, sizeof(sa.sa_family));
357ca26842eSHajimu UMEMOTO 	if (error)
358ca26842eSHajimu UMEMOTO 		return (error);
359ca26842eSHajimu UMEMOTO 
360ca26842eSHajimu UMEMOTO 	return (0);
361ca26842eSHajimu UMEMOTO }
362ca26842eSHajimu UMEMOTO 
3635a8a13e0SDavid Malone static int
3645a8a13e0SDavid Malone linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags)
3655a8a13e0SDavid Malone {
3665a8a13e0SDavid Malone 	struct mbuf *control;
3675a8a13e0SDavid Malone 	struct sockaddr *to;
3685a8a13e0SDavid Malone 	int error;
3695a8a13e0SDavid Malone 
3705a8a13e0SDavid Malone 	if (mp->msg_name != NULL) {
3715a8a13e0SDavid Malone 		error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
3725a8a13e0SDavid Malone 		if (error)
3735a8a13e0SDavid Malone 			return (error);
3745a8a13e0SDavid Malone 		mp->msg_name = to;
3755a8a13e0SDavid Malone 	} else
3765a8a13e0SDavid Malone 		to = NULL;
3775a8a13e0SDavid Malone 
3785a8a13e0SDavid Malone 	if (mp->msg_control != NULL) {
3795a8a13e0SDavid Malone 		struct cmsghdr *cmsg;
3805a8a13e0SDavid Malone 
3815a8a13e0SDavid Malone 		if (mp->msg_controllen < sizeof(struct cmsghdr)) {
3825a8a13e0SDavid Malone 			error = EINVAL;
3835a8a13e0SDavid Malone 			goto bad;
3845a8a13e0SDavid Malone 		}
3855a8a13e0SDavid Malone 		error = sockargs(&control, mp->msg_control,
3865a8a13e0SDavid Malone 		    mp->msg_controllen, MT_CONTROL);
3875a8a13e0SDavid Malone 		if (error)
3885a8a13e0SDavid Malone 			goto bad;
3895a8a13e0SDavid Malone 
3905a8a13e0SDavid Malone 		cmsg = mtod(control, struct cmsghdr *);
3915a8a13e0SDavid Malone 		cmsg->cmsg_level = linux_to_bsd_sockopt_level(cmsg->cmsg_level);
3925a8a13e0SDavid Malone 	} else
3935a8a13e0SDavid Malone 		control = NULL;
3945a8a13e0SDavid Malone 
3955a8a13e0SDavid Malone 	error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control);
3965a8a13e0SDavid Malone 
3975a8a13e0SDavid Malone bad:
3985a8a13e0SDavid Malone 	if (to)
3995a8a13e0SDavid Malone 		FREE(to, M_SONAME);
4005a8a13e0SDavid Malone 	return (error);
4015a8a13e0SDavid Malone }
4025a8a13e0SDavid Malone 
4033f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
404f2477ae1SMike Smith static int
4054d45de74SDavid Malone linux_check_hdrincl(struct thread *td, caddr_t *sg, int s)
406f2477ae1SMike Smith {
407f2477ae1SMike Smith 	struct getsockopt_args /* {
408f2477ae1SMike Smith 		int s;
409f2477ae1SMike Smith 		int level;
410f2477ae1SMike Smith 		int name;
411f2477ae1SMike Smith 		caddr_t val;
412f2477ae1SMike Smith 		int *avalsize;
413f2477ae1SMike Smith 	} */ bsd_args;
414f2477ae1SMike Smith 	int error;
4154d45de74SDavid Malone 	caddr_t val, valsize;
416f2477ae1SMike Smith 	int size_val = sizeof val;
417f2477ae1SMike Smith 	int optval;
418f2477ae1SMike Smith 
4194d45de74SDavid Malone 	val = stackgap_alloc(sg, sizeof(int));
4204d45de74SDavid Malone 	valsize = stackgap_alloc(sg, sizeof(int));
421f2477ae1SMike Smith 
422f2477ae1SMike Smith 	if ((error = copyout(&size_val, valsize, sizeof(size_val))))
4233f3a4815SMarcel Moolenaar 		return (error);
4243f3a4815SMarcel Moolenaar 
425f2477ae1SMike Smith 	bsd_args.s = s;
426f2477ae1SMike Smith 	bsd_args.level = IPPROTO_IP;
427f2477ae1SMike Smith 	bsd_args.name = IP_HDRINCL;
428f2477ae1SMike Smith 	bsd_args.val = val;
429f2477ae1SMike Smith 	bsd_args.avalsize = (int *)valsize;
430b40ce416SJulian Elischer 	if ((error = getsockopt(td, &bsd_args)))
4313f3a4815SMarcel Moolenaar 		return (error);
4323f3a4815SMarcel Moolenaar 
433f2477ae1SMike Smith 	if ((error = copyin(val, &optval, sizeof(optval))))
4343f3a4815SMarcel Moolenaar 		return (error);
4353f3a4815SMarcel Moolenaar 
4363f3a4815SMarcel Moolenaar 	return (optval == 0);
437f2477ae1SMike Smith }
438f2477ae1SMike Smith 
4395a8a13e0SDavid Malone struct linux_sendto_args {
4405a8a13e0SDavid Malone 	int s;
4415a8a13e0SDavid Malone 	void *msg;
4425a8a13e0SDavid Malone 	int len;
4435a8a13e0SDavid Malone 	int flags;
4445a8a13e0SDavid Malone 	caddr_t to;
4455a8a13e0SDavid Malone 	int tolen;
4465a8a13e0SDavid Malone };
4475a8a13e0SDavid Malone 
448f2477ae1SMike Smith /*
449f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
450f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
451f2477ae1SMike Smith  */
452f2477ae1SMike Smith static int
4535a8a13e0SDavid Malone linux_sendto_hdrincl(struct thread *td, caddr_t *sg, struct linux_sendto_args *linux_args)
454f2477ae1SMike Smith {
455f2477ae1SMike Smith /*
456f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
457f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
458f2477ae1SMike Smith  * It should include all the fields we modify (ip_len and ip_off)
459f2477ae1SMike Smith  * and be as small as possible to minimize copying overhead.
460f2477ae1SMike Smith  */
461f2477ae1SMike Smith #define linux_ip_copysize	8
462f2477ae1SMike Smith 
463f2477ae1SMike Smith 	struct ip *packet;
4645a8a13e0SDavid Malone 	struct msghdr msg;
4655a8a13e0SDavid Malone 	struct iovec aiov[2];
466f2477ae1SMike Smith 	int error;
467f2477ae1SMike Smith 
468f2477ae1SMike Smith 	/* Check the packet isn't too small before we mess with it */
4695a8a13e0SDavid Malone 	if (linux_args->len < linux_ip_copysize)
4703f3a4815SMarcel Moolenaar 		return (EINVAL);
471f2477ae1SMike Smith 
472f2477ae1SMike Smith 	/*
473f2477ae1SMike Smith 	 * Tweaking the user buffer in place would be bad manners.
474f2477ae1SMike Smith 	 * We create a corrected IP header with just the needed length,
475f2477ae1SMike Smith 	 * then use an iovec to glue it to the rest of the user packet
4765a8a13e0SDavid Malone 	 * when calling sendit().
477f2477ae1SMike Smith 	 */
4784d45de74SDavid Malone 	packet = (struct ip *)stackgap_alloc(sg, linux_ip_copysize);
479f2477ae1SMike Smith 
480f2477ae1SMike Smith 	/* Make a copy of the beginning of the packet to be sent */
4815a8a13e0SDavid Malone 	if ((error = copyin(linux_args->msg, packet, linux_ip_copysize)))
4823f3a4815SMarcel Moolenaar 		return (error);
483f2477ae1SMike Smith 
484f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
4855a8a13e0SDavid Malone 	packet->ip_len = linux_args->len;
486f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
487f2477ae1SMike Smith 
488f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
4895a8a13e0SDavid Malone 	msg.msg_name = linux_args->to;
4905a8a13e0SDavid Malone 	msg.msg_namelen = linux_args->tolen;
4915a8a13e0SDavid Malone 	msg.msg_iov = aiov;
4925a8a13e0SDavid Malone 	msg.msg_iovlen = 2;
4935a8a13e0SDavid Malone 	msg.msg_control = NULL;
4945a8a13e0SDavid Malone 	msg.msg_flags = 0;
4955a8a13e0SDavid Malone 	aiov[0].iov_base = (char *)packet;
4965a8a13e0SDavid Malone 	aiov[0].iov_len = linux_ip_copysize;
4975a8a13e0SDavid Malone 	aiov[1].iov_base = (char *)(linux_args->msg) + linux_ip_copysize;
4985a8a13e0SDavid Malone 	aiov[1].iov_len = linux_args->len - linux_ip_copysize;
4995a8a13e0SDavid Malone 	error = linux_sendit(td, linux_args->s, &msg, linux_args->flags);
5005a8a13e0SDavid Malone 	return (error);
501f2477ae1SMike Smith }
502f2477ae1SMike Smith 
503c21dee17SSøren Schmidt struct linux_socket_args {
504c21dee17SSøren Schmidt 	int domain;
505c21dee17SSøren Schmidt 	int type;
506c21dee17SSøren Schmidt 	int protocol;
507c21dee17SSøren Schmidt };
508c21dee17SSøren Schmidt 
509c21dee17SSøren Schmidt static int
510b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
511c21dee17SSøren Schmidt {
512c21dee17SSøren Schmidt 	struct linux_socket_args linux_args;
513ef04503dSPeter Wemm 	struct socket_args /* {
514c21dee17SSøren Schmidt 		int domain;
515c21dee17SSøren Schmidt 		int type;
516c21dee17SSøren Schmidt 		int protocol;
517ef04503dSPeter Wemm 	} */ bsd_args;
518ca26842eSHajimu UMEMOTO 	struct setsockopt_args /* {
519ca26842eSHajimu UMEMOTO 		int s;
520ca26842eSHajimu UMEMOTO 		int level;
521ca26842eSHajimu UMEMOTO 		int name;
522ca26842eSHajimu UMEMOTO 		caddr_t val;
523ca26842eSHajimu UMEMOTO 		int valsize;
524ca26842eSHajimu UMEMOTO 	} */ bsd_setsockopt_args;
525c21dee17SSøren Schmidt 	int error;
526f2477ae1SMike Smith 	int retval_socket;
527c21dee17SSøren Schmidt 
5283f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5293f3a4815SMarcel Moolenaar 		return (error);
5303f3a4815SMarcel Moolenaar 
531c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
532c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
533c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
534c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
5353f3a4815SMarcel Moolenaar 		return (EINVAL);
536f2477ae1SMike Smith 
537b40ce416SJulian Elischer 	retval_socket = socket(td, &bsd_args);
538f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
539f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
540f2477ae1SMike Smith 	    && bsd_args.domain == AF_INET
541f2477ae1SMike Smith 	    && retval_socket >= 0) {
542f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
543f2477ae1SMike Smith 		caddr_t sg;
544f2477ae1SMike Smith 		int *hdrincl;
545f2477ae1SMike Smith 
546f2477ae1SMike Smith 		sg = stackgap_init();
547f2477ae1SMike Smith 		hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
548f2477ae1SMike Smith 		*hdrincl = 1;
549b40ce416SJulian Elischer 		bsd_setsockopt_args.s = td->td_retval[0];
550f2477ae1SMike Smith 		bsd_setsockopt_args.level = IPPROTO_IP;
551f2477ae1SMike Smith 		bsd_setsockopt_args.name = IP_HDRINCL;
552f2477ae1SMike Smith 		bsd_setsockopt_args.val = (caddr_t)hdrincl;
553f2477ae1SMike Smith 		bsd_setsockopt_args.valsize = sizeof(*hdrincl);
554f2477ae1SMike Smith 		/* We ignore any error returned by setsockopt() */
555b40ce416SJulian Elischer 		setsockopt(td, &bsd_setsockopt_args);
556f2477ae1SMike Smith 		/* Copy back the return value from socket() */
557b40ce416SJulian Elischer 		td->td_retval[0] = bsd_setsockopt_args.s;
558f2477ae1SMike Smith 	}
559ca26842eSHajimu UMEMOTO #ifdef INET6
560ca26842eSHajimu UMEMOTO 	/*
561ca26842eSHajimu UMEMOTO 	 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
562ca26842eSHajimu UMEMOTO 	 * default and some apps depend on this. So, set V6ONLY to 0
563ca26842eSHajimu UMEMOTO 	 * for Linux apps if the sysctl value is set to 1.
564ca26842eSHajimu UMEMOTO 	 */
56537e7a5a2SHajimu UMEMOTO 	if (bsd_args.domain == PF_INET6 && retval_socket >= 0
56637e7a5a2SHajimu UMEMOTO #ifndef KLD_MODULE
56737e7a5a2SHajimu UMEMOTO 	    /*
56837e7a5a2SHajimu UMEMOTO 	     * XXX: Avoid undefined symbol error with an IPv4 only
56937e7a5a2SHajimu UMEMOTO 	     * kernel.
57037e7a5a2SHajimu UMEMOTO 	     */
57137e7a5a2SHajimu UMEMOTO 	    && ip6_v6only
57237e7a5a2SHajimu UMEMOTO #endif
57337e7a5a2SHajimu UMEMOTO 	    ) {
574ca26842eSHajimu UMEMOTO 		caddr_t sg;
575ca26842eSHajimu UMEMOTO 		int *v6only;
576ca26842eSHajimu UMEMOTO 
577ca26842eSHajimu UMEMOTO 		sg = stackgap_init();
578ca26842eSHajimu UMEMOTO 		v6only = (int *)stackgap_alloc(&sg, sizeof(*v6only));
579ca26842eSHajimu UMEMOTO 		*v6only = 0;
580ca26842eSHajimu UMEMOTO 		bsd_setsockopt_args.s = td->td_retval[0];
581ca26842eSHajimu UMEMOTO 		bsd_setsockopt_args.level = IPPROTO_IPV6;
582ca26842eSHajimu UMEMOTO 		bsd_setsockopt_args.name = IPV6_V6ONLY;
583ca26842eSHajimu UMEMOTO 		bsd_setsockopt_args.val = (caddr_t)v6only;
584ca26842eSHajimu UMEMOTO 		bsd_setsockopt_args.valsize = sizeof(*v6only);
585ca26842eSHajimu UMEMOTO 		/* We ignore any error returned by setsockopt() */
586ca26842eSHajimu UMEMOTO 		setsockopt(td, &bsd_setsockopt_args);
587ca26842eSHajimu UMEMOTO 		/* Copy back the return value from socket() */
588ca26842eSHajimu UMEMOTO 		td->td_retval[0] = bsd_setsockopt_args.s;
589ca26842eSHajimu UMEMOTO 	}
590ca26842eSHajimu UMEMOTO #endif
5913f3a4815SMarcel Moolenaar 
5923f3a4815SMarcel Moolenaar 	return (retval_socket);
593c21dee17SSøren Schmidt }
594c21dee17SSøren Schmidt 
595c21dee17SSøren Schmidt struct linux_bind_args {
596c21dee17SSøren Schmidt 	int s;
597ca26842eSHajimu UMEMOTO 	struct osockaddr *name;
598c21dee17SSøren Schmidt 	int namelen;
599c21dee17SSøren Schmidt };
600c21dee17SSøren Schmidt 
601c21dee17SSøren Schmidt static int
602b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
603c21dee17SSøren Schmidt {
604c21dee17SSøren Schmidt 	struct linux_bind_args linux_args;
605ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
606c21dee17SSøren Schmidt 	int error;
607c21dee17SSøren Schmidt 
6083f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6093f3a4815SMarcel Moolenaar 		return (error);
6103f3a4815SMarcel Moolenaar 
611ca26842eSHajimu UMEMOTO 	error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
612ca26842eSHajimu UMEMOTO 	if (error)
613ca26842eSHajimu UMEMOTO 		return (error);
614ca26842eSHajimu UMEMOTO 
615ca26842eSHajimu UMEMOTO 	return (kern_bind(td, linux_args.s, sa));
616c21dee17SSøren Schmidt }
617c21dee17SSøren Schmidt 
618c21dee17SSøren Schmidt struct linux_connect_args {
619c21dee17SSøren Schmidt 	int s;
620ca26842eSHajimu UMEMOTO 	struct osockaddr * name;
621c21dee17SSøren Schmidt 	int namelen;
622c21dee17SSøren Schmidt };
623b40ce416SJulian Elischer int linux_connect(struct thread *, struct linux_connect_args *);
624930a65feSAndrew Gallatin #endif /* !__alpha__*/
625c21dee17SSøren Schmidt 
626930a65feSAndrew Gallatin int
627b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
628c21dee17SSøren Schmidt {
629c21dee17SSøren Schmidt 	struct linux_connect_args linux_args;
6300bf301c0SJonathan Lemon 	struct socket *so;
631ca26842eSHajimu UMEMOTO 	struct sockaddr *sa;
63239c95b83SMatthew Dillon 	u_int fflag;
633c21dee17SSøren Schmidt 	int error;
634c21dee17SSøren Schmidt 
635930a65feSAndrew Gallatin #ifdef __alpha__
636930a65feSAndrew Gallatin 	bcopy(args, &linux_args, sizeof(linux_args));
637930a65feSAndrew Gallatin #else
6383f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6393f3a4815SMarcel Moolenaar 		return (error);
640930a65feSAndrew Gallatin #endif /* __alpha__ */
6413f3a4815SMarcel Moolenaar 
6424d45de74SDavid Malone 	error = linux_getsockaddr(&sa, (struct osockaddr *)linux_args.name,
6434d45de74SDavid Malone 	    linux_args.namelen);
644ca26842eSHajimu UMEMOTO 	if (error)
645ca26842eSHajimu UMEMOTO 		return (error);
646ca26842eSHajimu UMEMOTO 
647ca26842eSHajimu UMEMOTO 	error = kern_connect(td, linux_args.s, sa);
6480bf301c0SJonathan Lemon 	if (error != EISCONN)
6490bf301c0SJonathan Lemon 		return (error);
6500bf301c0SJonathan Lemon 
651dad3b88aSMike Smith 	/*
652dad3b88aSMike Smith 	 * Linux doesn't return EISCONN the first time it occurs,
653dad3b88aSMike Smith 	 * when on a non-blocking socket. Instead it returns the
654dad3b88aSMike Smith 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
655dad3b88aSMike Smith 	 */
65639c95b83SMatthew Dillon 	if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0)
6573f3a4815SMarcel Moolenaar 		return(error);
6580bf301c0SJonathan Lemon 	error = EISCONN;
65939c95b83SMatthew Dillon 	if (fflag & FNONBLOCK) {
6605002a60fSMarcel Moolenaar 		if (so->so_emuldata == 0)
6610bf301c0SJonathan Lemon 			error = so->so_error;
6620bf301c0SJonathan Lemon 		so->so_emuldata = (void *)1;
663dad3b88aSMike Smith 	}
66439c95b83SMatthew Dillon 	fputsock(so);
6653f3a4815SMarcel Moolenaar 	return (error);
666c21dee17SSøren Schmidt }
667c21dee17SSøren Schmidt 
668930a65feSAndrew Gallatin #ifndef __alpha__
669930a65feSAndrew Gallatin 
670c21dee17SSøren Schmidt struct linux_listen_args {
671c21dee17SSøren Schmidt 	int s;
672c21dee17SSøren Schmidt 	int backlog;
673c21dee17SSøren Schmidt };
674c21dee17SSøren Schmidt 
675c21dee17SSøren Schmidt static int
676b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
677c21dee17SSøren Schmidt {
678c21dee17SSøren Schmidt 	struct linux_listen_args linux_args;
679ef04503dSPeter Wemm 	struct listen_args /* {
680c21dee17SSøren Schmidt 		int s;
681c21dee17SSøren Schmidt 		int backlog;
682ef04503dSPeter Wemm 	} */ bsd_args;
683c21dee17SSøren Schmidt 	int error;
684c21dee17SSøren Schmidt 
6853f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6863f3a4815SMarcel Moolenaar 		return (error);
6873f3a4815SMarcel Moolenaar 
688c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
689c21dee17SSøren Schmidt 	bsd_args.backlog = linux_args.backlog;
690b40ce416SJulian Elischer 	return (listen(td, &bsd_args));
691c21dee17SSøren Schmidt }
692c21dee17SSøren Schmidt 
693c21dee17SSøren Schmidt struct linux_accept_args {
694c21dee17SSøren Schmidt 	int s;
695ca26842eSHajimu UMEMOTO 	struct osockaddr *addr;
696c21dee17SSøren Schmidt 	int *namelen;
697c21dee17SSøren Schmidt };
698c21dee17SSøren Schmidt 
699c21dee17SSøren Schmidt static int
700b40ce416SJulian Elischer linux_accept(struct thread *td, struct linux_accept_args *args)
701c21dee17SSøren Schmidt {
702c21dee17SSøren Schmidt 	struct linux_accept_args linux_args;
703ef04503dSPeter Wemm 	struct accept_args /* {
704c21dee17SSøren Schmidt 		int s;
705c21dee17SSøren Schmidt 		caddr_t name;
706c21dee17SSøren Schmidt 		int *anamelen;
707ef04503dSPeter Wemm 	} */ bsd_args;
708ca26842eSHajimu UMEMOTO 	struct close_args /* {
709ca26842eSHajimu UMEMOTO 		int     fd;
710ca26842eSHajimu UMEMOTO 	} */ c_args;
711dba5ab66SMarcel Moolenaar 	struct fcntl_args /* {
712dba5ab66SMarcel Moolenaar 		int fd;
713dba5ab66SMarcel Moolenaar 		int cmd;
714dba5ab66SMarcel Moolenaar 		long arg;
715dba5ab66SMarcel Moolenaar 	} */ f_args;
716c21dee17SSøren Schmidt 	int error;
717c21dee17SSøren Schmidt 
7183f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7193f3a4815SMarcel Moolenaar 		return (error);
7203f3a4815SMarcel Moolenaar 
721c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
722c21dee17SSøren Schmidt 	bsd_args.name = (caddr_t)linux_args.addr;
723c21dee17SSøren Schmidt 	bsd_args.anamelen = linux_args.namelen;
724044af7c3SJonathan Mini 	error = oaccept(td, &bsd_args);
725dba5ab66SMarcel Moolenaar 	if (error)
726dba5ab66SMarcel Moolenaar 		return (error);
727ca26842eSHajimu UMEMOTO 	if (linux_args.addr) {
728ca26842eSHajimu UMEMOTO 		error = linux_sa_put(linux_args.addr);
729ca26842eSHajimu UMEMOTO 		if (error) {
730ca26842eSHajimu UMEMOTO 			c_args.fd = td->td_retval[0];
731ca26842eSHajimu UMEMOTO 			(void)close(td, &c_args);
732ca26842eSHajimu UMEMOTO 			return (error);
733ca26842eSHajimu UMEMOTO 		}
734ca26842eSHajimu UMEMOTO 	}
735dba5ab66SMarcel Moolenaar 
736dba5ab66SMarcel Moolenaar 	/*
737dba5ab66SMarcel Moolenaar 	 * linux appears not to copy flags from the parent socket to the
738dba5ab66SMarcel Moolenaar 	 * accepted one, so we must clear the flags in the new descriptor.
739dba5ab66SMarcel Moolenaar 	 * Ignore any errors, because we already have an open fd.
740dba5ab66SMarcel Moolenaar 	 */
741b40ce416SJulian Elischer 	f_args.fd = td->td_retval[0];
742dba5ab66SMarcel Moolenaar 	f_args.cmd = F_SETFL;
743dba5ab66SMarcel Moolenaar 	f_args.arg = 0;
744b40ce416SJulian Elischer 	(void)fcntl(td, &f_args);
745b40ce416SJulian Elischer 	td->td_retval[0] = f_args.fd;
746dba5ab66SMarcel Moolenaar 	return (0);
747c21dee17SSøren Schmidt }
748c21dee17SSøren Schmidt 
749c21dee17SSøren Schmidt struct linux_getsockname_args {
750c21dee17SSøren Schmidt 	int s;
751ca26842eSHajimu UMEMOTO 	struct osockaddr *addr;
752c21dee17SSøren Schmidt 	int *namelen;
753c21dee17SSøren Schmidt };
754c21dee17SSøren Schmidt 
755c21dee17SSøren Schmidt static int
756b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
757c21dee17SSøren Schmidt {
758c21dee17SSøren Schmidt 	struct linux_getsockname_args linux_args;
759ef04503dSPeter Wemm 	struct getsockname_args /* {
760c21dee17SSøren Schmidt 		int fdes;
761c21dee17SSøren Schmidt 		caddr_t asa;
762c21dee17SSøren Schmidt 		int *alen;
763ef04503dSPeter Wemm 	} */ bsd_args;
764c21dee17SSøren Schmidt 	int error;
765c21dee17SSøren Schmidt 
7663f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7673f3a4815SMarcel Moolenaar 		return (error);
7683f3a4815SMarcel Moolenaar 
769c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
770c21dee17SSøren Schmidt 	bsd_args.asa = (caddr_t) linux_args.addr;
771c21dee17SSøren Schmidt 	bsd_args.alen = linux_args.namelen;
772ca26842eSHajimu UMEMOTO 	error = ogetsockname(td, &bsd_args);
773ca26842eSHajimu UMEMOTO 	if (error)
774ca26842eSHajimu UMEMOTO 		return (error);
775ca26842eSHajimu UMEMOTO 	error = linux_sa_put(linux_args.addr);
776ca26842eSHajimu UMEMOTO 	if (error)
777ca26842eSHajimu UMEMOTO 		return (error);
778ca26842eSHajimu UMEMOTO 	return (0);
779c21dee17SSøren Schmidt }
780c21dee17SSøren Schmidt 
781c21dee17SSøren Schmidt struct linux_getpeername_args {
782c21dee17SSøren Schmidt 	int s;
783ca26842eSHajimu UMEMOTO 	struct osockaddr *addr;
784c21dee17SSøren Schmidt 	int *namelen;
785c21dee17SSøren Schmidt };
786c21dee17SSøren Schmidt 
787c21dee17SSøren Schmidt static int
788b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
789c21dee17SSøren Schmidt {
790c21dee17SSøren Schmidt 	struct linux_getpeername_args linux_args;
791044af7c3SJonathan Mini 	struct ogetpeername_args /* {
792c21dee17SSøren Schmidt 		int fdes;
793c21dee17SSøren Schmidt 		caddr_t asa;
794c21dee17SSøren Schmidt 		int *alen;
795ef04503dSPeter Wemm 	} */ bsd_args;
796c21dee17SSøren Schmidt 	int error;
797c21dee17SSøren Schmidt 
7983f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7993f3a4815SMarcel Moolenaar 		return (error);
8003f3a4815SMarcel Moolenaar 
801c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
802c21dee17SSøren Schmidt 	bsd_args.asa = (caddr_t) linux_args.addr;
803c21dee17SSøren Schmidt 	bsd_args.alen = linux_args.namelen;
804ca26842eSHajimu UMEMOTO 	error = ogetpeername(td, &bsd_args);
805ca26842eSHajimu UMEMOTO 	if (error)
806ca26842eSHajimu UMEMOTO 		return (error);
807ca26842eSHajimu UMEMOTO 	error = linux_sa_put(linux_args.addr);
808ca26842eSHajimu UMEMOTO 	if (error)
809ca26842eSHajimu UMEMOTO 		return (error);
810ca26842eSHajimu UMEMOTO 	return (0);
811c21dee17SSøren Schmidt }
812c21dee17SSøren Schmidt 
813c21dee17SSøren Schmidt struct linux_socketpair_args {
814c21dee17SSøren Schmidt 	int domain;
815c21dee17SSøren Schmidt 	int type;
816c21dee17SSøren Schmidt 	int protocol;
817c21dee17SSøren Schmidt 	int *rsv;
818c21dee17SSøren Schmidt };
819c21dee17SSøren Schmidt 
820c21dee17SSøren Schmidt static int
821b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
822c21dee17SSøren Schmidt {
823c21dee17SSøren Schmidt 	struct linux_socketpair_args linux_args;
824ef04503dSPeter Wemm 	struct socketpair_args /* {
825c21dee17SSøren Schmidt 		int domain;
826c21dee17SSøren Schmidt 		int type;
827c21dee17SSøren Schmidt 		int protocol;
828c21dee17SSøren Schmidt 		int *rsv;
829ef04503dSPeter Wemm 	} */ bsd_args;
830c21dee17SSøren Schmidt 	int error;
831c21dee17SSøren Schmidt 
8323f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8333f3a4815SMarcel Moolenaar 		return (error);
8343f3a4815SMarcel Moolenaar 
835c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
836c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
8373f3a4815SMarcel Moolenaar 		return (EINVAL);
8383f3a4815SMarcel Moolenaar 
839c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
840c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
841c21dee17SSøren Schmidt 	bsd_args.rsv = linux_args.rsv;
842b40ce416SJulian Elischer 	return (socketpair(td, &bsd_args));
843c21dee17SSøren Schmidt }
844c21dee17SSøren Schmidt 
845c21dee17SSøren Schmidt struct linux_send_args {
846c21dee17SSøren Schmidt 	int s;
847c21dee17SSøren Schmidt 	void *msg;
848c21dee17SSøren Schmidt 	int len;
849c21dee17SSøren Schmidt 	int flags;
850c21dee17SSøren Schmidt };
851c21dee17SSøren Schmidt 
852c21dee17SSøren Schmidt static int
853b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
854c21dee17SSøren Schmidt {
855c21dee17SSøren Schmidt 	struct linux_send_args linux_args;
856044af7c3SJonathan Mini 	struct osend_args /* {
857c21dee17SSøren Schmidt 		int s;
858c21dee17SSøren Schmidt 		caddr_t buf;
859044af7c3SJonathan Mini 		int len;
860c21dee17SSøren Schmidt 		int flags;
861ef04503dSPeter Wemm 	} */ bsd_args;
862c21dee17SSøren Schmidt 	int error;
863c21dee17SSøren Schmidt 
8643f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8653f3a4815SMarcel Moolenaar 		return (error);
8663f3a4815SMarcel Moolenaar 
867c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
868c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.msg;
869c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
870c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
871044af7c3SJonathan Mini 	return (osend(td, &bsd_args));
872c21dee17SSøren Schmidt }
873c21dee17SSøren Schmidt 
874c21dee17SSøren Schmidt struct linux_recv_args {
875c21dee17SSøren Schmidt 	int s;
876c21dee17SSøren Schmidt 	void *msg;
877c21dee17SSøren Schmidt 	int len;
878c21dee17SSøren Schmidt 	int flags;
879c21dee17SSøren Schmidt };
880c21dee17SSøren Schmidt 
881c21dee17SSøren Schmidt static int
882b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
883c21dee17SSøren Schmidt {
884c21dee17SSøren Schmidt 	struct linux_recv_args linux_args;
885044af7c3SJonathan Mini 	struct orecv_args /* {
886c21dee17SSøren Schmidt 		int s;
887c21dee17SSøren Schmidt 		caddr_t buf;
888c21dee17SSøren Schmidt 		int len;
889c21dee17SSøren Schmidt 		int flags;
890ef04503dSPeter Wemm 	} */ bsd_args;
891c21dee17SSøren Schmidt 	int error;
892c21dee17SSøren Schmidt 
8933f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8943f3a4815SMarcel Moolenaar 		return (error);
8953f3a4815SMarcel Moolenaar 
896c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
897c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.msg;
898c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
899c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
900044af7c3SJonathan Mini 	return (orecv(td, &bsd_args));
901c21dee17SSøren Schmidt }
902c21dee17SSøren Schmidt 
903c21dee17SSøren Schmidt static int
904b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
905c21dee17SSøren Schmidt {
906c21dee17SSøren Schmidt 	struct linux_sendto_args linux_args;
9075a8a13e0SDavid Malone 	struct msghdr msg;
9085a8a13e0SDavid Malone 	struct iovec aiov;
909ca26842eSHajimu UMEMOTO 	caddr_t sg = stackgap_init();
9105a8a13e0SDavid Malone 	int error;
911c21dee17SSøren Schmidt 
9123f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
9133f3a4815SMarcel Moolenaar 		return (error);
9143f3a4815SMarcel Moolenaar 
9154d45de74SDavid Malone 	if (linux_check_hdrincl(td, &sg, linux_args.s) == 0)
916f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
9175a8a13e0SDavid Malone 		return (linux_sendto_hdrincl(td, &sg, &linux_args));
918f2477ae1SMike Smith 
9195a8a13e0SDavid Malone 	msg.msg_name = linux_args.to;
9205a8a13e0SDavid Malone 	msg.msg_namelen = linux_args.tolen;
9215a8a13e0SDavid Malone 	msg.msg_iov = &aiov;
9225a8a13e0SDavid Malone 	msg.msg_iovlen = 1;
9235a8a13e0SDavid Malone 	msg.msg_control = NULL;
9245a8a13e0SDavid Malone 	msg.msg_flags = 0;
9255a8a13e0SDavid Malone 	aiov.iov_base = linux_args.msg;
9265a8a13e0SDavid Malone 	aiov.iov_len = linux_args.len;
9275a8a13e0SDavid Malone 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags);
9285a8a13e0SDavid Malone 	return (error);
929c21dee17SSøren Schmidt }
930c21dee17SSøren Schmidt 
931c21dee17SSøren Schmidt struct linux_recvfrom_args {
932c21dee17SSøren Schmidt 	int s;
933c21dee17SSøren Schmidt 	void *buf;
934c21dee17SSøren Schmidt 	int len;
935c21dee17SSøren Schmidt 	int flags;
936c21dee17SSøren Schmidt 	caddr_t from;
937c21dee17SSøren Schmidt 	int *fromlen;
938c21dee17SSøren Schmidt };
939c21dee17SSøren Schmidt 
940c21dee17SSøren Schmidt static int
941b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
942c21dee17SSøren Schmidt {
943c21dee17SSøren Schmidt 	struct linux_recvfrom_args linux_args;
944ef04503dSPeter Wemm 	struct recvfrom_args /* {
945c21dee17SSøren Schmidt 		int s;
946c21dee17SSøren Schmidt 		caddr_t buf;
947c21dee17SSøren Schmidt 		size_t len;
948c21dee17SSøren Schmidt 		int flags;
949c21dee17SSøren Schmidt 		caddr_t from;
950c21dee17SSøren Schmidt 		int *fromlenaddr;
951ef04503dSPeter Wemm 	} */ bsd_args;
952c21dee17SSøren Schmidt 	int error;
953c21dee17SSøren Schmidt 
9543f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
9553f3a4815SMarcel Moolenaar 		return (error);
9563f3a4815SMarcel Moolenaar 
957c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
958c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.buf;
959c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
96040dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
961c21dee17SSøren Schmidt 	bsd_args.from = linux_args.from;
962c21dee17SSøren Schmidt 	bsd_args.fromlenaddr = linux_args.fromlen;
963ca26842eSHajimu UMEMOTO 	error = orecvfrom(td, &bsd_args);
964ca26842eSHajimu UMEMOTO 	if (error)
965ca26842eSHajimu UMEMOTO 		return (error);
966ca26842eSHajimu UMEMOTO 	if (linux_args.from) {
967ca26842eSHajimu UMEMOTO 		error = linux_sa_put((struct osockaddr *) linux_args.from);
968ca26842eSHajimu UMEMOTO 		if (error)
969ca26842eSHajimu UMEMOTO 			return (error);
970ca26842eSHajimu UMEMOTO 	}
971ca26842eSHajimu UMEMOTO 	return (0);
972ca26842eSHajimu UMEMOTO }
973ca26842eSHajimu UMEMOTO 
974ca26842eSHajimu UMEMOTO struct linux_sendmsg_args {
975ca26842eSHajimu UMEMOTO 	int s;
976ca26842eSHajimu UMEMOTO 	const struct msghdr *msg;
977ca26842eSHajimu UMEMOTO 	int flags;
978ca26842eSHajimu UMEMOTO };
979ca26842eSHajimu UMEMOTO 
980ca26842eSHajimu UMEMOTO static int
981ca26842eSHajimu UMEMOTO linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
982ca26842eSHajimu UMEMOTO {
983ca26842eSHajimu UMEMOTO 	struct linux_sendmsg_args linux_args;
984ca26842eSHajimu UMEMOTO 	struct msghdr msg;
9855a8a13e0SDavid Malone 	struct iovec aiov[UIO_SMALLIOV], *iov;
986ca26842eSHajimu UMEMOTO 	int error;
987ca26842eSHajimu UMEMOTO 
988ca26842eSHajimu UMEMOTO 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
989ca26842eSHajimu UMEMOTO 		return (error);
990ca26842eSHajimu UMEMOTO 
9914b7ef73dSDag-Erling Smørgrav 	error = copyin(linux_args.msg, &msg, sizeof(msg));
992ca26842eSHajimu UMEMOTO 	if (error)
993ca26842eSHajimu UMEMOTO 		return (error);
9945a8a13e0SDavid Malone 	if ((u_int)msg.msg_iovlen >= UIO_SMALLIOV) {
9955a8a13e0SDavid Malone 		if ((u_int)msg.msg_iovlen >= UIO_MAXIOV)
9965a8a13e0SDavid Malone 			return (EMSGSIZE);
9975a8a13e0SDavid Malone 		MALLOC(iov, struct iovec *,
9985a8a13e0SDavid Malone 			sizeof(struct iovec) * (u_int)msg.msg_iovlen, M_IOV,
9995a8a13e0SDavid Malone 			M_WAITOK);
10005a8a13e0SDavid Malone 	} else {
10015a8a13e0SDavid Malone 		iov = aiov;
10025a8a13e0SDavid Malone 	}
10035a8a13e0SDavid Malone 	if (msg.msg_iovlen &&
10045a8a13e0SDavid Malone 	    (error = copyin(msg.msg_iov, iov,
10055a8a13e0SDavid Malone 	    (unsigned)(msg.msg_iovlen * sizeof (struct iovec)))))
10065a8a13e0SDavid Malone 		goto done;
10075a8a13e0SDavid Malone 	msg.msg_iov = iov;
10085a8a13e0SDavid Malone 	msg.msg_flags = 0;
1009ca26842eSHajimu UMEMOTO 
10105a8a13e0SDavid Malone 	error = linux_sendit(td, linux_args.s, &msg, linux_args.flags);
10115a8a13e0SDavid Malone done:
10125a8a13e0SDavid Malone 	if (iov != aiov)
10135a8a13e0SDavid Malone 		FREE(iov, M_IOV);
1014ca26842eSHajimu UMEMOTO 	return (error);
1015c21dee17SSøren Schmidt }
1016c21dee17SSøren Schmidt 
101740dbba57SAssar Westerlund struct linux_recvmsg_args {
101840dbba57SAssar Westerlund 	int s;
101940dbba57SAssar Westerlund 	struct msghdr *msg;
102040dbba57SAssar Westerlund 	int flags;
102140dbba57SAssar Westerlund };
102240dbba57SAssar Westerlund 
102340dbba57SAssar Westerlund static int
1024b40ce416SJulian Elischer linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
102540dbba57SAssar Westerlund {
102640dbba57SAssar Westerlund 	struct linux_recvmsg_args linux_args;
102740dbba57SAssar Westerlund 	struct recvmsg_args /* {
102840dbba57SAssar Westerlund 		int	s;
102940dbba57SAssar Westerlund 		struct	msghdr *msg;
103040dbba57SAssar Westerlund 		int	flags;
103140dbba57SAssar Westerlund 	} */ bsd_args;
1032ca26842eSHajimu UMEMOTO 	struct msghdr msg;
103384b11cd8SMitsuru IWASAKI 	struct cmsghdr *cmsg;
103440dbba57SAssar Westerlund 	int error;
103540dbba57SAssar Westerlund 
103640dbba57SAssar Westerlund 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
103740dbba57SAssar Westerlund 		return (error);
103840dbba57SAssar Westerlund 
103940dbba57SAssar Westerlund 	bsd_args.s = linux_args.s;
104040dbba57SAssar Westerlund 	bsd_args.msg = linux_args.msg;
104140dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
1042ca26842eSHajimu UMEMOTO 	error = recvmsg(td, &bsd_args);
1043ca26842eSHajimu UMEMOTO 	if (error)
1044ca26842eSHajimu UMEMOTO 		return (error);
1045ca26842eSHajimu UMEMOTO 
104684b11cd8SMitsuru IWASAKI 	if (bsd_args.msg->msg_control != NULL) {
104784b11cd8SMitsuru IWASAKI 		cmsg = (struct cmsghdr*)bsd_args.msg->msg_control;
104884b11cd8SMitsuru IWASAKI 		cmsg->cmsg_level = bsd_to_linux_sockopt_level(cmsg->cmsg_level);
104984b11cd8SMitsuru IWASAKI 	}
105084b11cd8SMitsuru IWASAKI 
10514b7ef73dSDag-Erling Smørgrav 	error = copyin(linux_args.msg, &msg, sizeof(msg));
1052ca26842eSHajimu UMEMOTO 	if (error)
1053ca26842eSHajimu UMEMOTO 		return (error);
1054ca26842eSHajimu UMEMOTO 	if (msg.msg_name && msg.msg_namelen > 2)
1055ca26842eSHajimu UMEMOTO 		error = linux_sa_put(msg.msg_name);
1056ca26842eSHajimu UMEMOTO 	return (error);
105740dbba57SAssar Westerlund }
105840dbba57SAssar Westerlund 
1059c21dee17SSøren Schmidt struct linux_shutdown_args {
1060c21dee17SSøren Schmidt 	int s;
1061c21dee17SSøren Schmidt 	int how;
1062c21dee17SSøren Schmidt };
1063c21dee17SSøren Schmidt 
1064c21dee17SSøren Schmidt static int
1065b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1066c21dee17SSøren Schmidt {
1067c21dee17SSøren Schmidt 	struct linux_shutdown_args linux_args;
1068ef04503dSPeter Wemm 	struct shutdown_args /* {
1069c21dee17SSøren Schmidt 		int s;
1070c21dee17SSøren Schmidt 		int how;
1071ef04503dSPeter Wemm 	} */ bsd_args;
1072c21dee17SSøren Schmidt 	int error;
1073c21dee17SSøren Schmidt 
10743f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
10753f3a4815SMarcel Moolenaar 		return (error);
10763f3a4815SMarcel Moolenaar 
1077c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1078c21dee17SSøren Schmidt 	bsd_args.how = linux_args.how;
1079b40ce416SJulian Elischer 	return (shutdown(td, &bsd_args));
1080c21dee17SSøren Schmidt }
1081c21dee17SSøren Schmidt 
1082c21dee17SSøren Schmidt struct linux_setsockopt_args {
1083c21dee17SSøren Schmidt 	int s;
1084c21dee17SSøren Schmidt 	int level;
1085c21dee17SSøren Schmidt 	int optname;
1086c21dee17SSøren Schmidt 	void *optval;
1087c21dee17SSøren Schmidt 	int optlen;
1088c21dee17SSøren Schmidt };
1089c21dee17SSøren Schmidt 
1090c21dee17SSøren Schmidt static int
1091b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1092c21dee17SSøren Schmidt {
1093c21dee17SSøren Schmidt 	struct linux_setsockopt_args linux_args;
1094ef04503dSPeter Wemm 	struct setsockopt_args /* {
1095c21dee17SSøren Schmidt 		int s;
1096c21dee17SSøren Schmidt 		int level;
1097c21dee17SSøren Schmidt 		int name;
1098c21dee17SSøren Schmidt 		caddr_t val;
1099c21dee17SSøren Schmidt 		int valsize;
1100ef04503dSPeter Wemm 	} */ bsd_args;
1101c21dee17SSøren Schmidt 	int error, name;
1102c21dee17SSøren Schmidt 
11033f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
11043f3a4815SMarcel Moolenaar 		return (error);
11053f3a4815SMarcel Moolenaar 
1106c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1107c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1108c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1109c21dee17SSøren Schmidt 	case SOL_SOCKET:
1110c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1111c21dee17SSøren Schmidt 		break;
1112c21dee17SSøren Schmidt 	case IPPROTO_IP:
1113c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1114c21dee17SSøren Schmidt 		break;
1115dad3b88aSMike Smith 	case IPPROTO_TCP:
1116dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1117dad3b88aSMike Smith 		name = linux_args.optname;
1118dad3b88aSMike Smith 		break;
1119c21dee17SSøren Schmidt 	default:
11203f3a4815SMarcel Moolenaar 		name = -1;
11213f3a4815SMarcel Moolenaar 		break;
1122c21dee17SSøren Schmidt 	}
1123c21dee17SSøren Schmidt 	if (name == -1)
11243f3a4815SMarcel Moolenaar 		return (EINVAL);
11253f3a4815SMarcel Moolenaar 
1126c21dee17SSøren Schmidt 	bsd_args.name = name;
1127c21dee17SSøren Schmidt 	bsd_args.val = linux_args.optval;
1128c21dee17SSøren Schmidt 	bsd_args.valsize = linux_args.optlen;
1129b40ce416SJulian Elischer 	return (setsockopt(td, &bsd_args));
1130c21dee17SSøren Schmidt }
1131c21dee17SSøren Schmidt 
1132c21dee17SSøren Schmidt struct linux_getsockopt_args {
1133c21dee17SSøren Schmidt 	int s;
1134c21dee17SSøren Schmidt 	int level;
1135c21dee17SSøren Schmidt 	int optname;
1136c21dee17SSøren Schmidt 	void *optval;
1137c21dee17SSøren Schmidt 	int *optlen;
1138c21dee17SSøren Schmidt };
1139c21dee17SSøren Schmidt 
1140c21dee17SSøren Schmidt static int
1141b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1142c21dee17SSøren Schmidt {
1143c21dee17SSøren Schmidt 	struct linux_getsockopt_args linux_args;
1144ef04503dSPeter Wemm 	struct getsockopt_args /* {
1145c21dee17SSøren Schmidt 		int s;
1146c21dee17SSøren Schmidt 		int level;
1147c21dee17SSøren Schmidt 		int name;
1148c21dee17SSøren Schmidt 		caddr_t val;
1149c21dee17SSøren Schmidt 		int *avalsize;
1150ef04503dSPeter Wemm 	} */ bsd_args;
1151c21dee17SSøren Schmidt 	int error, name;
1152c21dee17SSøren Schmidt 
11533f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
11543f3a4815SMarcel Moolenaar 		return (error);
11553f3a4815SMarcel Moolenaar 
1156c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
1157c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
1158c21dee17SSøren Schmidt 	switch (bsd_args.level) {
1159c21dee17SSøren Schmidt 	case SOL_SOCKET:
1160c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
1161c21dee17SSøren Schmidt 		break;
1162c21dee17SSøren Schmidt 	case IPPROTO_IP:
1163c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
1164c21dee17SSøren Schmidt 		break;
1165dad3b88aSMike Smith 	case IPPROTO_TCP:
1166dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
1167dad3b88aSMike Smith 		name = linux_args.optname;
1168dad3b88aSMike Smith 		break;
1169c21dee17SSøren Schmidt 	default:
11703f3a4815SMarcel Moolenaar 		name = -1;
11713f3a4815SMarcel Moolenaar 		break;
1172c21dee17SSøren Schmidt 	}
1173c21dee17SSøren Schmidt 	if (name == -1)
11743f3a4815SMarcel Moolenaar 		return (EINVAL);
11753f3a4815SMarcel Moolenaar 
1176f2477ae1SMike Smith 	bsd_args.name = name;
1177c21dee17SSøren Schmidt 	bsd_args.val = linux_args.optval;
1178c21dee17SSøren Schmidt 	bsd_args.avalsize = linux_args.optlen;
1179b40ce416SJulian Elischer 	return (getsockopt(td, &bsd_args));
1180c21dee17SSøren Schmidt }
1181c21dee17SSøren Schmidt 
1182c21dee17SSøren Schmidt int
1183b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1184c21dee17SSøren Schmidt {
11855002a60fSMarcel Moolenaar 	void *arg = (void *)args->args;
11863f3a4815SMarcel Moolenaar 
1187c21dee17SSøren Schmidt 	switch (args->what) {
1188c21dee17SSøren Schmidt 	case LINUX_SOCKET:
1189b40ce416SJulian Elischer 		return (linux_socket(td, arg));
1190c21dee17SSøren Schmidt 	case LINUX_BIND:
1191b40ce416SJulian Elischer 		return (linux_bind(td, arg));
1192c21dee17SSøren Schmidt 	case LINUX_CONNECT:
1193b40ce416SJulian Elischer 		return (linux_connect(td, arg));
1194c21dee17SSøren Schmidt 	case LINUX_LISTEN:
1195b40ce416SJulian Elischer 		return (linux_listen(td, arg));
1196c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
1197b40ce416SJulian Elischer 		return (linux_accept(td, arg));
1198c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
1199b40ce416SJulian Elischer 		return (linux_getsockname(td, arg));
1200c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
1201b40ce416SJulian Elischer 		return (linux_getpeername(td, arg));
1202c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
1203b40ce416SJulian Elischer 		return (linux_socketpair(td, arg));
1204c21dee17SSøren Schmidt 	case LINUX_SEND:
1205b40ce416SJulian Elischer 		return (linux_send(td, arg));
1206c21dee17SSøren Schmidt 	case LINUX_RECV:
1207b40ce416SJulian Elischer 		return (linux_recv(td, arg));
1208c21dee17SSøren Schmidt 	case LINUX_SENDTO:
1209b40ce416SJulian Elischer 		return (linux_sendto(td, arg));
1210c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
1211b40ce416SJulian Elischer 		return (linux_recvfrom(td, arg));
1212c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
1213b40ce416SJulian Elischer 		return (linux_shutdown(td, arg));
1214c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
1215b40ce416SJulian Elischer 		return (linux_setsockopt(td, arg));
1216c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
1217b40ce416SJulian Elischer 		return (linux_getsockopt(td, arg));
1218e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
1219ca26842eSHajimu UMEMOTO 		return (linux_sendmsg(td, arg));
1220e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
1221b40ce416SJulian Elischer 		return (linux_recvmsg(td, arg));
1222c21dee17SSøren Schmidt 	}
12233f3a4815SMarcel Moolenaar 
12243f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
12253f3a4815SMarcel Moolenaar 	return (ENOSYS);
1226c21dee17SSøren Schmidt }
12275231fb20SDavid E. O'Brien #endif	/*!__alpha__*/
1228