xref: /freebsd/sys/compat/linux/linux_socket.c (revision 40dbba57542e80ba86c72034bf11f3621c37209a)
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
15c21dee17SSøren Schmidt  *    derived from this software withough 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>
43c21dee17SSøren Schmidt #include <sys/socket.h>
4408637435SBruce Evans #include <sys/uio.h>
451f3dad5aSBruce Evans 
46c21dee17SSøren Schmidt #include <netinet/in.h>
47f2477ae1SMike Smith #include <netinet/in_systm.h>
48f2477ae1SMike Smith #include <netinet/ip.h>
49c21dee17SSøren Schmidt 
50ac951e62SMarcel Moolenaar #include <machine/../linux/linux.h>
51ebea8660SMarcel Moolenaar #include <machine/../linux/linux_proto.h>
5240dbba57SAssar Westerlund #include <compat/linux/linux_socket.h>
53ac951e62SMarcel Moolenaar #include <compat/linux/linux_util.h>
54c21dee17SSøren Schmidt 
555231fb20SDavid E. O'Brien #ifndef __alpha__
56c21dee17SSøren Schmidt static int
57c21dee17SSøren Schmidt linux_to_bsd_domain(int domain)
58c21dee17SSøren Schmidt {
593f3a4815SMarcel Moolenaar 
60c21dee17SSøren Schmidt 	switch (domain) {
61c21dee17SSøren Schmidt 	case LINUX_AF_UNSPEC:
623f3a4815SMarcel Moolenaar 		return (AF_UNSPEC);
63c21dee17SSøren Schmidt 	case LINUX_AF_UNIX:
643f3a4815SMarcel Moolenaar 		return (AF_LOCAL);
65c21dee17SSøren Schmidt 	case LINUX_AF_INET:
663f3a4815SMarcel Moolenaar 		return (AF_INET);
67c21dee17SSøren Schmidt 	case LINUX_AF_AX25:
683f3a4815SMarcel Moolenaar 		return (AF_CCITT);
69c21dee17SSøren Schmidt 	case LINUX_AF_IPX:
703f3a4815SMarcel Moolenaar 		return (AF_IPX);
71c21dee17SSøren Schmidt 	case LINUX_AF_APPLETALK:
723f3a4815SMarcel Moolenaar 		return (AF_APPLETALK);
73c21dee17SSøren Schmidt 	}
743f3a4815SMarcel Moolenaar 	return (-1);
75c21dee17SSøren Schmidt }
76c21dee17SSøren Schmidt 
77c21dee17SSøren Schmidt static int
78c21dee17SSøren Schmidt linux_to_bsd_sockopt_level(int level)
79c21dee17SSøren Schmidt {
803f3a4815SMarcel Moolenaar 
81c21dee17SSøren Schmidt 	switch (level) {
82c21dee17SSøren Schmidt 	case LINUX_SOL_SOCKET:
833f3a4815SMarcel Moolenaar 		return (SOL_SOCKET);
84c21dee17SSøren Schmidt 	}
853f3a4815SMarcel Moolenaar 	return (level);
86c21dee17SSøren Schmidt }
87c21dee17SSøren Schmidt 
883f3a4815SMarcel Moolenaar static int
893f3a4815SMarcel Moolenaar linux_to_bsd_ip_sockopt(int opt)
90c21dee17SSøren Schmidt {
913f3a4815SMarcel Moolenaar 
92c21dee17SSøren Schmidt 	switch (opt) {
93c21dee17SSøren Schmidt 	case LINUX_IP_TOS:
943f3a4815SMarcel Moolenaar 		return (IP_TOS);
95c21dee17SSøren Schmidt 	case LINUX_IP_TTL:
963f3a4815SMarcel Moolenaar 		return (IP_TTL);
9766ff6a3cSBill Fenner 	case LINUX_IP_OPTIONS:
983f3a4815SMarcel Moolenaar 		return (IP_OPTIONS);
9966ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_IF:
1003f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_IF);
10166ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_TTL:
1023f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_TTL);
10366ff6a3cSBill Fenner 	case LINUX_IP_MULTICAST_LOOP:
1043f3a4815SMarcel Moolenaar 		return (IP_MULTICAST_LOOP);
10566ff6a3cSBill Fenner 	case LINUX_IP_ADD_MEMBERSHIP:
1063f3a4815SMarcel Moolenaar 		return (IP_ADD_MEMBERSHIP);
10766ff6a3cSBill Fenner 	case LINUX_IP_DROP_MEMBERSHIP:
1083f3a4815SMarcel Moolenaar 		return (IP_DROP_MEMBERSHIP);
10966ff6a3cSBill Fenner 	case LINUX_IP_HDRINCL:
1103f3a4815SMarcel Moolenaar 		return (IP_HDRINCL);
111c21dee17SSøren Schmidt 	}
1123f3a4815SMarcel Moolenaar 	return (-1);
113c21dee17SSøren Schmidt }
114c21dee17SSøren Schmidt 
115c21dee17SSøren Schmidt static int
116c21dee17SSøren Schmidt linux_to_bsd_so_sockopt(int opt)
117c21dee17SSøren Schmidt {
1183f3a4815SMarcel Moolenaar 
119c21dee17SSøren Schmidt 	switch (opt) {
120c21dee17SSøren Schmidt 	case LINUX_SO_DEBUG:
1213f3a4815SMarcel Moolenaar 		return (SO_DEBUG);
122c21dee17SSøren Schmidt 	case LINUX_SO_REUSEADDR:
1233f3a4815SMarcel Moolenaar 		return (SO_REUSEADDR);
124c21dee17SSøren Schmidt 	case LINUX_SO_TYPE:
1253f3a4815SMarcel Moolenaar 		return (SO_TYPE);
126c21dee17SSøren Schmidt 	case LINUX_SO_ERROR:
1273f3a4815SMarcel Moolenaar 		return (SO_ERROR);
128c21dee17SSøren Schmidt 	case LINUX_SO_DONTROUTE:
1293f3a4815SMarcel Moolenaar 		return (SO_DONTROUTE);
130c21dee17SSøren Schmidt 	case LINUX_SO_BROADCAST:
1313f3a4815SMarcel Moolenaar 		return (SO_BROADCAST);
132c21dee17SSøren Schmidt 	case LINUX_SO_SNDBUF:
1333f3a4815SMarcel Moolenaar 		return (SO_SNDBUF);
134c21dee17SSøren Schmidt 	case LINUX_SO_RCVBUF:
1353f3a4815SMarcel Moolenaar 		return (SO_RCVBUF);
136c21dee17SSøren Schmidt 	case LINUX_SO_KEEPALIVE:
1373f3a4815SMarcel Moolenaar 		return (SO_KEEPALIVE);
138c21dee17SSøren Schmidt 	case LINUX_SO_OOBINLINE:
1393f3a4815SMarcel Moolenaar 		return (SO_OOBINLINE);
140c21dee17SSøren Schmidt 	case LINUX_SO_LINGER:
1413f3a4815SMarcel Moolenaar 		return (SO_LINGER);
142c21dee17SSøren Schmidt 	}
1433f3a4815SMarcel Moolenaar 	return (-1);
144c21dee17SSøren Schmidt }
145c21dee17SSøren Schmidt 
14640dbba57SAssar Westerlund static int
14740dbba57SAssar Westerlund linux_to_bsd_msg_flags(int flags)
14840dbba57SAssar Westerlund {
14940dbba57SAssar Westerlund 	int ret_flags = 0;
15040dbba57SAssar Westerlund 
15140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_OOB)
15240dbba57SAssar Westerlund 		ret_flags |= MSG_OOB;
15340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PEEK)
15440dbba57SAssar Westerlund 		ret_flags |= MSG_PEEK;
15540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTROUTE)
15640dbba57SAssar Westerlund 		ret_flags |= MSG_DONTROUTE;
15740dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CTRUNC)
15840dbba57SAssar Westerlund 		ret_flags |= MSG_CTRUNC;
15940dbba57SAssar Westerlund 	if (flags & LINUX_MSG_TRUNC)
16040dbba57SAssar Westerlund 		ret_flags |= MSG_TRUNC;
16140dbba57SAssar Westerlund 	if (flags & LINUX_MSG_DONTWAIT)
16240dbba57SAssar Westerlund 		ret_flags |= MSG_DONTWAIT;
16340dbba57SAssar Westerlund 	if (flags & LINUX_MSG_EOR)
16440dbba57SAssar Westerlund 		ret_flags |= MSG_EOR;
16540dbba57SAssar Westerlund 	if (flags & LINUX_MSG_WAITALL)
16640dbba57SAssar Westerlund 		ret_flags |= MSG_WAITALL;
16740dbba57SAssar Westerlund #if 0 /* not handled */
16840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_PROXY)
16940dbba57SAssar Westerlund 		;
17040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_FIN)
17140dbba57SAssar Westerlund 		;
17240dbba57SAssar Westerlund 	if (flags & LINUX_MSG_SYN)
17340dbba57SAssar Westerlund 		;
17440dbba57SAssar Westerlund 	if (flags & LINUX_MSG_CONFIRM)
17540dbba57SAssar Westerlund 		;
17640dbba57SAssar Westerlund 	if (flags & LINUX_MSG_RST)
17740dbba57SAssar Westerlund 		;
17840dbba57SAssar Westerlund 	if (flags & LINUX_MSG_ERRQUEUE)
17940dbba57SAssar Westerlund 		;
18040dbba57SAssar Westerlund 	if (flags & LINUX_MSG_NOSIGNAL)
18140dbba57SAssar Westerlund 		;
18240dbba57SAssar Westerlund #endif
18340dbba57SAssar Westerlund 	return ret_flags;
18440dbba57SAssar Westerlund }
18540dbba57SAssar Westerlund 
1863f3a4815SMarcel Moolenaar /* Return 0 if IP_HDRINCL is set for the given socket. */
187f2477ae1SMike Smith static int
188f2477ae1SMike Smith linux_check_hdrincl(struct proc *p, int s)
189f2477ae1SMike Smith {
190f2477ae1SMike Smith 	struct getsockopt_args /* {
191f2477ae1SMike Smith 		int s;
192f2477ae1SMike Smith 		int level;
193f2477ae1SMike Smith 		int name;
194f2477ae1SMike Smith 		caddr_t val;
195f2477ae1SMike Smith 		int *avalsize;
196f2477ae1SMike Smith 	} */ bsd_args;
197f2477ae1SMike Smith 	int error;
198f2477ae1SMike Smith 	caddr_t sg, val, valsize;
199f2477ae1SMike Smith 	int size_val = sizeof val;
200f2477ae1SMike Smith 	int optval;
201f2477ae1SMike Smith 
202f2477ae1SMike Smith 	sg = stackgap_init();
203f2477ae1SMike Smith 	val = stackgap_alloc(&sg, sizeof(int));
204f2477ae1SMike Smith 	valsize = stackgap_alloc(&sg, sizeof(int));
205f2477ae1SMike Smith 
206f2477ae1SMike Smith 	if ((error = copyout(&size_val, valsize, sizeof(size_val))))
2073f3a4815SMarcel Moolenaar 		return (error);
2083f3a4815SMarcel Moolenaar 
209f2477ae1SMike Smith 	bsd_args.s = s;
210f2477ae1SMike Smith 	bsd_args.level = IPPROTO_IP;
211f2477ae1SMike Smith 	bsd_args.name = IP_HDRINCL;
212f2477ae1SMike Smith 	bsd_args.val = val;
213f2477ae1SMike Smith 	bsd_args.avalsize = (int *)valsize;
214f2477ae1SMike Smith 	if ((error = getsockopt(p, &bsd_args)))
2153f3a4815SMarcel Moolenaar 		return (error);
2163f3a4815SMarcel Moolenaar 
217f2477ae1SMike Smith 	if ((error = copyin(val, &optval, sizeof(optval))))
2183f3a4815SMarcel Moolenaar 		return (error);
2193f3a4815SMarcel Moolenaar 
2203f3a4815SMarcel Moolenaar 	return (optval == 0);
221f2477ae1SMike Smith }
222f2477ae1SMike Smith 
223f2477ae1SMike Smith /*
224f2477ae1SMike Smith  * Updated sendto() when IP_HDRINCL is set:
225f2477ae1SMike Smith  * tweak endian-dependent fields in the IP packet.
226f2477ae1SMike Smith  */
227f2477ae1SMike Smith static int
228f2477ae1SMike Smith linux_sendto_hdrincl(struct proc *p, struct sendto_args *bsd_args)
229f2477ae1SMike Smith {
230f2477ae1SMike Smith /*
231f2477ae1SMike Smith  * linux_ip_copysize defines how many bytes we should copy
232f2477ae1SMike Smith  * from the beginning of the IP packet before we customize it for BSD.
233f2477ae1SMike Smith  * It should include all the fields we modify (ip_len and ip_off)
234f2477ae1SMike Smith  * and be as small as possible to minimize copying overhead.
235f2477ae1SMike Smith  */
236f2477ae1SMike Smith #define linux_ip_copysize	8
237f2477ae1SMike Smith 
238f2477ae1SMike Smith 	caddr_t sg;
239f2477ae1SMike Smith 	struct ip *packet;
240f2477ae1SMike Smith 	struct msghdr *msg;
241f2477ae1SMike Smith 	struct iovec *iov;
242f2477ae1SMike Smith 
243f2477ae1SMike Smith 	int error;
244f2477ae1SMike Smith 	struct  sendmsg_args /* {
245f2477ae1SMike Smith 		int s;
246f2477ae1SMike Smith 		caddr_t msg;
247f2477ae1SMike Smith 		int flags;
248f2477ae1SMike Smith 	} */ sendmsg_args;
249f2477ae1SMike Smith 
250f2477ae1SMike Smith 	/* Check the packet isn't too small before we mess with it */
251f2477ae1SMike Smith 	if (bsd_args->len < linux_ip_copysize)
2523f3a4815SMarcel Moolenaar 		return (EINVAL);
253f2477ae1SMike Smith 
254f2477ae1SMike Smith 	/*
255f2477ae1SMike Smith 	 * Tweaking the user buffer in place would be bad manners.
256f2477ae1SMike Smith 	 * We create a corrected IP header with just the needed length,
257f2477ae1SMike Smith 	 * then use an iovec to glue it to the rest of the user packet
258f2477ae1SMike Smith 	 * when calling sendmsg().
259f2477ae1SMike Smith 	 */
260f2477ae1SMike Smith 	sg = stackgap_init();
261f2477ae1SMike Smith 	packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
262f2477ae1SMike Smith 	msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
263f2477ae1SMike Smith 	iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
264f2477ae1SMike Smith 
265f2477ae1SMike Smith 	/* Make a copy of the beginning of the packet to be sent */
2663f3a4815SMarcel Moolenaar 	if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize)))
2673f3a4815SMarcel Moolenaar 		return (error);
268f2477ae1SMike Smith 
269f2477ae1SMike Smith 	/* Convert fields from Linux to BSD raw IP socket format */
270f2477ae1SMike Smith 	packet->ip_len = bsd_args->len;
271f2477ae1SMike Smith 	packet->ip_off = ntohs(packet->ip_off);
272f2477ae1SMike Smith 
273f2477ae1SMike Smith 	/* Prepare the msghdr and iovec structures describing the new packet */
274f2477ae1SMike Smith 	msg->msg_name = bsd_args->to;
275f2477ae1SMike Smith 	msg->msg_namelen = bsd_args->tolen;
276f2477ae1SMike Smith 	msg->msg_iov = iov;
277f2477ae1SMike Smith 	msg->msg_iovlen = 2;
278f2477ae1SMike Smith 	msg->msg_control = NULL;
279f2477ae1SMike Smith 	msg->msg_controllen = 0;
280f2477ae1SMike Smith 	msg->msg_flags = 0;
281f2477ae1SMike Smith 	iov[0].iov_base = (char *)packet;
282f2477ae1SMike Smith 	iov[0].iov_len = linux_ip_copysize;
283f2477ae1SMike Smith 	iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
284f2477ae1SMike Smith 	iov[1].iov_len = bsd_args->len - linux_ip_copysize;
285f2477ae1SMike Smith 
286f2477ae1SMike Smith 	sendmsg_args.s = bsd_args->s;
287f2477ae1SMike Smith 	sendmsg_args.msg = (caddr_t)msg;
288f2477ae1SMike Smith 	sendmsg_args.flags = bsd_args->flags;
2893f3a4815SMarcel Moolenaar 	return (sendmsg(p, &sendmsg_args));
290f2477ae1SMike Smith }
291f2477ae1SMike Smith 
292c21dee17SSøren Schmidt struct linux_socket_args {
293c21dee17SSøren Schmidt 	int domain;
294c21dee17SSøren Schmidt 	int type;
295c21dee17SSøren Schmidt 	int protocol;
296c21dee17SSøren Schmidt };
297c21dee17SSøren Schmidt 
298c21dee17SSøren Schmidt static int
299cb226aaaSPoul-Henning Kamp linux_socket(struct proc *p, struct linux_socket_args *args)
300c21dee17SSøren Schmidt {
301c21dee17SSøren Schmidt 	struct linux_socket_args linux_args;
302ef04503dSPeter Wemm 	struct socket_args /* {
303c21dee17SSøren Schmidt 		int domain;
304c21dee17SSøren Schmidt 		int type;
305c21dee17SSøren Schmidt 		int protocol;
306ef04503dSPeter Wemm 	} */ bsd_args;
307c21dee17SSøren Schmidt 	int error;
308f2477ae1SMike Smith 	int retval_socket;
309c21dee17SSøren Schmidt 
3103f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
3113f3a4815SMarcel Moolenaar 		return (error);
3123f3a4815SMarcel Moolenaar 
313c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
314c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
315c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
316c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
3173f3a4815SMarcel Moolenaar 		return (EINVAL);
318f2477ae1SMike Smith 
319f2477ae1SMike Smith 	retval_socket = socket(p, &bsd_args);
320f2477ae1SMike Smith 	if (bsd_args.type == SOCK_RAW
321f2477ae1SMike Smith 	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
322f2477ae1SMike Smith 	    && bsd_args.domain == AF_INET
323f2477ae1SMike Smith 	    && retval_socket >= 0) {
324f2477ae1SMike Smith 		/* It's a raw IP socket: set the IP_HDRINCL option. */
325f2477ae1SMike Smith 		struct setsockopt_args /* {
326f2477ae1SMike Smith 			int s;
327f2477ae1SMike Smith 			int level;
328f2477ae1SMike Smith 			int name;
329f2477ae1SMike Smith 			caddr_t val;
330f2477ae1SMike Smith 			int valsize;
331f2477ae1SMike Smith 		} */ bsd_setsockopt_args;
332f2477ae1SMike Smith 		caddr_t sg;
333f2477ae1SMike Smith 		int *hdrincl;
334f2477ae1SMike Smith 
335f2477ae1SMike Smith 		sg = stackgap_init();
336f2477ae1SMike Smith 		hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
337f2477ae1SMike Smith 		*hdrincl = 1;
338f2477ae1SMike Smith 		bsd_setsockopt_args.s = p->p_retval[0];
339f2477ae1SMike Smith 		bsd_setsockopt_args.level = IPPROTO_IP;
340f2477ae1SMike Smith 		bsd_setsockopt_args.name = IP_HDRINCL;
341f2477ae1SMike Smith 		bsd_setsockopt_args.val = (caddr_t)hdrincl;
342f2477ae1SMike Smith 		bsd_setsockopt_args.valsize = sizeof(*hdrincl);
343f2477ae1SMike Smith 		/* We ignore any error returned by setsockopt() */
344f2477ae1SMike Smith 		setsockopt(p, &bsd_setsockopt_args);
345f2477ae1SMike Smith 		/* Copy back the return value from socket() */
346f2477ae1SMike Smith 		p->p_retval[0] = bsd_setsockopt_args.s;
347f2477ae1SMike Smith 	}
3483f3a4815SMarcel Moolenaar 
3493f3a4815SMarcel Moolenaar 	return (retval_socket);
350c21dee17SSøren Schmidt }
351c21dee17SSøren Schmidt 
352c21dee17SSøren Schmidt struct linux_bind_args {
353c21dee17SSøren Schmidt 	int s;
354c21dee17SSøren Schmidt 	struct sockaddr *name;
355c21dee17SSøren Schmidt 	int namelen;
356c21dee17SSøren Schmidt };
357c21dee17SSøren Schmidt 
358c21dee17SSøren Schmidt static int
359cb226aaaSPoul-Henning Kamp linux_bind(struct proc *p, struct linux_bind_args *args)
360c21dee17SSøren Schmidt {
361c21dee17SSøren Schmidt 	struct linux_bind_args linux_args;
362ef04503dSPeter Wemm 	struct bind_args /* {
363c21dee17SSøren Schmidt 		int s;
364c21dee17SSøren Schmidt 		caddr_t name;
365c21dee17SSøren Schmidt 		int namelen;
366ef04503dSPeter Wemm 	} */ bsd_args;
367c21dee17SSøren Schmidt 	int error;
368c21dee17SSøren Schmidt 
3693f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
3703f3a4815SMarcel Moolenaar 		return (error);
3713f3a4815SMarcel Moolenaar 
372c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
373c21dee17SSøren Schmidt 	bsd_args.name = (caddr_t)linux_args.name;
374c21dee17SSøren Schmidt 	bsd_args.namelen = linux_args.namelen;
3753f3a4815SMarcel Moolenaar 	return (bind(p, &bsd_args));
376c21dee17SSøren Schmidt }
377c21dee17SSøren Schmidt 
378c21dee17SSøren Schmidt struct linux_connect_args {
379c21dee17SSøren Schmidt 	int s;
380c21dee17SSøren Schmidt 	struct sockaddr * name;
381c21dee17SSøren Schmidt 	int namelen;
382c21dee17SSøren Schmidt };
383930a65feSAndrew Gallatin int linux_connect(struct proc *, struct linux_connect_args *);
384930a65feSAndrew Gallatin #endif /* !__alpha__*/
385c21dee17SSøren Schmidt 
386930a65feSAndrew Gallatin int
387cb226aaaSPoul-Henning Kamp linux_connect(struct proc *p, struct linux_connect_args *args)
388c21dee17SSøren Schmidt {
389c21dee17SSøren Schmidt 	struct linux_connect_args linux_args;
390ef04503dSPeter Wemm 	struct connect_args /* {
391c21dee17SSøren Schmidt 		int s;
392c21dee17SSøren Schmidt 		caddr_t name;
393c21dee17SSøren Schmidt 		int namelen;
394ef04503dSPeter Wemm 	} */ bsd_args;
395c21dee17SSøren Schmidt 	int error;
396c21dee17SSøren Schmidt 
397930a65feSAndrew Gallatin #ifdef __alpha__
398930a65feSAndrew Gallatin 	bcopy(args, &linux_args, sizeof(linux_args));
399930a65feSAndrew Gallatin #else
4003f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
4013f3a4815SMarcel Moolenaar 		return (error);
402930a65feSAndrew Gallatin #endif /* __alpha__ */
4033f3a4815SMarcel Moolenaar 
404c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
405c21dee17SSøren Schmidt 	bsd_args.name = (caddr_t)linux_args.name;
406c21dee17SSøren Schmidt 	bsd_args.namelen = linux_args.namelen;
407dad3b88aSMike Smith 	error = connect(p, &bsd_args);
408dad3b88aSMike Smith 	if (error == EISCONN) {
409dad3b88aSMike Smith 		/*
410dad3b88aSMike Smith 		 * Linux doesn't return EISCONN the first time it occurs,
411dad3b88aSMike Smith 		 * when on a non-blocking socket. Instead it returns the
412dad3b88aSMike Smith 		 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
413dad3b88aSMike Smith 		 */
414dad3b88aSMike Smith 		struct fcntl_args /* {
415dad3b88aSMike Smith 			int fd;
416dad3b88aSMike Smith 			int cmd;
417dad3b88aSMike Smith 			int arg;
418dad3b88aSMike Smith 		} */ bsd_fcntl_args;
419dad3b88aSMike Smith 		struct getsockopt_args /* {
420dad3b88aSMike Smith 			int s;
421dad3b88aSMike Smith 			int level;
422dad3b88aSMike Smith 			int name;
423dad3b88aSMike Smith 			caddr_t val;
424dad3b88aSMike Smith 			int *avalsize;
425dad3b88aSMike Smith 		} */ bsd_getsockopt_args;
426dad3b88aSMike Smith 		void *status, *statusl;
427dad3b88aSMike Smith 		int stat, statl = sizeof stat;
428dad3b88aSMike Smith 		caddr_t sg;
429dad3b88aSMike Smith 
430dad3b88aSMike Smith 		/* Check for non-blocking */
431dad3b88aSMike Smith 		bsd_fcntl_args.fd = linux_args.s;
432dad3b88aSMike Smith 		bsd_fcntl_args.cmd = F_GETFL;
433dad3b88aSMike Smith 		bsd_fcntl_args.arg = 0;
434dad3b88aSMike Smith 		error = fcntl(p, &bsd_fcntl_args);
435dad3b88aSMike Smith 		if (error == 0 && (p->p_retval[0] & O_NONBLOCK)) {
436dad3b88aSMike Smith 			sg = stackgap_init();
437dad3b88aSMike Smith 			status = stackgap_alloc(&sg, sizeof stat);
438dad3b88aSMike Smith 			statusl = stackgap_alloc(&sg, sizeof statusl);
439dad3b88aSMike Smith 
440dad3b88aSMike Smith 			if ((error = copyout(&statl, statusl, sizeof statl)))
4413f3a4815SMarcel Moolenaar 				return (error);
442dad3b88aSMike Smith 
443dad3b88aSMike Smith 			bsd_getsockopt_args.s = linux_args.s;
444dad3b88aSMike Smith 			bsd_getsockopt_args.level = SOL_SOCKET;
445dad3b88aSMike Smith 			bsd_getsockopt_args.name = SO_ERROR;
446dad3b88aSMike Smith 			bsd_getsockopt_args.val = status;
447dad3b88aSMike Smith 			bsd_getsockopt_args.avalsize = statusl;
448dad3b88aSMike Smith 
449dad3b88aSMike Smith 			error = getsockopt(p, &bsd_getsockopt_args);
450dad3b88aSMike Smith 			if (error)
4513f3a4815SMarcel Moolenaar 				return (error);
4523f3a4815SMarcel Moolenaar 
453dad3b88aSMike Smith 			if ((error = copyin(status, &stat, sizeof stat)))
4543f3a4815SMarcel Moolenaar 				return (error);
4553f3a4815SMarcel Moolenaar 
456dad3b88aSMike Smith 			p->p_retval[0] = stat;
4573f3a4815SMarcel Moolenaar 			return (0);
458dad3b88aSMike Smith 		}
459dad3b88aSMike Smith 	}
4603f3a4815SMarcel Moolenaar 
4613f3a4815SMarcel Moolenaar 	return (error);
462c21dee17SSøren Schmidt }
463c21dee17SSøren Schmidt 
464930a65feSAndrew Gallatin #ifndef __alpha__
465930a65feSAndrew Gallatin 
466c21dee17SSøren Schmidt struct linux_listen_args {
467c21dee17SSøren Schmidt 	int s;
468c21dee17SSøren Schmidt 	int backlog;
469c21dee17SSøren Schmidt };
470c21dee17SSøren Schmidt 
471c21dee17SSøren Schmidt static int
472cb226aaaSPoul-Henning Kamp linux_listen(struct proc *p, struct linux_listen_args *args)
473c21dee17SSøren Schmidt {
474c21dee17SSøren Schmidt 	struct linux_listen_args linux_args;
475ef04503dSPeter Wemm 	struct listen_args /* {
476c21dee17SSøren Schmidt 		int s;
477c21dee17SSøren Schmidt 		int backlog;
478ef04503dSPeter Wemm 	} */ bsd_args;
479c21dee17SSøren Schmidt 	int error;
480c21dee17SSøren Schmidt 
4813f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
4823f3a4815SMarcel Moolenaar 		return (error);
4833f3a4815SMarcel Moolenaar 
484c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
485c21dee17SSøren Schmidt 	bsd_args.backlog = linux_args.backlog;
4863f3a4815SMarcel Moolenaar 	return (listen(p, &bsd_args));
487c21dee17SSøren Schmidt }
488c21dee17SSøren Schmidt 
489c21dee17SSøren Schmidt struct linux_accept_args {
490c21dee17SSøren Schmidt 	int s;
491c21dee17SSøren Schmidt 	struct sockaddr *addr;
492c21dee17SSøren Schmidt 	int *namelen;
493c21dee17SSøren Schmidt };
494c21dee17SSøren Schmidt 
495c21dee17SSøren Schmidt static int
496cb226aaaSPoul-Henning Kamp linux_accept(struct proc *p, struct linux_accept_args *args)
497c21dee17SSøren Schmidt {
498c21dee17SSøren Schmidt 	struct linux_accept_args linux_args;
499ef04503dSPeter Wemm 	struct accept_args /* {
500c21dee17SSøren Schmidt 		int s;
501c21dee17SSøren Schmidt 		caddr_t name;
502c21dee17SSøren Schmidt 		int *anamelen;
503ef04503dSPeter Wemm 	} */ bsd_args;
504dba5ab66SMarcel Moolenaar 	struct fcntl_args /* {
505dba5ab66SMarcel Moolenaar 		int fd;
506dba5ab66SMarcel Moolenaar 		int cmd;
507dba5ab66SMarcel Moolenaar 		long arg;
508dba5ab66SMarcel Moolenaar 	} */ f_args;
509c21dee17SSøren Schmidt 	int error;
510c21dee17SSøren Schmidt 
5113f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5123f3a4815SMarcel Moolenaar 		return (error);
5133f3a4815SMarcel Moolenaar 
514c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
515c21dee17SSøren Schmidt 	bsd_args.name = (caddr_t)linux_args.addr;
516c21dee17SSøren Schmidt 	bsd_args.anamelen = linux_args.namelen;
517dba5ab66SMarcel Moolenaar 	error = oaccept(p, &bsd_args);
518dba5ab66SMarcel Moolenaar 	if (error)
519dba5ab66SMarcel Moolenaar 		return (error);
520dba5ab66SMarcel Moolenaar 
521dba5ab66SMarcel Moolenaar 	/*
522dba5ab66SMarcel Moolenaar 	 * linux appears not to copy flags from the parent socket to the
523dba5ab66SMarcel Moolenaar 	 * accepted one, so we must clear the flags in the new descriptor.
524dba5ab66SMarcel Moolenaar 	 * Ignore any errors, because we already have an open fd.
525dba5ab66SMarcel Moolenaar 	 */
526dba5ab66SMarcel Moolenaar 	f_args.fd = p->p_retval[0];
527dba5ab66SMarcel Moolenaar 	f_args.cmd = F_SETFL;
528dba5ab66SMarcel Moolenaar 	f_args.arg = 0;
529dba5ab66SMarcel Moolenaar 	(void)fcntl(p, &f_args);
530dba5ab66SMarcel Moolenaar 	p->p_retval[0] = f_args.fd;
531dba5ab66SMarcel Moolenaar 	return (0);
532c21dee17SSøren Schmidt }
533c21dee17SSøren Schmidt 
534c21dee17SSøren Schmidt struct linux_getsockname_args {
535c21dee17SSøren Schmidt 	int s;
536c21dee17SSøren Schmidt 	struct sockaddr *addr;
537c21dee17SSøren Schmidt 	int *namelen;
538c21dee17SSøren Schmidt };
539c21dee17SSøren Schmidt 
540c21dee17SSøren Schmidt static int
541cb226aaaSPoul-Henning Kamp linux_getsockname(struct proc *p, struct linux_getsockname_args *args)
542c21dee17SSøren Schmidt {
543c21dee17SSøren Schmidt 	struct linux_getsockname_args linux_args;
544ef04503dSPeter Wemm 	struct getsockname_args /* {
545c21dee17SSøren Schmidt 		int fdes;
546c21dee17SSøren Schmidt 		caddr_t asa;
547c21dee17SSøren Schmidt 		int *alen;
548ef04503dSPeter Wemm 	} */ bsd_args;
549c21dee17SSøren Schmidt 	int error;
550c21dee17SSøren Schmidt 
5513f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5523f3a4815SMarcel Moolenaar 		return (error);
5533f3a4815SMarcel Moolenaar 
554c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
555c21dee17SSøren Schmidt 	bsd_args.asa = (caddr_t) linux_args.addr;
556c21dee17SSøren Schmidt 	bsd_args.alen = linux_args.namelen;
5573f3a4815SMarcel Moolenaar 	return (ogetsockname(p, &bsd_args));
558c21dee17SSøren Schmidt }
559c21dee17SSøren Schmidt 
560c21dee17SSøren Schmidt struct linux_getpeername_args {
561c21dee17SSøren Schmidt 	int s;
562c21dee17SSøren Schmidt 	struct sockaddr *addr;
563c21dee17SSøren Schmidt 	int *namelen;
564c21dee17SSøren Schmidt };
565c21dee17SSøren Schmidt 
566c21dee17SSøren Schmidt static int
567cb226aaaSPoul-Henning Kamp linux_getpeername(struct proc *p, struct linux_getpeername_args *args)
568c21dee17SSøren Schmidt {
569c21dee17SSøren Schmidt 	struct linux_getpeername_args linux_args;
570ef04503dSPeter Wemm 	struct ogetpeername_args /* {
571c21dee17SSøren Schmidt 		int fdes;
572c21dee17SSøren Schmidt 		caddr_t asa;
573c21dee17SSøren Schmidt 		int *alen;
574ef04503dSPeter Wemm 	} */ bsd_args;
575c21dee17SSøren Schmidt 	int error;
576c21dee17SSøren Schmidt 
5773f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
5783f3a4815SMarcel Moolenaar 		return (error);
5793f3a4815SMarcel Moolenaar 
580c21dee17SSøren Schmidt 	bsd_args.fdes = linux_args.s;
581c21dee17SSøren Schmidt 	bsd_args.asa = (caddr_t) linux_args.addr;
582c21dee17SSøren Schmidt 	bsd_args.alen = linux_args.namelen;
5833f3a4815SMarcel Moolenaar 	return (ogetpeername(p, &bsd_args));
584c21dee17SSøren Schmidt }
585c21dee17SSøren Schmidt 
586c21dee17SSøren Schmidt struct linux_socketpair_args {
587c21dee17SSøren Schmidt 	int domain;
588c21dee17SSøren Schmidt 	int type;
589c21dee17SSøren Schmidt 	int protocol;
590c21dee17SSøren Schmidt 	int *rsv;
591c21dee17SSøren Schmidt };
592c21dee17SSøren Schmidt 
593c21dee17SSøren Schmidt static int
594cb226aaaSPoul-Henning Kamp linux_socketpair(struct proc *p, struct linux_socketpair_args *args)
595c21dee17SSøren Schmidt {
596c21dee17SSøren Schmidt 	struct linux_socketpair_args linux_args;
597ef04503dSPeter Wemm 	struct socketpair_args /* {
598c21dee17SSøren Schmidt 		int domain;
599c21dee17SSøren Schmidt 		int type;
600c21dee17SSøren Schmidt 		int protocol;
601c21dee17SSøren Schmidt 		int *rsv;
602ef04503dSPeter Wemm 	} */ bsd_args;
603c21dee17SSøren Schmidt 	int error;
604c21dee17SSøren Schmidt 
6053f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6063f3a4815SMarcel Moolenaar 		return (error);
6073f3a4815SMarcel Moolenaar 
608c21dee17SSøren Schmidt 	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
609c21dee17SSøren Schmidt 	if (bsd_args.domain == -1)
6103f3a4815SMarcel Moolenaar 		return (EINVAL);
6113f3a4815SMarcel Moolenaar 
612c21dee17SSøren Schmidt 	bsd_args.type = linux_args.type;
613c21dee17SSøren Schmidt 	bsd_args.protocol = linux_args.protocol;
614c21dee17SSøren Schmidt 	bsd_args.rsv = linux_args.rsv;
6153f3a4815SMarcel Moolenaar 	return (socketpair(p, &bsd_args));
616c21dee17SSøren Schmidt }
617c21dee17SSøren Schmidt 
618c21dee17SSøren Schmidt struct linux_send_args {
619c21dee17SSøren Schmidt 	int s;
620c21dee17SSøren Schmidt 	void *msg;
621c21dee17SSøren Schmidt 	int len;
622c21dee17SSøren Schmidt 	int flags;
623c21dee17SSøren Schmidt };
624c21dee17SSøren Schmidt 
625c21dee17SSøren Schmidt static int
626cb226aaaSPoul-Henning Kamp linux_send(struct proc *p, struct linux_send_args *args)
627c21dee17SSøren Schmidt {
628c21dee17SSøren Schmidt 	struct linux_send_args linux_args;
629ef04503dSPeter Wemm 	struct osend_args /* {
630c21dee17SSøren Schmidt 		int s;
631c21dee17SSøren Schmidt 		caddr_t buf;
632c21dee17SSøren Schmidt 		int len;
633c21dee17SSøren Schmidt 		int flags;
634ef04503dSPeter Wemm 	} */ bsd_args;
635c21dee17SSøren Schmidt 	int error;
636c21dee17SSøren Schmidt 
6373f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6383f3a4815SMarcel Moolenaar 		return (error);
6393f3a4815SMarcel Moolenaar 
640c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
641c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.msg;
642c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
643c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
6443f3a4815SMarcel Moolenaar 	return (osend(p, &bsd_args));
645c21dee17SSøren Schmidt }
646c21dee17SSøren Schmidt 
647c21dee17SSøren Schmidt struct linux_recv_args {
648c21dee17SSøren Schmidt 	int s;
649c21dee17SSøren Schmidt 	void *msg;
650c21dee17SSøren Schmidt 	int len;
651c21dee17SSøren Schmidt 	int flags;
652c21dee17SSøren Schmidt };
653c21dee17SSøren Schmidt 
654c21dee17SSøren Schmidt static int
655cb226aaaSPoul-Henning Kamp linux_recv(struct proc *p, struct linux_recv_args *args)
656c21dee17SSøren Schmidt {
657c21dee17SSøren Schmidt 	struct linux_recv_args linux_args;
658ef04503dSPeter Wemm 	struct orecv_args /* {
659c21dee17SSøren Schmidt 		int s;
660c21dee17SSøren Schmidt 		caddr_t buf;
661c21dee17SSøren Schmidt 		int len;
662c21dee17SSøren Schmidt 		int flags;
663ef04503dSPeter Wemm 	} */ bsd_args;
664c21dee17SSøren Schmidt 	int error;
665c21dee17SSøren Schmidt 
6663f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
6673f3a4815SMarcel Moolenaar 		return (error);
6683f3a4815SMarcel Moolenaar 
669c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
670c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.msg;
671c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
672c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
6733f3a4815SMarcel Moolenaar 	return (orecv(p, &bsd_args));
674c21dee17SSøren Schmidt }
675c21dee17SSøren Schmidt 
676c21dee17SSøren Schmidt struct linux_sendto_args {
677c21dee17SSøren Schmidt 	int s;
678c21dee17SSøren Schmidt 	void *msg;
679c21dee17SSøren Schmidt 	int len;
680c21dee17SSøren Schmidt 	int flags;
681c21dee17SSøren Schmidt 	caddr_t to;
682c21dee17SSøren Schmidt 	int tolen;
683c21dee17SSøren Schmidt };
684c21dee17SSøren Schmidt 
685c21dee17SSøren Schmidt static int
686cb226aaaSPoul-Henning Kamp linux_sendto(struct proc *p, struct linux_sendto_args *args)
687c21dee17SSøren Schmidt {
688c21dee17SSøren Schmidt 	struct linux_sendto_args linux_args;
689ef04503dSPeter Wemm 	struct sendto_args /* {
690c21dee17SSøren Schmidt 		int s;
691c21dee17SSøren Schmidt 		caddr_t buf;
692c21dee17SSøren Schmidt 		size_t len;
693c21dee17SSøren Schmidt 		int flags;
694c21dee17SSøren Schmidt 		caddr_t to;
695c21dee17SSøren Schmidt 		int tolen;
696ef04503dSPeter Wemm 	} */ bsd_args;
697c21dee17SSøren Schmidt 	int error;
698c21dee17SSøren Schmidt 
6993f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7003f3a4815SMarcel Moolenaar 		return (error);
7013f3a4815SMarcel Moolenaar 
702c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
703c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.msg;
704c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
705c21dee17SSøren Schmidt 	bsd_args.flags = linux_args.flags;
706c21dee17SSøren Schmidt 	bsd_args.to = linux_args.to;
707c21dee17SSøren Schmidt 	bsd_args.tolen = linux_args.tolen;
708f2477ae1SMike Smith 
709f2477ae1SMike Smith 	if (linux_check_hdrincl(p, linux_args.s) == 0)
710f2477ae1SMike Smith 		/* IP_HDRINCL set, tweak the packet before sending */
7113f3a4815SMarcel Moolenaar 		return (linux_sendto_hdrincl(p, &bsd_args));
712f2477ae1SMike Smith 
7133f3a4815SMarcel Moolenaar 	return (sendto(p, &bsd_args));
714c21dee17SSøren Schmidt }
715c21dee17SSøren Schmidt 
716c21dee17SSøren Schmidt struct linux_recvfrom_args {
717c21dee17SSøren Schmidt 	int s;
718c21dee17SSøren Schmidt 	void *buf;
719c21dee17SSøren Schmidt 	int len;
720c21dee17SSøren Schmidt 	int flags;
721c21dee17SSøren Schmidt 	caddr_t from;
722c21dee17SSøren Schmidt 	int *fromlen;
723c21dee17SSøren Schmidt };
724c21dee17SSøren Schmidt 
725c21dee17SSøren Schmidt static int
726cb226aaaSPoul-Henning Kamp linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args)
727c21dee17SSøren Schmidt {
728c21dee17SSøren Schmidt 	struct linux_recvfrom_args linux_args;
729ef04503dSPeter Wemm 	struct recvfrom_args /* {
730c21dee17SSøren Schmidt 		int s;
731c21dee17SSøren Schmidt 		caddr_t buf;
732c21dee17SSøren Schmidt 		size_t len;
733c21dee17SSøren Schmidt 		int flags;
734c21dee17SSøren Schmidt 		caddr_t from;
735c21dee17SSøren Schmidt 		int *fromlenaddr;
736ef04503dSPeter Wemm 	} */ bsd_args;
737c21dee17SSøren Schmidt 	int error;
738c21dee17SSøren Schmidt 
7393f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7403f3a4815SMarcel Moolenaar 		return (error);
7413f3a4815SMarcel Moolenaar 
742c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
743c21dee17SSøren Schmidt 	bsd_args.buf = linux_args.buf;
744c21dee17SSøren Schmidt 	bsd_args.len = linux_args.len;
74540dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
746c21dee17SSøren Schmidt 	bsd_args.from = linux_args.from;
747c21dee17SSøren Schmidt 	bsd_args.fromlenaddr = linux_args.fromlen;
7483f3a4815SMarcel Moolenaar 	return (orecvfrom(p, &bsd_args));
749c21dee17SSøren Schmidt }
750c21dee17SSøren Schmidt 
75140dbba57SAssar Westerlund struct linux_recvmsg_args {
75240dbba57SAssar Westerlund 	int s;
75340dbba57SAssar Westerlund 	struct msghdr *msg;
75440dbba57SAssar Westerlund 	int flags;
75540dbba57SAssar Westerlund };
75640dbba57SAssar Westerlund 
75740dbba57SAssar Westerlund static int
75840dbba57SAssar Westerlund linux_recvmsg(struct proc *p, struct linux_recvmsg_args *args)
75940dbba57SAssar Westerlund {
76040dbba57SAssar Westerlund 	struct linux_recvmsg_args linux_args;
76140dbba57SAssar Westerlund 	struct recvmsg_args /* {
76240dbba57SAssar Westerlund 		int	s;
76340dbba57SAssar Westerlund 		struct	msghdr *msg;
76440dbba57SAssar Westerlund 		int	flags;
76540dbba57SAssar Westerlund 	} */ bsd_args;
76640dbba57SAssar Westerlund 	int error;
76740dbba57SAssar Westerlund 
76840dbba57SAssar Westerlund 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
76940dbba57SAssar Westerlund 		return (error);
77040dbba57SAssar Westerlund 
77140dbba57SAssar Westerlund 	bsd_args.s = linux_args.s;
77240dbba57SAssar Westerlund 	bsd_args.msg = linux_args.msg;
77340dbba57SAssar Westerlund 	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
77440dbba57SAssar Westerlund 	return (recvmsg(p, &bsd_args));
77540dbba57SAssar Westerlund }
77640dbba57SAssar Westerlund 
777c21dee17SSøren Schmidt struct linux_shutdown_args {
778c21dee17SSøren Schmidt 	int s;
779c21dee17SSøren Schmidt 	int how;
780c21dee17SSøren Schmidt };
781c21dee17SSøren Schmidt 
782c21dee17SSøren Schmidt static int
783cb226aaaSPoul-Henning Kamp linux_shutdown(struct proc *p, struct linux_shutdown_args *args)
784c21dee17SSøren Schmidt {
785c21dee17SSøren Schmidt 	struct linux_shutdown_args linux_args;
786ef04503dSPeter Wemm 	struct shutdown_args /* {
787c21dee17SSøren Schmidt 		int s;
788c21dee17SSøren Schmidt 		int how;
789ef04503dSPeter Wemm 	} */ bsd_args;
790c21dee17SSøren Schmidt 	int error;
791c21dee17SSøren Schmidt 
7923f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
7933f3a4815SMarcel Moolenaar 		return (error);
7943f3a4815SMarcel Moolenaar 
795c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
796c21dee17SSøren Schmidt 	bsd_args.how = linux_args.how;
7973f3a4815SMarcel Moolenaar 	return (shutdown(p, &bsd_args));
798c21dee17SSøren Schmidt }
799c21dee17SSøren Schmidt 
800c21dee17SSøren Schmidt struct linux_setsockopt_args {
801c21dee17SSøren Schmidt 	int s;
802c21dee17SSøren Schmidt 	int level;
803c21dee17SSøren Schmidt 	int optname;
804c21dee17SSøren Schmidt 	void *optval;
805c21dee17SSøren Schmidt 	int optlen;
806c21dee17SSøren Schmidt };
807c21dee17SSøren Schmidt 
808c21dee17SSøren Schmidt static int
809cb226aaaSPoul-Henning Kamp linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args)
810c21dee17SSøren Schmidt {
811c21dee17SSøren Schmidt 	struct linux_setsockopt_args linux_args;
812ef04503dSPeter Wemm 	struct setsockopt_args /* {
813c21dee17SSøren Schmidt 		int s;
814c21dee17SSøren Schmidt 		int level;
815c21dee17SSøren Schmidt 		int name;
816c21dee17SSøren Schmidt 		caddr_t val;
817c21dee17SSøren Schmidt 		int valsize;
818ef04503dSPeter Wemm 	} */ bsd_args;
819c21dee17SSøren Schmidt 	int error, name;
820c21dee17SSøren Schmidt 
8213f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8223f3a4815SMarcel Moolenaar 		return (error);
8233f3a4815SMarcel Moolenaar 
824c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
825c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
826c21dee17SSøren Schmidt 	switch (bsd_args.level) {
827c21dee17SSøren Schmidt 	case SOL_SOCKET:
828c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
829c21dee17SSøren Schmidt 		break;
830c21dee17SSøren Schmidt 	case IPPROTO_IP:
831c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
832c21dee17SSøren Schmidt 		break;
833dad3b88aSMike Smith 	case IPPROTO_TCP:
834dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
835dad3b88aSMike Smith 		name = linux_args.optname;
836dad3b88aSMike Smith 		break;
837c21dee17SSøren Schmidt 	default:
8383f3a4815SMarcel Moolenaar 		name = -1;
8393f3a4815SMarcel Moolenaar 		break;
840c21dee17SSøren Schmidt 	}
841c21dee17SSøren Schmidt 	if (name == -1)
8423f3a4815SMarcel Moolenaar 		return (EINVAL);
8433f3a4815SMarcel Moolenaar 
844c21dee17SSøren Schmidt 	bsd_args.name = name;
845c21dee17SSøren Schmidt 	bsd_args.val = linux_args.optval;
846c21dee17SSøren Schmidt 	bsd_args.valsize = linux_args.optlen;
8473f3a4815SMarcel Moolenaar 	return (setsockopt(p, &bsd_args));
848c21dee17SSøren Schmidt }
849c21dee17SSøren Schmidt 
850c21dee17SSøren Schmidt struct linux_getsockopt_args {
851c21dee17SSøren Schmidt 	int s;
852c21dee17SSøren Schmidt 	int level;
853c21dee17SSøren Schmidt 	int optname;
854c21dee17SSøren Schmidt 	void *optval;
855c21dee17SSøren Schmidt 	int *optlen;
856c21dee17SSøren Schmidt };
857c21dee17SSøren Schmidt 
858c21dee17SSøren Schmidt static int
859cb226aaaSPoul-Henning Kamp linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args)
860c21dee17SSøren Schmidt {
861c21dee17SSøren Schmidt 	struct linux_getsockopt_args linux_args;
862ef04503dSPeter Wemm 	struct getsockopt_args /* {
863c21dee17SSøren Schmidt 		int s;
864c21dee17SSøren Schmidt 		int level;
865c21dee17SSøren Schmidt 		int name;
866c21dee17SSøren Schmidt 		caddr_t val;
867c21dee17SSøren Schmidt 		int *avalsize;
868ef04503dSPeter Wemm 	} */ bsd_args;
869c21dee17SSøren Schmidt 	int error, name;
870c21dee17SSøren Schmidt 
8713f3a4815SMarcel Moolenaar 	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
8723f3a4815SMarcel Moolenaar 		return (error);
8733f3a4815SMarcel Moolenaar 
874c21dee17SSøren Schmidt 	bsd_args.s = linux_args.s;
875c21dee17SSøren Schmidt 	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
876c21dee17SSøren Schmidt 	switch (bsd_args.level) {
877c21dee17SSøren Schmidt 	case SOL_SOCKET:
878c21dee17SSøren Schmidt 		name = linux_to_bsd_so_sockopt(linux_args.optname);
879c21dee17SSøren Schmidt 		break;
880c21dee17SSøren Schmidt 	case IPPROTO_IP:
881c21dee17SSøren Schmidt 		name = linux_to_bsd_ip_sockopt(linux_args.optname);
882c21dee17SSøren Schmidt 		break;
883dad3b88aSMike Smith 	case IPPROTO_TCP:
884dad3b88aSMike Smith 		/* Linux TCP option values match BSD's */
885dad3b88aSMike Smith 		name = linux_args.optname;
886dad3b88aSMike Smith 		break;
887c21dee17SSøren Schmidt 	default:
8883f3a4815SMarcel Moolenaar 		name = -1;
8893f3a4815SMarcel Moolenaar 		break;
890c21dee17SSøren Schmidt 	}
891c21dee17SSøren Schmidt 	if (name == -1)
8923f3a4815SMarcel Moolenaar 		return (EINVAL);
8933f3a4815SMarcel Moolenaar 
894f2477ae1SMike Smith 	bsd_args.name = name;
895c21dee17SSøren Schmidt 	bsd_args.val = linux_args.optval;
896c21dee17SSøren Schmidt 	bsd_args.avalsize = linux_args.optlen;
8973f3a4815SMarcel Moolenaar 	return (getsockopt(p, &bsd_args));
898c21dee17SSøren Schmidt }
899c21dee17SSøren Schmidt 
900c21dee17SSøren Schmidt int
901cb226aaaSPoul-Henning Kamp linux_socketcall(struct proc *p, struct linux_socketcall_args *args)
902c21dee17SSøren Schmidt {
9033f3a4815SMarcel Moolenaar 
904c21dee17SSøren Schmidt 	switch (args->what) {
905c21dee17SSøren Schmidt 	case LINUX_SOCKET:
9063f3a4815SMarcel Moolenaar 		return (linux_socket(p, args->args));
907c21dee17SSøren Schmidt 	case LINUX_BIND:
9083f3a4815SMarcel Moolenaar 		return (linux_bind(p, args->args));
909c21dee17SSøren Schmidt 	case LINUX_CONNECT:
9103f3a4815SMarcel Moolenaar 		return (linux_connect(p, args->args));
911c21dee17SSøren Schmidt 	case LINUX_LISTEN:
9123f3a4815SMarcel Moolenaar 		return (linux_listen(p, args->args));
913c21dee17SSøren Schmidt 	case LINUX_ACCEPT:
9143f3a4815SMarcel Moolenaar 		return (linux_accept(p, args->args));
915c21dee17SSøren Schmidt 	case LINUX_GETSOCKNAME:
9163f3a4815SMarcel Moolenaar 		return (linux_getsockname(p, args->args));
917c21dee17SSøren Schmidt 	case LINUX_GETPEERNAME:
9183f3a4815SMarcel Moolenaar 		return (linux_getpeername(p, args->args));
919c21dee17SSøren Schmidt 	case LINUX_SOCKETPAIR:
9203f3a4815SMarcel Moolenaar 		return (linux_socketpair(p, args->args));
921c21dee17SSøren Schmidt 	case LINUX_SEND:
9223f3a4815SMarcel Moolenaar 		return (linux_send(p, args->args));
923c21dee17SSøren Schmidt 	case LINUX_RECV:
9243f3a4815SMarcel Moolenaar 		return (linux_recv(p, args->args));
925c21dee17SSøren Schmidt 	case LINUX_SENDTO:
9263f3a4815SMarcel Moolenaar 		return (linux_sendto(p, args->args));
927c21dee17SSøren Schmidt 	case LINUX_RECVFROM:
9283f3a4815SMarcel Moolenaar 		return (linux_recvfrom(p, args->args));
929c21dee17SSøren Schmidt 	case LINUX_SHUTDOWN:
9303f3a4815SMarcel Moolenaar 		return (linux_shutdown(p, args->args));
931c21dee17SSøren Schmidt 	case LINUX_SETSOCKOPT:
9323f3a4815SMarcel Moolenaar 		return (linux_setsockopt(p, args->args));
933c21dee17SSøren Schmidt 	case LINUX_GETSOCKOPT:
9343f3a4815SMarcel Moolenaar 		return (linux_getsockopt(p, args->args));
935e76bba09SSøren Schmidt 	case LINUX_SENDMSG:
936096d55fcSMike Smith 		do {
937096d55fcSMike Smith 			int error;
938096d55fcSMike Smith 			int level;
939096d55fcSMike Smith 			caddr_t control;
940096d55fcSMike Smith 			struct {
941096d55fcSMike Smith 				int s;
942096d55fcSMike Smith 				const struct msghdr *msg;
943096d55fcSMike Smith 				int flags;
944096d55fcSMike Smith 			} *uap = args->args;
945096d55fcSMike Smith 
9463f3a4815SMarcel Moolenaar 			error = copyin(&uap->msg->msg_control, &control,
9473f3a4815SMarcel Moolenaar 			    sizeof(caddr_t));
948096d55fcSMike Smith 			if (error)
9493f3a4815SMarcel Moolenaar 				return (error);
9503f3a4815SMarcel Moolenaar 
951096d55fcSMike Smith 			if (control == NULL)
952096d55fcSMike Smith 				goto done;
9533f3a4815SMarcel Moolenaar 
954096d55fcSMike Smith 			error = copyin(&((struct cmsghdr*)control)->cmsg_level,
955096d55fcSMike Smith 			    &level, sizeof(int));
956096d55fcSMike Smith 			if (error)
9573f3a4815SMarcel Moolenaar 				return (error);
9583f3a4815SMarcel Moolenaar 
959096d55fcSMike Smith 			if (level == 1) {
960096d55fcSMike Smith 				/*
9613f3a4815SMarcel Moolenaar 				 * Linux thinks that SOL_SOCKET is 1; we know
9623f3a4815SMarcel Moolenaar 				 * that it's really 0xffff, of course.
963096d55fcSMike Smith 				 */
964096d55fcSMike Smith 				level = SOL_SOCKET;
9653f3a4815SMarcel Moolenaar 				error = copyout(&level,
9663f3a4815SMarcel Moolenaar 				    &((struct cmsghdr *)control)->cmsg_level,
9673f3a4815SMarcel Moolenaar 				    sizeof(int));
968096d55fcSMike Smith 				if (error)
9693f3a4815SMarcel Moolenaar 					return (error);
970096d55fcSMike Smith 			}
971096d55fcSMike Smith 		done:
9723f3a4815SMarcel Moolenaar 			return (sendmsg(p, args->args));
973096d55fcSMike Smith 		} while (0);
974e76bba09SSøren Schmidt 	case LINUX_RECVMSG:
97540dbba57SAssar Westerlund 		return (linux_recvmsg(p, args->args));
976c21dee17SSøren Schmidt 	}
9773f3a4815SMarcel Moolenaar 
9783f3a4815SMarcel Moolenaar 	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
9793f3a4815SMarcel Moolenaar 	return (ENOSYS);
980c21dee17SSøren Schmidt }
9815231fb20SDavid E. O'Brien #endif	/*!__alpha__*/
982