xref: /freebsd/sys/compat/linux/linux_socket.c (revision 044af7c3570a43d06a8fce313448fb3d0351b81d)
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  *
28c3aac50fSPeter Wemm  * $FreeBSD$
29c21dee17SSøren Schmidt  */
30c21dee17SSøren Schmidt 
311f3dad5aSBruce Evans /* XXX we use functions that might not exist. */
325591b823SEivind Eklund #include "opt_compat.h"
335591b823SEivind Eklund 
345591b823SEivind Eklund #ifndef COMPAT_43
355591b823SEivind Eklund #error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
365591b823SEivind Eklund #endif
371f3dad5aSBruce Evans 
38c21dee17SSøren Schmidt #include <sys/param.h>
39f2477ae1SMike Smith #include <sys/proc.h>
40c21dee17SSøren Schmidt #include <sys/systm.h>
411f3dad5aSBruce Evans #include <sys/sysproto.h>
42dad3b88aSMike Smith #include <sys/fcntl.h>
430bf301c0SJonathan Lemon #include <sys/file.h>
44c21dee17SSøren Schmidt #include <sys/socket.h>
450bf301c0SJonathan Lemon #include <sys/socketvar.h>
4608637435SBruce Evans #include <sys/uio.h>
471f3dad5aSBruce Evans 
48c21dee17SSøren Schmidt #include <netinet/in.h>
49f2477ae1SMike Smith #include <netinet/in_systm.h>
50f2477ae1SMike Smith #include <netinet/ip.h>
51c21dee17SSøren Schmidt 
52ac951e62SMarcel Moolenaar #include <machine/../linux/linux.h>
53ebea8660SMarcel Moolenaar #include <machine/../linux/linux_proto.h>
5440dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
55ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
56c21dee17SSøren Schmidt 
574730796cSBill Fenner /*
584730796cSBill Fenner  * FreeBSD's socket calls require the sockaddr struct length to agree
594730796cSBill Fenner  * with the address family.  Linux does not, so we must force it.
604730796cSBill Fenner  */
614730796cSBill Fenner static int
624730796cSBill Fenner linux_to_bsd_namelen(caddr_t name, int namelen)
634730796cSBill Fenner {
644730796cSBill Fenner 	uint16_t	family;	/* XXX must match Linux sockaddr */
654730796cSBill Fenner 
664730796cSBill Fenner 	if (copyin(name, &family, sizeof(family)))
674730796cSBill Fenner 		return namelen;
684730796cSBill Fenner 
694730796cSBill Fenner 	switch (family) {
704730796cSBill Fenner 		case AF_INET:
714730796cSBill Fenner 			return sizeof(struct sockaddr_in);
724730796cSBill Fenner 		case AF_INET6:
734730796cSBill Fenner 			return sizeof(struct sockaddr_in6);
744730796cSBill Fenner 	}
754730796cSBill Fenner 	return namelen;
764730796cSBill Fenner }
774730796cSBill Fenner 
785231fb20SDavid E. O'Brien #ifndef __alpha__
79c21dee17SSøren Schmidt static int
80c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
81c21dee17SSøren Schmidt {
823f3a4815SMarcel Moolenaar 
83c21dee17SSøren Schmidt 	switch (domain) {
84c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
853f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
86c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
873f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
88c21dee17SSøren Schmidt 	case LINUX_AF_INET:
893f3a4815SMarcel Moolenaar 		return (AF_INET);
90c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
913f3a4815SMarcel Moolenaar 		return (AF_CCITT);
92c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
933f3a4815SMarcel Moolenaar 		return (AF_IPX);
94c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
953f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
96c21dee17SSøren Schmidt 	}
973f3a4815SMarcel Moolenaar 	return (-1);
98c21dee17SSøren Schmidt }
99c21dee17SSøren Schmidt 
100c21dee17SSøren Schmidt static int
101c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
102c21dee17SSøren Schmidt {
1033f3a4815SMarcel Moolenaar 
104c21dee17SSøren Schmidt 	switch (level) {
105c21dee17SSøren Schmidt 	case LINUX_SOL_SOCKET:
1063f3a4815SMarcel Moolenaar 		return (SOL_SOCKET);
107c21dee17SSøren Schmidt 	}
1083f3a4815SMarcel Moolenaar 	return (level);
109c21dee17SSøren Schmidt }
110c21dee17SSøren Schmidt 
1113f3a4815SMarcel Moolenaar static int
1123f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
113c21dee17SSøren Schmidt {
1143f3a4815SMarcel Moolenaar 
115c21dee17SSøren Schmidt 	switch (opt) {
116c21dee17SSøren Schmidt 	case LINUX_IP_TOS:
1173f3a4815SMarcel Moolenaar 		return (IP_TOS);
118c21dee17SSøren Schmidt 	case LINUX_IP_TTL:
1193f3a4815SMarcel Moolenaar 		return (IP_TTL);
12066ff6a3cSBill Fenner 	case LINUX_IP_OPTIONS:
1213f3a4815SMarcel Moolenaar 		return (IP_OPTIONS);
12266ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_IF:
1233f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_IF);
12466ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_TTL:
1253f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_TTL);
12666ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_LOOP:
1273f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_LOOP);
12866ff6a3cSBill Fenner 	case LINUX_IP_ADD_MEMBERSHIP:
1293f3a4815SMarcel Moolenaar 		return (IP_ADD_MEMBERSHIP);
13066ff6a3cSBill Fenner 	case LINUX_IP_DROP_MEMBERSHIP:
1313f3a4815SMarcel Moolenaar 		return (IP_DROP_MEMBERSHIP);
13266ff6a3cSBill Fenner 	case LINUX_IP_HDRINCL:
1333f3a4815SMarcel Moolenaar 		return (IP_HDRINCL);
134c21dee17SSøren Schmidt 	}
1353f3a4815SMarcel Moolenaar 	return (-1);
136c21dee17SSøren Schmidt }
137c21dee17SSøren Schmidt 
138c21dee17SSøren Schmidt static int
139c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
140c21dee17SSøren Schmidt {
1413f3a4815SMarcel Moolenaar 
142c21dee17SSøren Schmidt 	switch (opt) {
143c21dee17SSøren Schmidt 	case LINUX_SO_DEBUG:
1443f3a4815SMarcel Moolenaar 		return (SO_DEBUG);
145c21dee17SSøren Schmidt 	case LINUX_SO_REUSEADDR:
1463f3a4815SMarcel Moolenaar 		return (SO_REUSEADDR);
147c21dee17SSøren Schmidt 	case LINUX_SO_TYPE:
1483f3a4815SMarcel Moolenaar 		return (SO_TYPE);
149c21dee17SSøren Schmidt 	case LINUX_SO_ERROR:
1503f3a4815SMarcel Moolenaar 		return (SO_ERROR);
151c21dee17SSøren Schmidt 	case LINUX_SO_DONTROUTE:
1523f3a4815SMarcel Moolenaar 		return (SO_DONTROUTE);
153c21dee17SSøren Schmidt 	case LINUX_SO_BROADCAST:
1543f3a4815SMarcel Moolenaar 		return (SO_BROADCAST);
155c21dee17SSøren Schmidt 	case LINUX_SO_SNDBUF:
1563f3a4815SMarcel Moolenaar 		return (SO_SNDBUF);
157c21dee17SSøren Schmidt 	case LINUX_SO_RCVBUF:
1583f3a4815SMarcel Moolenaar 		return (SO_RCVBUF);
159c21dee17SSøren Schmidt 	case LINUX_SO_KEEPALIVE:
1603f3a4815SMarcel Moolenaar 		return (SO_KEEPALIVE);
161c21dee17SSøren Schmidt 	case LINUX_SO_OOBINLINE:
1623f3a4815SMarcel Moolenaar 		return (SO_OOBINLINE);
163c21dee17SSøren Schmidt 	case LINUX_SO_LINGER:
1643f3a4815SMarcel Moolenaar 		return (SO_LINGER);
165c21dee17SSøren Schmidt 	}
1663f3a4815SMarcel Moolenaar 	return (-1);
167c21dee17SSøren Schmidt }
168c21dee17SSøren Schmidt 
16940dbba57SAssar Westerlund static int
17040dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
17140dbba57SAssar Westerlund {
17240dbba57SAssar Westerlund 	int ret_flags = 0;
17340dbba57SAssar Westerlund 
17440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
17540dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
17640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
17740dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
17840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
17940dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
18040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
18140dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
18240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
18340dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
18440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
18540dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
18640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
18740dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
18840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
18940dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
19040dbba57SAssar Westerlund #if 0 /* not handled */
19140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
19240dbba57SAssar Westerlund 		;
19340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
19440dbba57SAssar Westerlund 		;
19540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
19640dbba57SAssar Westerlund 		;
19740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
19840dbba57SAssar Westerlund 		;
19940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
20040dbba57SAssar Westerlund 		;
20140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
20240dbba57SAssar Westerlund 		;
20340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_NOSIGNAL)
20440dbba57SAssar Westerlund 		;
20540dbba57SAssar Westerlund #endif
20640dbba57SAssar Westerlund 	return ret_flags;
20740dbba57SAssar Westerlund }
20840dbba57SAssar Westerlund 
2093f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
210f2477ae1SMike Smith static int
211b40ce416SJulian Elischer linux_check_hdrincl(struct thread *td, int s)
212f2477ae1SMike Smith {
213f2477ae1SMike Smith 	struct getsockopt_args /* {
214f2477ae1SMike Smith 		int s;
215f2477ae1SMike Smith 		int level;
216f2477ae1SMike Smith 		int name;
217f2477ae1SMike Smith 		caddr_t val;
218f2477ae1SMike Smith 		int *avalsize;
219f2477ae1SMike Smith 	} */ bsd_args;
220f2477ae1SMike Smith 	int error;
221f2477ae1SMike Smith 	caddr_t sg, val, valsize;
222f2477ae1SMike Smith 	int size_val = sizeof val;
223f2477ae1SMike Smith 	int optval;
224f2477ae1SMike Smith 
225f2477ae1SMike Smith 	sg = stackgap_init();
226f2477ae1SMike Smith 	val = stackgap_alloc(&sg, sizeof(int));
227f2477ae1SMike Smith 	valsize = stackgap_alloc(&sg, sizeof(int));
228f2477ae1SMike Smith 
229f2477ae1SMike Smith 	if ((error = copyout(&size_val, valsize, sizeof(size_val))))
2303f3a4815SMarcel Moolenaar 		return (error);
2313f3a4815SMarcel Moolenaar 
232f2477ae1SMike Smith 	bsd_args.s = s;
233f2477ae1SMike Smith 	bsd_args.level = IPPROTO_IP;
234f2477ae1SMike Smith 	bsd_args.name = IP_HDRINCL;
235f2477ae1SMike Smith 	bsd_args.val = val;
236f2477ae1SMike Smith 	bsd_args.avalsize = (int *)valsize;
237b40ce416SJulian Elischer 	if ((error = getsockopt(td, &bsd_args)))
2383f3a4815SMarcel Moolenaar 		return (error);
2393f3a4815SMarcel Moolenaar 
240f2477ae1SMike Smith 	if ((error = copyin(val, &optval, sizeof(optval))))
2413f3a4815SMarcel Moolenaar 		return (error);
2423f3a4815SMarcel Moolenaar 
2433f3a4815SMarcel Moolenaar 	return (optval == 0);
244f2477ae1SMike Smith }
245f2477ae1SMike Smith 
246f2477ae1SMike Smith /*
247f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
248f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
249f2477ae1SMike Smith  */
250f2477ae1SMike Smith static int
251b40ce416SJulian Elischer linux_sendto_hdrincl(struct thread *td, struct sendto_args *bsd_args)
252f2477ae1SMike Smith {
253f2477ae1SMike Smith /*
254f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
255f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
256f2477ae1SMike Smith  * It should include all the fields we modify (ip_len and ip_off)
257f2477ae1SMike Smith  * and be as small as possible to minimize copying overhead.
258f2477ae1SMike Smith  */
259f2477ae1SMike Smith #define linux_ip_copysize	8
260f2477ae1SMike Smith 
261f2477ae1SMike Smith 	caddr_t sg;
262f2477ae1SMike Smith 	struct ip *packet;
263f2477ae1SMike Smith 	struct msghdr *msg;
264f2477ae1SMike Smith 	struct iovec *iov;
265f2477ae1SMike Smith 
266f2477ae1SMike Smith 	int error;
267f2477ae1SMike Smith 	struct  sendmsg_args /* {
268f2477ae1SMike Smith 		int s;
269f2477ae1SMike Smith 		caddr_t msg;
270f2477ae1SMike Smith 		int flags;
271f2477ae1SMike Smith 	} */ sendmsg_args;
272f2477ae1SMike Smith 
273f2477ae1SMike Smith 	/* Check the packet isn't too small before we mess with it */
274f2477ae1SMike Smith 	if (bsd_args->len < linux_ip_copysize)
2753f3a4815SMarcel Moolenaar 		return (EINVAL);
276f2477ae1SMike Smith 
277f2477ae1SMike Smith 	/*
278f2477ae1SMike Smith 	 * Tweaking the user buffer in place would be bad manners.
279f2477ae1SMike Smith 	 * We create a corrected IP header with just the needed length,
280f2477ae1SMike Smith 	 * then use an iovec to glue it to the rest of the user packet
281f2477ae1SMike Smith 	 * when calling sendmsg().
282f2477ae1SMike Smith 	 */
283f2477ae1SMike Smith 	sg = stackgap_init();
284f2477ae1SMike Smith 	packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
285f2477ae1SMike Smith 	msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
286f2477ae1SMike Smith 	iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
287f2477ae1SMike Smith 
288f2477ae1SMike Smith 	/* Make a copy of the beginning of the packet to be sent */
2893f3a4815SMarcel Moolenaar 	if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize)))
2903f3a4815SMarcel Moolenaar 		return (error);
291f2477ae1SMike Smith 
292f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
293f2477ae1SMike Smith 	packet->ip_len = bsd_args->len;
294f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
295f2477ae1SMike Smith 
296f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
297f2477ae1SMike Smith 	msg->msg_name = bsd_args->to;
298f2477ae1SMike Smith 	msg->msg_namelen = bsd_args->tolen;
299f2477ae1SMike Smith 	msg->msg_iov = iov;
300f2477ae1SMike Smith 	msg->msg_iovlen = 2;
301f2477ae1SMike Smith 	msg->msg_control = NULL;
302f2477ae1SMike Smith 	msg->msg_controllen = 0;
303f2477ae1SMike Smith 	msg->msg_flags = 0;
304f2477ae1SMike Smith 	iov[0].iov_base = (char *)packet;
305f2477ae1SMike Smith 	iov[0].iov_len = linux_ip_copysize;
306f2477ae1SMike Smith 	iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
307f2477ae1SMike Smith 	iov[1].iov_len = bsd_args->len - linux_ip_copysize;
308f2477ae1SMike Smith 
309f2477ae1SMike Smith 	sendmsg_args.s = bsd_args->s;
310f2477ae1SMike Smith 	sendmsg_args.msg = (caddr_t)msg;
311f2477ae1SMike Smith 	sendmsg_args.flags = bsd_args->flags;
312b40ce416SJulian Elischer 	return (sendmsg(td, &sendmsg_args));
313f2477ae1SMike Smith }
314f2477ae1SMike Smith 
315c21dee17SSøren Schmidt struct linux_socket_args {
316c21dee17SSøren Schmidt 	int domain;
317c21dee17SSøren Schmidt 	int type;
318c21dee17SSøren Schmidt 	int protocol;
319c21dee17SSøren Schmidt };
320c21dee17SSøren Schmidt 
321c21dee17SSøren Schmidt static int
322b40ce416SJulian Elischer linux_socket(struct thread *td, struct linux_socket_args *args)
323c21dee17SSøren Schmidt {
324c21dee17SSøren Schmidt 	struct linux_socket_args linux_args;
325ef04503dSPeter Wemm 	struct socket_args /* {
326c21dee17SSøren Schmidt 		int domain;
327c21dee17SSøren Schmidt 		int type;
328c21dee17SSøren Schmidt 		int protocol;
329ef04503dSPeter Wemm 	} */ bsd_args;
330c21dee17SSøren Schmidt 	int error;
331f2477ae1SMike Smith 	int retval_socket;
332c21dee17SSøren Schmidt 
3333f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
3343f3a4815SMarcel Moolenaar 		return (error);
3353f3a4815SMarcel Moolenaar 
336c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
337c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
338c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
339c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
3403f3a4815SMarcel Moolenaar 		return (EINVAL);
341f2477ae1SMike Smith 
342b40ce416SJulian Elischer 	retval_socket = socket(td, &bsd_args);
343f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
344f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
345f2477ae1SMike Smith 	    && bsd_args.domain == AF_INET
346f2477ae1SMike Smith 	    && retval_socket >= 0) {
347f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
348f2477ae1SMike Smith 		struct setsockopt_args /* {
349f2477ae1SMike Smith 			int s;
350f2477ae1SMike Smith 			int level;
351f2477ae1SMike Smith 			int name;
352f2477ae1SMike Smith 			caddr_t val;
353f2477ae1SMike Smith 			int valsize;
354f2477ae1SMike Smith 		} */ bsd_setsockopt_args;
355f2477ae1SMike Smith 		caddr_t sg;
356f2477ae1SMike Smith 		int *hdrincl;
357f2477ae1SMike Smith 
358f2477ae1SMike Smith 		sg = stackgap_init();
359f2477ae1SMike Smith 		hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
360f2477ae1SMike Smith 		*hdrincl = 1;
361b40ce416SJulian Elischer 		bsd_setsockopt_args.s = td->td_retval[0];
362f2477ae1SMike Smith 		bsd_setsockopt_args.level = IPPROTO_IP;
363f2477ae1SMike Smith 		bsd_setsockopt_args.name = IP_HDRINCL;
364f2477ae1SMike Smith 		bsd_setsockopt_args.val = (caddr_t)hdrincl;
365f2477ae1SMike Smith 		bsd_setsockopt_args.valsize = sizeof(*hdrincl);
366f2477ae1SMike Smith 		/* We ignore any error returned by setsockopt() */
367b40ce416SJulian Elischer 		setsockopt(td, &bsd_setsockopt_args);
368f2477ae1SMike Smith 		/* Copy back the return value from socket() */
369b40ce416SJulian Elischer 		td->td_retval[0] = bsd_setsockopt_args.s;
370f2477ae1SMike Smith 	}
3713f3a4815SMarcel Moolenaar 
3723f3a4815SMarcel Moolenaar 	return (retval_socket);
373c21dee17SSøren Schmidt }
374c21dee17SSøren Schmidt 
375c21dee17SSøren Schmidt struct linux_bind_args {
376c21dee17SSøren Schmidt 	int s;
377c21dee17SSøren Schmidt 	struct sockaddr *name;
378c21dee17SSøren Schmidt 	int namelen;
379c21dee17SSøren Schmidt };
380c21dee17SSøren Schmidt 
381c21dee17SSøren Schmidt static int
382b40ce416SJulian Elischer linux_bind(struct thread *td, struct linux_bind_args *args)
383c21dee17SSøren Schmidt {
384c21dee17SSøren Schmidt 	struct linux_bind_args linux_args;
385ef04503dSPeter Wemm 	struct bind_args /* {
386c21dee17SSøren Schmidt 		int s;
387c21dee17SSøren Schmidt 		caddr_t name;
388c21dee17SSøren Schmidt 		int namelen;
389ef04503dSPeter Wemm 	} */ bsd_args;
390c21dee17SSøren Schmidt 	int error;
391c21dee17SSøren Schmidt 
3923f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
3933f3a4815SMarcel Moolenaar 		return (error);
3943f3a4815SMarcel Moolenaar 
395c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
396c21dee17SSøren Schmidt 	bsd_args.name = (caddr_t)linux_args.name;
3974730796cSBill Fenner 	bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name, linux_args.namelen);
398b40ce416SJulian Elischer 	return (bind(td, &bsd_args));
399c21dee17SSøren Schmidt }
400c21dee17SSøren Schmidt 
401c21dee17SSøren Schmidt struct linux_connect_args {
402c21dee17SSøren Schmidt 	int s;
403c21dee17SSøren Schmidt 	struct sockaddr * name;
404c21dee17SSøren Schmidt 	int namelen;
405c21dee17SSøren Schmidt };
406b40ce416SJulian Elischer int linux_connect(struct thread *, struct linux_connect_args *);
407930a65feSAndrew Gallatin #endif /* !__alpha__*/
408c21dee17SSøren Schmidt 
409930a65feSAndrew Gallatin int
410b40ce416SJulian Elischer linux_connect(struct thread *td, struct linux_connect_args *args)
411c21dee17SSøren Schmidt {
412c21dee17SSøren Schmidt 	struct linux_connect_args linux_args;
413ef04503dSPeter Wemm 	struct connect_args /* {
414c21dee17SSøren Schmidt 		int s;
415c21dee17SSøren Schmidt 		caddr_t name;
416c21dee17SSøren Schmidt 		int namelen;
417ef04503dSPeter Wemm 	} */ bsd_args;
4180bf301c0SJonathan Lemon 	struct socket *so;
41939c95b83SMatthew Dillon 	u_int fflag;
420c21dee17SSøren Schmidt 	int error;
421c21dee17SSøren Schmidt 
422930a65feSAndrew Gallatin #ifdef __alpha__
423930a65feSAndrew Gallatin 	bcopy(args, &linux_args, sizeof(linux_args));
424930a65feSAndrew Gallatin #else
4253f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
4263f3a4815SMarcel Moolenaar 		return (error);
427930a65feSAndrew Gallatin #endif /* __alpha__ */
4283f3a4815SMarcel Moolenaar 
429c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
430c21dee17SSøren Schmidt 	bsd_args.name = (caddr_t)linux_args.name;
4314730796cSBill Fenner 	bsd_args.namelen = linux_to_bsd_namelen(bsd_args.name, linux_args.namelen);
432b40ce416SJulian Elischer 	error = connect(td, &bsd_args);
4330bf301c0SJonathan Lemon 	if (error != EISCONN)
4340bf301c0SJonathan Lemon 		return (error);
4350bf301c0SJonathan Lemon 
436dad3b88aSMike Smith 	/*
437dad3b88aSMike Smith 	 * Linux doesn't return EISCONN the first time it occurs,
438dad3b88aSMike Smith 	 * when on a non-blocking socket. Instead it returns the
439dad3b88aSMike Smith 	 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
440dad3b88aSMike Smith 	 */
44139c95b83SMatthew Dillon 	if ((error = fgetsock(td, linux_args.s, &so, &fflag)) != 0)
4423f3a4815SMarcel Moolenaar 		return(error);
4430bf301c0SJonathan Lemon 	error = EISCONN;
44439c95b83SMatthew Dillon 	if (fflag & FNONBLOCK) {
4455002a60fSMarcel Moolenaar 		if (so->so_emuldata == 0)
4460bf301c0SJonathan Lemon 			error = so->so_error;
4470bf301c0SJonathan Lemon 		so->so_emuldata = (void *)1;
448dad3b88aSMike Smith 	}
44939c95b83SMatthew Dillon 	fputsock(so);
4503f3a4815SMarcel Moolenaar 	return (error);
451c21dee17SSøren Schmidt }
452c21dee17SSøren Schmidt 
453930a65feSAndrew Gallatin #ifndef __alpha__
454930a65feSAndrew Gallatin 
455c21dee17SSøren Schmidt struct linux_listen_args {
456c21dee17SSøren Schmidt 	int s;
457c21dee17SSøren Schmidt 	int backlog;
458c21dee17SSøren Schmidt };
459c21dee17SSøren Schmidt 
460c21dee17SSøren Schmidt static int
461b40ce416SJulian Elischer linux_listen(struct thread *td, struct linux_listen_args *args)
462c21dee17SSøren Schmidt {
463c21dee17SSøren Schmidt 	struct linux_listen_args linux_args;
464ef04503dSPeter Wemm 	struct listen_args /* {
465c21dee17SSøren Schmidt 		int s;
466c21dee17SSøren Schmidt 		int backlog;
467ef04503dSPeter Wemm 	} */ bsd_args;
468c21dee17SSøren Schmidt 	int error;
469c21dee17SSøren Schmidt 
4703f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
4713f3a4815SMarcel Moolenaar 		return (error);
4723f3a4815SMarcel Moolenaar 
473c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
474c21dee17SSøren Schmidt 	bsd_args.backlog = linux_args.backlog;
475b40ce416SJulian Elischer 	return (listen(td, &bsd_args));
476c21dee17SSøren Schmidt }
477c21dee17SSøren Schmidt 
478c21dee17SSøren Schmidt struct linux_accept_args {
479c21dee17SSøren Schmidt 	int s;
480c21dee17SSøren Schmidt 	struct sockaddr *addr;
481c21dee17SSøren Schmidt 	int *namelen;
482c21dee17SSøren Schmidt };
483c21dee17SSøren Schmidt 
484c21dee17SSøren Schmidt static int
485b40ce416SJulian Elischer linux_accept(struct thread *td, struct linux_accept_args *args)
486c21dee17SSøren Schmidt {
487c21dee17SSøren Schmidt 	struct linux_accept_args linux_args;
488ef04503dSPeter Wemm 	struct accept_args /* {
489c21dee17SSøren Schmidt 		int s;
490c21dee17SSøren Schmidt 		caddr_t name;
491c21dee17SSøren Schmidt 		int *anamelen;
492ef04503dSPeter Wemm 	} */ bsd_args;
493dba5ab66SMarcel Moolenaar 	struct fcntl_args /* {
494dba5ab66SMarcel Moolenaar 		int fd;
495dba5ab66SMarcel Moolenaar 		int cmd;
496dba5ab66SMarcel Moolenaar 		long arg;
497dba5ab66SMarcel Moolenaar 	} */ f_args;
498c21dee17SSøren Schmidt 	int error;
499c21dee17SSøren Schmidt 
5003f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5013f3a4815SMarcel Moolenaar 		return (error);
5023f3a4815SMarcel Moolenaar 
503c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
504c21dee17SSøren Schmidt 	bsd_args.name = (caddr_t)linux_args.addr;
505c21dee17SSøren Schmidt 	bsd_args.anamelen = linux_args.namelen;
506044af7c3SJonathan Mini 	error = oaccept(td, &bsd_args);
507dba5ab66SMarcel Moolenaar 	if (error)
508dba5ab66SMarcel Moolenaar 		return (error);
509dba5ab66SMarcel Moolenaar 
510dba5ab66SMarcel Moolenaar 	/*
511dba5ab66SMarcel Moolenaar 	 * linux appears not to copy flags from the parent socket to the
512dba5ab66SMarcel Moolenaar 	 * accepted one, so we must clear the flags in the new descriptor.
513dba5ab66SMarcel Moolenaar 	 * Ignore any errors, because we already have an open fd.
514dba5ab66SMarcel Moolenaar 	 */
515b40ce416SJulian Elischer 	f_args.fd = td->td_retval[0];
516dba5ab66SMarcel Moolenaar 	f_args.cmd = F_SETFL;
517dba5ab66SMarcel Moolenaar 	f_args.arg = 0;
518b40ce416SJulian Elischer 	(void)fcntl(td, &f_args);
519b40ce416SJulian Elischer 	td->td_retval[0] = f_args.fd;
520dba5ab66SMarcel Moolenaar 	return (0);
521c21dee17SSøren Schmidt }
522c21dee17SSøren Schmidt 
523c21dee17SSøren Schmidt struct linux_getsockname_args {
524c21dee17SSøren Schmidt 	int s;
525c21dee17SSøren Schmidt 	struct sockaddr *addr;
526c21dee17SSøren Schmidt 	int *namelen;
527c21dee17SSøren Schmidt };
528c21dee17SSøren Schmidt 
529c21dee17SSøren Schmidt static int
530b40ce416SJulian Elischer linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
531c21dee17SSøren Schmidt {
532c21dee17SSøren Schmidt 	struct linux_getsockname_args linux_args;
533ef04503dSPeter Wemm 	struct getsockname_args /* {
534c21dee17SSøren Schmidt 		int fdes;
535c21dee17SSøren Schmidt 		caddr_t asa;
536c21dee17SSøren Schmidt 		int *alen;
537ef04503dSPeter Wemm 	} */ bsd_args;
538c21dee17SSøren Schmidt 	int error;
539c21dee17SSøren Schmidt 
5403f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5413f3a4815SMarcel Moolenaar 		return (error);
5423f3a4815SMarcel Moolenaar 
543c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
544c21dee17SSøren Schmidt 	bsd_args.asa = (caddr_t) linux_args.addr;
545c21dee17SSøren Schmidt 	bsd_args.alen = linux_args.namelen;
546044af7c3SJonathan Mini 	return (ogetsockname(td, &bsd_args));
547c21dee17SSøren Schmidt }
548c21dee17SSøren Schmidt 
549c21dee17SSøren Schmidt struct linux_getpeername_args {
550c21dee17SSøren Schmidt 	int s;
551c21dee17SSøren Schmidt 	struct sockaddr *addr;
552c21dee17SSøren Schmidt 	int *namelen;
553c21dee17SSøren Schmidt };
554c21dee17SSøren Schmidt 
555c21dee17SSøren Schmidt static int
556b40ce416SJulian Elischer linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
557c21dee17SSøren Schmidt {
558c21dee17SSøren Schmidt 	struct linux_getpeername_args linux_args;
559044af7c3SJonathan Mini 	struct ogetpeername_args /* {
560c21dee17SSøren Schmidt 		int fdes;
561c21dee17SSøren Schmidt 		caddr_t asa;
562c21dee17SSøren Schmidt 		int *alen;
563ef04503dSPeter Wemm 	} */ bsd_args;
564c21dee17SSøren Schmidt 	int error;
565c21dee17SSøren Schmidt 
5663f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5673f3a4815SMarcel Moolenaar 		return (error);
5683f3a4815SMarcel Moolenaar 
569c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
570c21dee17SSøren Schmidt 	bsd_args.asa = (caddr_t) linux_args.addr;
571c21dee17SSøren Schmidt 	bsd_args.alen = linux_args.namelen;
572044af7c3SJonathan Mini 	return (ogetpeername(td, &bsd_args));
573c21dee17SSøren Schmidt }
574c21dee17SSøren Schmidt 
575c21dee17SSøren Schmidt struct linux_socketpair_args {
576c21dee17SSøren Schmidt 	int domain;
577c21dee17SSøren Schmidt 	int type;
578c21dee17SSøren Schmidt 	int protocol;
579c21dee17SSøren Schmidt 	int *rsv;
580c21dee17SSøren Schmidt };
581c21dee17SSøren Schmidt 
582c21dee17SSøren Schmidt static int
583b40ce416SJulian Elischer linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
584c21dee17SSøren Schmidt {
585c21dee17SSøren Schmidt 	struct linux_socketpair_args linux_args;
586ef04503dSPeter Wemm 	struct socketpair_args /* {
587c21dee17SSøren Schmidt 		int domain;
588c21dee17SSøren Schmidt 		int type;
589c21dee17SSøren Schmidt 		int protocol;
590c21dee17SSøren Schmidt 		int *rsv;
591ef04503dSPeter Wemm 	} */ bsd_args;
592c21dee17SSøren Schmidt 	int error;
593c21dee17SSøren Schmidt 
5943f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5953f3a4815SMarcel Moolenaar 		return (error);
5963f3a4815SMarcel Moolenaar 
597c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
598c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
5993f3a4815SMarcel Moolenaar 		return (EINVAL);
6003f3a4815SMarcel Moolenaar 
601c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
602c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
603c21dee17SSøren Schmidt 	bsd_args.rsv = linux_args.rsv;
604b40ce416SJulian Elischer 	return (socketpair(td, &bsd_args));
605c21dee17SSøren Schmidt }
606c21dee17SSøren Schmidt 
607c21dee17SSøren Schmidt struct linux_send_args {
608c21dee17SSøren Schmidt 	int s;
609c21dee17SSøren Schmidt 	void *msg;
610c21dee17SSøren Schmidt 	int len;
611c21dee17SSøren Schmidt 	int flags;
612c21dee17SSøren Schmidt };
613c21dee17SSøren Schmidt 
614c21dee17SSøren Schmidt static int
615b40ce416SJulian Elischer linux_send(struct thread *td, struct linux_send_args *args)
616c21dee17SSøren Schmidt {
617c21dee17SSøren Schmidt 	struct linux_send_args linux_args;
618044af7c3SJonathan Mini 	struct osend_args /* {
619c21dee17SSøren Schmidt 		int s;
620c21dee17SSøren Schmidt 		caddr_t buf;
621044af7c3SJonathan Mini 		int len;
622c21dee17SSøren Schmidt 		int flags;
623ef04503dSPeter Wemm 	} */ bsd_args;
624c21dee17SSøren Schmidt 	int error;
625c21dee17SSøren Schmidt 
6263f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6273f3a4815SMarcel Moolenaar 		return (error);
6283f3a4815SMarcel Moolenaar 
629c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
630c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.msg;
631c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
632c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
633044af7c3SJonathan Mini 	return (osend(td, &bsd_args));
634c21dee17SSøren Schmidt }
635c21dee17SSøren Schmidt 
636c21dee17SSøren Schmidt struct linux_recv_args {
637c21dee17SSøren Schmidt 	int s;
638c21dee17SSøren Schmidt 	void *msg;
639c21dee17SSøren Schmidt 	int len;
640c21dee17SSøren Schmidt 	int flags;
641c21dee17SSøren Schmidt };
642c21dee17SSøren Schmidt 
643c21dee17SSøren Schmidt static int
644b40ce416SJulian Elischer linux_recv(struct thread *td, struct linux_recv_args *args)
645c21dee17SSøren Schmidt {
646c21dee17SSøren Schmidt 	struct linux_recv_args linux_args;
647044af7c3SJonathan Mini 	struct orecv_args /* {
648c21dee17SSøren Schmidt 		int s;
649c21dee17SSøren Schmidt 		caddr_t buf;
650c21dee17SSøren Schmidt 		int len;
651c21dee17SSøren Schmidt 		int flags;
652ef04503dSPeter Wemm 	} */ bsd_args;
653c21dee17SSøren Schmidt 	int error;
654c21dee17SSøren Schmidt 
6553f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6563f3a4815SMarcel Moolenaar 		return (error);
6573f3a4815SMarcel Moolenaar 
658c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
659c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.msg;
660c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
661c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
662044af7c3SJonathan Mini 	return (orecv(td, &bsd_args));
663c21dee17SSøren Schmidt }
664c21dee17SSøren Schmidt 
665c21dee17SSøren Schmidt struct linux_sendto_args {
666c21dee17SSøren Schmidt 	int s;
667c21dee17SSøren Schmidt 	void *msg;
668c21dee17SSøren Schmidt 	int len;
669c21dee17SSøren Schmidt 	int flags;
670c21dee17SSøren Schmidt 	caddr_t to;
671c21dee17SSøren Schmidt 	int tolen;
672c21dee17SSøren Schmidt };
673c21dee17SSøren Schmidt 
674c21dee17SSøren Schmidt static int
675b40ce416SJulian Elischer linux_sendto(struct thread *td, struct linux_sendto_args *args)
676c21dee17SSøren Schmidt {
677c21dee17SSøren Schmidt 	struct linux_sendto_args linux_args;
678ef04503dSPeter Wemm 	struct sendto_args /* {
679c21dee17SSøren Schmidt 		int s;
680c21dee17SSøren Schmidt 		caddr_t buf;
681c21dee17SSøren Schmidt 		size_t len;
682c21dee17SSøren Schmidt 		int flags;
683c21dee17SSøren Schmidt 		caddr_t to;
684c21dee17SSøren Schmidt 		int tolen;
685ef04503dSPeter Wemm 	} */ bsd_args;
686c21dee17SSøren Schmidt 	int error;
687c21dee17SSøren Schmidt 
6883f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6893f3a4815SMarcel Moolenaar 		return (error);
6903f3a4815SMarcel Moolenaar 
691c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
692c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.msg;
693c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
694c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
695c21dee17SSøren Schmidt 	bsd_args.to = linux_args.to;
696c21dee17SSøren Schmidt 	bsd_args.tolen = linux_args.tolen;
697f2477ae1SMike Smith 
698b40ce416SJulian Elischer 	if (linux_check_hdrincl(td, linux_args.s) == 0)
699f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
700b40ce416SJulian Elischer 		return (linux_sendto_hdrincl(td, &bsd_args));
701f2477ae1SMike Smith 
702b40ce416SJulian Elischer 	return (sendto(td, &bsd_args));
703c21dee17SSøren Schmidt }
704c21dee17SSøren Schmidt 
705c21dee17SSøren Schmidt struct linux_recvfrom_args {
706c21dee17SSøren Schmidt 	int s;
707c21dee17SSøren Schmidt 	void *buf;
708c21dee17SSøren Schmidt 	int len;
709c21dee17SSøren Schmidt 	int flags;
710c21dee17SSøren Schmidt 	caddr_t from;
711c21dee17SSøren Schmidt 	int *fromlen;
712c21dee17SSøren Schmidt };
713c21dee17SSøren Schmidt 
714c21dee17SSøren Schmidt static int
715b40ce416SJulian Elischer linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
716c21dee17SSøren Schmidt {
717c21dee17SSøren Schmidt 	struct linux_recvfrom_args linux_args;
718ef04503dSPeter Wemm 	struct recvfrom_args /* {
719c21dee17SSøren Schmidt 		int s;
720c21dee17SSøren Schmidt 		caddr_t buf;
721c21dee17SSøren Schmidt 		size_t len;
722c21dee17SSøren Schmidt 		int flags;
723c21dee17SSøren Schmidt 		caddr_t from;
724c21dee17SSøren Schmidt 		int *fromlenaddr;
725ef04503dSPeter Wemm 	} */ bsd_args;
726c21dee17SSøren Schmidt 	int error;
727c21dee17SSøren Schmidt 
7283f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7293f3a4815SMarcel Moolenaar 		return (error);
7303f3a4815SMarcel Moolenaar 
731c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
732c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.buf;
733c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
73440dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
735c21dee17SSøren Schmidt 	bsd_args.from = linux_args.from;
736c21dee17SSøren Schmidt 	bsd_args.fromlenaddr = linux_args.fromlen;
737044af7c3SJonathan Mini 	return (orecvfrom(td, &bsd_args));
738c21dee17SSøren Schmidt }
739c21dee17SSøren Schmidt 
74040dbba57SAssar Westerlund struct linux_recvmsg_args {
74140dbba57SAssar Westerlund 	int s;
74240dbba57SAssar Westerlund 	struct msghdr *msg;
74340dbba57SAssar Westerlund 	int flags;
74440dbba57SAssar Westerlund };
74540dbba57SAssar Westerlund 
74640dbba57SAssar Westerlund static int
747b40ce416SJulian Elischer linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
74840dbba57SAssar Westerlund {
74940dbba57SAssar Westerlund 	struct linux_recvmsg_args linux_args;
75040dbba57SAssar Westerlund 	struct recvmsg_args /* {
75140dbba57SAssar Westerlund 		int	s;
75240dbba57SAssar Westerlund 		struct	msghdr *msg;
75340dbba57SAssar Westerlund 		int	flags;
75440dbba57SAssar Westerlund 	} */ bsd_args;
75540dbba57SAssar Westerlund 	int error;
75640dbba57SAssar Westerlund 
75740dbba57SAssar Westerlund 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
75840dbba57SAssar Westerlund 		return (error);
75940dbba57SAssar Westerlund 
76040dbba57SAssar Westerlund 	bsd_args.s = linux_args.s;
76140dbba57SAssar Westerlund 	bsd_args.msg = linux_args.msg;
76240dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
763b40ce416SJulian Elischer 	return (recvmsg(td, &bsd_args));
76440dbba57SAssar Westerlund }
76540dbba57SAssar Westerlund 
766c21dee17SSøren Schmidt struct linux_shutdown_args {
767c21dee17SSøren Schmidt 	int s;
768c21dee17SSøren Schmidt 	int how;
769c21dee17SSøren Schmidt };
770c21dee17SSøren Schmidt 
771c21dee17SSøren Schmidt static int
772b40ce416SJulian Elischer linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
773c21dee17SSøren Schmidt {
774c21dee17SSøren Schmidt 	struct linux_shutdown_args linux_args;
775ef04503dSPeter Wemm 	struct shutdown_args /* {
776c21dee17SSøren Schmidt 		int s;
777c21dee17SSøren Schmidt 		int how;
778ef04503dSPeter Wemm 	} */ bsd_args;
779c21dee17SSøren Schmidt 	int error;
780c21dee17SSøren Schmidt 
7813f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7823f3a4815SMarcel Moolenaar 		return (error);
7833f3a4815SMarcel Moolenaar 
784c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
785c21dee17SSøren Schmidt 	bsd_args.how = linux_args.how;
786b40ce416SJulian Elischer 	return (shutdown(td, &bsd_args));
787c21dee17SSøren Schmidt }
788c21dee17SSøren Schmidt 
789c21dee17SSøren Schmidt struct linux_setsockopt_args {
790c21dee17SSøren Schmidt 	int s;
791c21dee17SSøren Schmidt 	int level;
792c21dee17SSøren Schmidt 	int optname;
793c21dee17SSøren Schmidt 	void *optval;
794c21dee17SSøren Schmidt 	int optlen;
795c21dee17SSøren Schmidt };
796c21dee17SSøren Schmidt 
797c21dee17SSøren Schmidt static int
798b40ce416SJulian Elischer linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
799c21dee17SSøren Schmidt {
800c21dee17SSøren Schmidt 	struct linux_setsockopt_args linux_args;
801ef04503dSPeter Wemm 	struct setsockopt_args /* {
802c21dee17SSøren Schmidt 		int s;
803c21dee17SSøren Schmidt 		int level;
804c21dee17SSøren Schmidt 		int name;
805c21dee17SSøren Schmidt 		caddr_t val;
806c21dee17SSøren Schmidt 		int valsize;
807ef04503dSPeter Wemm 	} */ bsd_args;
808c21dee17SSøren Schmidt 	int error, name;
809c21dee17SSøren Schmidt 
8103f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8113f3a4815SMarcel Moolenaar 		return (error);
8123f3a4815SMarcel Moolenaar 
813c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
814c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
815c21dee17SSøren Schmidt 	switch (bsd_args.level) {
816c21dee17SSøren Schmidt 	case SOL_SOCKET:
817c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
818c21dee17SSøren Schmidt 		break;
819c21dee17SSøren Schmidt 	case IPPROTO_IP:
820c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
821c21dee17SSøren Schmidt 		break;
822dad3b88aSMike Smith 	case IPPROTO_TCP:
823dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
824dad3b88aSMike Smith 		name = linux_args.optname;
825dad3b88aSMike Smith 		break;
826c21dee17SSøren Schmidt 	default:
8273f3a4815SMarcel Moolenaar 		name = -1;
8283f3a4815SMarcel Moolenaar 		break;
829c21dee17SSøren Schmidt 	}
830c21dee17SSøren Schmidt 	if (name == -1)
8313f3a4815SMarcel Moolenaar 		return (EINVAL);
8323f3a4815SMarcel Moolenaar 
833c21dee17SSøren Schmidt 	bsd_args.name = name;
834c21dee17SSøren Schmidt 	bsd_args.val = linux_args.optval;
835c21dee17SSøren Schmidt 	bsd_args.valsize = linux_args.optlen;
836b40ce416SJulian Elischer 	return (setsockopt(td, &bsd_args));
837c21dee17SSøren Schmidt }
838c21dee17SSøren Schmidt 
839c21dee17SSøren Schmidt struct linux_getsockopt_args {
840c21dee17SSøren Schmidt 	int s;
841c21dee17SSøren Schmidt 	int level;
842c21dee17SSøren Schmidt 	int optname;
843c21dee17SSøren Schmidt 	void *optval;
844c21dee17SSøren Schmidt 	int *optlen;
845c21dee17SSøren Schmidt };
846c21dee17SSøren Schmidt 
847c21dee17SSøren Schmidt static int
848b40ce416SJulian Elischer linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
849c21dee17SSøren Schmidt {
850c21dee17SSøren Schmidt 	struct linux_getsockopt_args linux_args;
851ef04503dSPeter Wemm 	struct getsockopt_args /* {
852c21dee17SSøren Schmidt 		int s;
853c21dee17SSøren Schmidt 		int level;
854c21dee17SSøren Schmidt 		int name;
855c21dee17SSøren Schmidt 		caddr_t val;
856c21dee17SSøren Schmidt 		int *avalsize;
857ef04503dSPeter Wemm 	} */ bsd_args;
858c21dee17SSøren Schmidt 	int error, name;
859c21dee17SSøren Schmidt 
8603f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8613f3a4815SMarcel Moolenaar 		return (error);
8623f3a4815SMarcel Moolenaar 
863c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
864c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
865c21dee17SSøren Schmidt 	switch (bsd_args.level) {
866c21dee17SSøren Schmidt 	case SOL_SOCKET:
867c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
868c21dee17SSøren Schmidt 		break;
869c21dee17SSøren Schmidt 	case IPPROTO_IP:
870c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
871c21dee17SSøren Schmidt 		break;
872dad3b88aSMike Smith 	case IPPROTO_TCP:
873dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
874dad3b88aSMike Smith 		name = linux_args.optname;
875dad3b88aSMike Smith 		break;
876c21dee17SSøren Schmidt 	default:
8773f3a4815SMarcel Moolenaar 		name = -1;
8783f3a4815SMarcel Moolenaar 		break;
879c21dee17SSøren Schmidt 	}
880c21dee17SSøren Schmidt 	if (name == -1)
8813f3a4815SMarcel Moolenaar 		return (EINVAL);
8823f3a4815SMarcel Moolenaar 
883f2477ae1SMike Smith 	bsd_args.name = name;
884c21dee17SSøren Schmidt 	bsd_args.val = linux_args.optval;
885c21dee17SSøren Schmidt 	bsd_args.avalsize = linux_args.optlen;
886b40ce416SJulian Elischer 	return (getsockopt(td, &bsd_args));
887c21dee17SSøren Schmidt }
888c21dee17SSøren Schmidt 
889c21dee17SSøren Schmidt int
890b40ce416SJulian Elischer linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
891c21dee17SSøren Schmidt {
8925002a60fSMarcel Moolenaar 	void *arg = (void *)args->args;
8933f3a4815SMarcel Moolenaar 
894c21dee17SSøren Schmidt 	switch (args->what) {
895c21dee17SSøren Schmidt 	case LINUX_SOCKET:
896b40ce416SJulian Elischer 		return (linux_socket(td, arg));
897c21dee17SSøren Schmidt 	case LINUX_BIND:
898b40ce416SJulian Elischer 		return (linux_bind(td, arg));
899c21dee17SSøren Schmidt 	case LINUX_CONNECT:
900b40ce416SJulian Elischer 		return (linux_connect(td, arg));
901c21dee17SSøren Schmidt 	case LINUX_LISTEN:
902b40ce416SJulian Elischer 		return (linux_listen(td, arg));
903c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
904b40ce416SJulian Elischer 		return (linux_accept(td, arg));
905c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
906b40ce416SJulian Elischer 		return (linux_getsockname(td, arg));
907c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
908b40ce416SJulian Elischer 		return (linux_getpeername(td, arg));
909c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
910b40ce416SJulian Elischer 		return (linux_socketpair(td, arg));
911c21dee17SSøren Schmidt 	case LINUX_SEND:
912b40ce416SJulian Elischer 		return (linux_send(td, arg));
913c21dee17SSøren Schmidt 	case LINUX_RECV:
914b40ce416SJulian Elischer 		return (linux_recv(td, arg));
915c21dee17SSøren Schmidt 	case LINUX_SENDTO:
916b40ce416SJulian Elischer 		return (linux_sendto(td, arg));
917c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
918b40ce416SJulian Elischer 		return (linux_recvfrom(td, arg));
919c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
920b40ce416SJulian Elischer 		return (linux_shutdown(td, arg));
921c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
922b40ce416SJulian Elischer 		return (linux_setsockopt(td, arg));
923c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
924b40ce416SJulian Elischer 		return (linux_getsockopt(td, arg));
925e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
926096d55fcSMike Smith 		do {
927096d55fcSMike Smith 			int error;
928096d55fcSMike Smith 			int level;
929096d55fcSMike Smith 			caddr_t control;
930096d55fcSMike Smith 			struct {
931096d55fcSMike Smith 				int s;
932096d55fcSMike Smith 				const struct msghdr *msg;
933096d55fcSMike Smith 				int flags;
9345002a60fSMarcel Moolenaar 			} *uap = arg;
935096d55fcSMike Smith 
9363f3a4815SMarcel Moolenaar 			error = copyin(&uap->msg->msg_control, &control,
9373f3a4815SMarcel Moolenaar 			    sizeof(caddr_t));
938096d55fcSMike Smith 			if (error)
9393f3a4815SMarcel Moolenaar 				return (error);
9403f3a4815SMarcel Moolenaar 
941096d55fcSMike Smith 			if (control == NULL)
942096d55fcSMike Smith 				goto done;
9433f3a4815SMarcel Moolenaar 
944096d55fcSMike Smith 			error = copyin(&((struct cmsghdr*)control)->cmsg_level,
945096d55fcSMike Smith 			    &level, sizeof(int));
946096d55fcSMike Smith 			if (error)
9473f3a4815SMarcel Moolenaar 				return (error);
9483f3a4815SMarcel Moolenaar 
949096d55fcSMike Smith 			if (level == 1) {
950096d55fcSMike Smith 				/*
9513f3a4815SMarcel Moolenaar 				 * Linux thinks that SOL_SOCKET is 1; we know
9523f3a4815SMarcel Moolenaar 				 * that it's really 0xffff, of course.
953096d55fcSMike Smith 				 */
954096d55fcSMike Smith 				level = SOL_SOCKET;
9553f3a4815SMarcel Moolenaar 				error = copyout(&level,
9563f3a4815SMarcel Moolenaar 				    &((struct cmsghdr *)control)->cmsg_level,
9573f3a4815SMarcel Moolenaar 				    sizeof(int));
958096d55fcSMike Smith 				if (error)
9593f3a4815SMarcel Moolenaar 					return (error);
960096d55fcSMike Smith 			}
961096d55fcSMike Smith 		done:
962b40ce416SJulian Elischer 			return (sendmsg(td, arg));
963096d55fcSMike Smith 		} while (0);
964e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
965b40ce416SJulian Elischer 		return (linux_recvmsg(td, arg));
966c21dee17SSøren Schmidt 	}
9673f3a4815SMarcel Moolenaar 
9683f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
9693f3a4815SMarcel Moolenaar 	return (ENOSYS);
970c21dee17SSøren Schmidt }
9715231fb20SDavid E. O'Brien #endif	/*!__alpha__*/
972