linux_socket.c revision 70178
1/*-
2 * Copyright (c) 1995 S�ren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software withough specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: head/sys/compat/linux/linux_socket.c 70178 2000-12-19 00:24:25Z assar $
29 */
30
31/* XXX we use functions that might not exist. */
32#include "opt_compat.h"
33
34#ifndef COMPAT_43
35#error "Unable to compile Linux-emulator due to missing COMPAT_43 option!"
36#endif
37
38#include <sys/param.h>
39#include <sys/proc.h>
40#include <sys/systm.h>
41#include <sys/sysproto.h>
42#include <sys/fcntl.h>
43#include <sys/socket.h>
44#include <sys/uio.h>
45
46#include <netinet/in.h>
47#include <netinet/in_systm.h>
48#include <netinet/ip.h>
49
50#include <machine/../linux/linux.h>
51#include <machine/../linux/linux_proto.h>
52#include <compat/linux/linux_socket.h>
53#include <compat/linux/linux_util.h>
54
55#ifndef __alpha__
56static int
57linux_to_bsd_domain(int domain)
58{
59
60	switch (domain) {
61	case LINUX_AF_UNSPEC:
62		return (AF_UNSPEC);
63	case LINUX_AF_UNIX:
64		return (AF_LOCAL);
65	case LINUX_AF_INET:
66		return (AF_INET);
67	case LINUX_AF_AX25:
68		return (AF_CCITT);
69	case LINUX_AF_IPX:
70		return (AF_IPX);
71	case LINUX_AF_APPLETALK:
72		return (AF_APPLETALK);
73	}
74	return (-1);
75}
76
77static int
78linux_to_bsd_sockopt_level(int level)
79{
80
81	switch (level) {
82	case LINUX_SOL_SOCKET:
83		return (SOL_SOCKET);
84	}
85	return (level);
86}
87
88static int
89linux_to_bsd_ip_sockopt(int opt)
90{
91
92	switch (opt) {
93	case LINUX_IP_TOS:
94		return (IP_TOS);
95	case LINUX_IP_TTL:
96		return (IP_TTL);
97	case LINUX_IP_OPTIONS:
98		return (IP_OPTIONS);
99	case LINUX_IP_MULTICAST_IF:
100		return (IP_MULTICAST_IF);
101	case LINUX_IP_MULTICAST_TTL:
102		return (IP_MULTICAST_TTL);
103	case LINUX_IP_MULTICAST_LOOP:
104		return (IP_MULTICAST_LOOP);
105	case LINUX_IP_ADD_MEMBERSHIP:
106		return (IP_ADD_MEMBERSHIP);
107	case LINUX_IP_DROP_MEMBERSHIP:
108		return (IP_DROP_MEMBERSHIP);
109	case LINUX_IP_HDRINCL:
110		return (IP_HDRINCL);
111	}
112	return (-1);
113}
114
115static int
116linux_to_bsd_so_sockopt(int opt)
117{
118
119	switch (opt) {
120	case LINUX_SO_DEBUG:
121		return (SO_DEBUG);
122	case LINUX_SO_REUSEADDR:
123		return (SO_REUSEADDR);
124	case LINUX_SO_TYPE:
125		return (SO_TYPE);
126	case LINUX_SO_ERROR:
127		return (SO_ERROR);
128	case LINUX_SO_DONTROUTE:
129		return (SO_DONTROUTE);
130	case LINUX_SO_BROADCAST:
131		return (SO_BROADCAST);
132	case LINUX_SO_SNDBUF:
133		return (SO_SNDBUF);
134	case LINUX_SO_RCVBUF:
135		return (SO_RCVBUF);
136	case LINUX_SO_KEEPALIVE:
137		return (SO_KEEPALIVE);
138	case LINUX_SO_OOBINLINE:
139		return (SO_OOBINLINE);
140	case LINUX_SO_LINGER:
141		return (SO_LINGER);
142	}
143	return (-1);
144}
145
146static int
147linux_to_bsd_msg_flags(int flags)
148{
149	int ret_flags = 0;
150
151	if (flags & LINUX_MSG_OOB)
152		ret_flags |= MSG_OOB;
153	if (flags & LINUX_MSG_PEEK)
154		ret_flags |= MSG_PEEK;
155	if (flags & LINUX_MSG_DONTROUTE)
156		ret_flags |= MSG_DONTROUTE;
157	if (flags & LINUX_MSG_CTRUNC)
158		ret_flags |= MSG_CTRUNC;
159	if (flags & LINUX_MSG_TRUNC)
160		ret_flags |= MSG_TRUNC;
161	if (flags & LINUX_MSG_DONTWAIT)
162		ret_flags |= MSG_DONTWAIT;
163	if (flags & LINUX_MSG_EOR)
164		ret_flags |= MSG_EOR;
165	if (flags & LINUX_MSG_WAITALL)
166		ret_flags |= MSG_WAITALL;
167#if 0 /* not handled */
168	if (flags & LINUX_MSG_PROXY)
169		;
170	if (flags & LINUX_MSG_FIN)
171		;
172	if (flags & LINUX_MSG_SYN)
173		;
174	if (flags & LINUX_MSG_CONFIRM)
175		;
176	if (flags & LINUX_MSG_RST)
177		;
178	if (flags & LINUX_MSG_ERRQUEUE)
179		;
180	if (flags & LINUX_MSG_NOSIGNAL)
181		;
182#endif
183	return ret_flags;
184}
185
186/* Return 0 if IP_HDRINCL is set for the given socket. */
187static int
188linux_check_hdrincl(struct proc *p, int s)
189{
190	struct getsockopt_args /* {
191		int s;
192		int level;
193		int name;
194		caddr_t val;
195		int *avalsize;
196	} */ bsd_args;
197	int error;
198	caddr_t sg, val, valsize;
199	int size_val = sizeof val;
200	int optval;
201
202	sg = stackgap_init();
203	val = stackgap_alloc(&sg, sizeof(int));
204	valsize = stackgap_alloc(&sg, sizeof(int));
205
206	if ((error = copyout(&size_val, valsize, sizeof(size_val))))
207		return (error);
208
209	bsd_args.s = s;
210	bsd_args.level = IPPROTO_IP;
211	bsd_args.name = IP_HDRINCL;
212	bsd_args.val = val;
213	bsd_args.avalsize = (int *)valsize;
214	if ((error = getsockopt(p, &bsd_args)))
215		return (error);
216
217	if ((error = copyin(val, &optval, sizeof(optval))))
218		return (error);
219
220	return (optval == 0);
221}
222
223/*
224 * Updated sendto() when IP_HDRINCL is set:
225 * tweak endian-dependent fields in the IP packet.
226 */
227static int
228linux_sendto_hdrincl(struct proc *p, struct sendto_args *bsd_args)
229{
230/*
231 * linux_ip_copysize defines how many bytes we should copy
232 * from the beginning of the IP packet before we customize it for BSD.
233 * It should include all the fields we modify (ip_len and ip_off)
234 * and be as small as possible to minimize copying overhead.
235 */
236#define linux_ip_copysize	8
237
238	caddr_t sg;
239	struct ip *packet;
240	struct msghdr *msg;
241	struct iovec *iov;
242
243	int error;
244	struct  sendmsg_args /* {
245		int s;
246		caddr_t msg;
247		int flags;
248	} */ sendmsg_args;
249
250	/* Check the packet isn't too small before we mess with it */
251	if (bsd_args->len < linux_ip_copysize)
252		return (EINVAL);
253
254	/*
255	 * Tweaking the user buffer in place would be bad manners.
256	 * We create a corrected IP header with just the needed length,
257	 * then use an iovec to glue it to the rest of the user packet
258	 * when calling sendmsg().
259	 */
260	sg = stackgap_init();
261	packet = (struct ip *)stackgap_alloc(&sg, linux_ip_copysize);
262	msg = (struct msghdr *)stackgap_alloc(&sg, sizeof(*msg));
263	iov = (struct iovec *)stackgap_alloc(&sg, sizeof(*iov)*2);
264
265	/* Make a copy of the beginning of the packet to be sent */
266	if ((error = copyin(bsd_args->buf, packet, linux_ip_copysize)))
267		return (error);
268
269	/* Convert fields from Linux to BSD raw IP socket format */
270	packet->ip_len = bsd_args->len;
271	packet->ip_off = ntohs(packet->ip_off);
272
273	/* Prepare the msghdr and iovec structures describing the new packet */
274	msg->msg_name = bsd_args->to;
275	msg->msg_namelen = bsd_args->tolen;
276	msg->msg_iov = iov;
277	msg->msg_iovlen = 2;
278	msg->msg_control = NULL;
279	msg->msg_controllen = 0;
280	msg->msg_flags = 0;
281	iov[0].iov_base = (char *)packet;
282	iov[0].iov_len = linux_ip_copysize;
283	iov[1].iov_base = (char *)(bsd_args->buf) + linux_ip_copysize;
284	iov[1].iov_len = bsd_args->len - linux_ip_copysize;
285
286	sendmsg_args.s = bsd_args->s;
287	sendmsg_args.msg = (caddr_t)msg;
288	sendmsg_args.flags = bsd_args->flags;
289	return (sendmsg(p, &sendmsg_args));
290}
291
292struct linux_socket_args {
293	int domain;
294	int type;
295	int protocol;
296};
297
298static int
299linux_socket(struct proc *p, struct linux_socket_args *args)
300{
301	struct linux_socket_args linux_args;
302	struct socket_args /* {
303		int domain;
304		int type;
305		int protocol;
306	} */ bsd_args;
307	int error;
308	int retval_socket;
309
310	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
311		return (error);
312
313	bsd_args.protocol = linux_args.protocol;
314	bsd_args.type = linux_args.type;
315	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
316	if (bsd_args.domain == -1)
317		return (EINVAL);
318
319	retval_socket = socket(p, &bsd_args);
320	if (bsd_args.type == SOCK_RAW
321	    && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
322	    && bsd_args.domain == AF_INET
323	    && retval_socket >= 0) {
324		/* It's a raw IP socket: set the IP_HDRINCL option. */
325		struct setsockopt_args /* {
326			int s;
327			int level;
328			int name;
329			caddr_t val;
330			int valsize;
331		} */ bsd_setsockopt_args;
332		caddr_t sg;
333		int *hdrincl;
334
335		sg = stackgap_init();
336		hdrincl = (int *)stackgap_alloc(&sg, sizeof(*hdrincl));
337		*hdrincl = 1;
338		bsd_setsockopt_args.s = p->p_retval[0];
339		bsd_setsockopt_args.level = IPPROTO_IP;
340		bsd_setsockopt_args.name = IP_HDRINCL;
341		bsd_setsockopt_args.val = (caddr_t)hdrincl;
342		bsd_setsockopt_args.valsize = sizeof(*hdrincl);
343		/* We ignore any error returned by setsockopt() */
344		setsockopt(p, &bsd_setsockopt_args);
345		/* Copy back the return value from socket() */
346		p->p_retval[0] = bsd_setsockopt_args.s;
347	}
348
349	return (retval_socket);
350}
351
352struct linux_bind_args {
353	int s;
354	struct sockaddr *name;
355	int namelen;
356};
357
358static int
359linux_bind(struct proc *p, struct linux_bind_args *args)
360{
361	struct linux_bind_args linux_args;
362	struct bind_args /* {
363		int s;
364		caddr_t name;
365		int namelen;
366	} */ bsd_args;
367	int error;
368
369	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
370		return (error);
371
372	bsd_args.s = linux_args.s;
373	bsd_args.name = (caddr_t)linux_args.name;
374	bsd_args.namelen = linux_args.namelen;
375	return (bind(p, &bsd_args));
376}
377
378struct linux_connect_args {
379	int s;
380	struct sockaddr * name;
381	int namelen;
382};
383int linux_connect(struct proc *, struct linux_connect_args *);
384#endif /* !__alpha__*/
385
386int
387linux_connect(struct proc *p, struct linux_connect_args *args)
388{
389	struct linux_connect_args linux_args;
390	struct connect_args /* {
391		int s;
392		caddr_t name;
393		int namelen;
394	} */ bsd_args;
395	int error;
396
397#ifdef __alpha__
398	bcopy(args, &linux_args, sizeof(linux_args));
399#else
400	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
401		return (error);
402#endif /* __alpha__ */
403
404	bsd_args.s = linux_args.s;
405	bsd_args.name = (caddr_t)linux_args.name;
406	bsd_args.namelen = linux_args.namelen;
407	error = connect(p, &bsd_args);
408	if (error == EISCONN) {
409		/*
410		 * Linux doesn't return EISCONN the first time it occurs,
411		 * when on a non-blocking socket. Instead it returns the
412		 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
413		 */
414		struct fcntl_args /* {
415			int fd;
416			int cmd;
417			int arg;
418		} */ bsd_fcntl_args;
419		struct getsockopt_args /* {
420			int s;
421			int level;
422			int name;
423			caddr_t val;
424			int *avalsize;
425		} */ bsd_getsockopt_args;
426		void *status, *statusl;
427		int stat, statl = sizeof stat;
428		caddr_t sg;
429
430		/* Check for non-blocking */
431		bsd_fcntl_args.fd = linux_args.s;
432		bsd_fcntl_args.cmd = F_GETFL;
433		bsd_fcntl_args.arg = 0;
434		error = fcntl(p, &bsd_fcntl_args);
435		if (error == 0 && (p->p_retval[0] & O_NONBLOCK)) {
436			sg = stackgap_init();
437			status = stackgap_alloc(&sg, sizeof stat);
438			statusl = stackgap_alloc(&sg, sizeof statusl);
439
440			if ((error = copyout(&statl, statusl, sizeof statl)))
441				return (error);
442
443			bsd_getsockopt_args.s = linux_args.s;
444			bsd_getsockopt_args.level = SOL_SOCKET;
445			bsd_getsockopt_args.name = SO_ERROR;
446			bsd_getsockopt_args.val = status;
447			bsd_getsockopt_args.avalsize = statusl;
448
449			error = getsockopt(p, &bsd_getsockopt_args);
450			if (error)
451				return (error);
452
453			if ((error = copyin(status, &stat, sizeof stat)))
454				return (error);
455
456			p->p_retval[0] = stat;
457			return (0);
458		}
459	}
460
461	return (error);
462}
463
464#ifndef __alpha__
465
466struct linux_listen_args {
467	int s;
468	int backlog;
469};
470
471static int
472linux_listen(struct proc *p, struct linux_listen_args *args)
473{
474	struct linux_listen_args linux_args;
475	struct listen_args /* {
476		int s;
477		int backlog;
478	} */ bsd_args;
479	int error;
480
481	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
482		return (error);
483
484	bsd_args.s = linux_args.s;
485	bsd_args.backlog = linux_args.backlog;
486	return (listen(p, &bsd_args));
487}
488
489struct linux_accept_args {
490	int s;
491	struct sockaddr *addr;
492	int *namelen;
493};
494
495static int
496linux_accept(struct proc *p, struct linux_accept_args *args)
497{
498	struct linux_accept_args linux_args;
499	struct accept_args /* {
500		int s;
501		caddr_t name;
502		int *anamelen;
503	} */ bsd_args;
504	struct fcntl_args /* {
505		int fd;
506		int cmd;
507		long arg;
508	} */ f_args;
509	int error;
510
511	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
512		return (error);
513
514	bsd_args.s = linux_args.s;
515	bsd_args.name = (caddr_t)linux_args.addr;
516	bsd_args.anamelen = linux_args.namelen;
517	error = oaccept(p, &bsd_args);
518	if (error)
519		return (error);
520
521	/*
522	 * linux appears not to copy flags from the parent socket to the
523	 * accepted one, so we must clear the flags in the new descriptor.
524	 * Ignore any errors, because we already have an open fd.
525	 */
526	f_args.fd = p->p_retval[0];
527	f_args.cmd = F_SETFL;
528	f_args.arg = 0;
529	(void)fcntl(p, &f_args);
530	p->p_retval[0] = f_args.fd;
531	return (0);
532}
533
534struct linux_getsockname_args {
535	int s;
536	struct sockaddr *addr;
537	int *namelen;
538};
539
540static int
541linux_getsockname(struct proc *p, struct linux_getsockname_args *args)
542{
543	struct linux_getsockname_args linux_args;
544	struct getsockname_args /* {
545		int fdes;
546		caddr_t asa;
547		int *alen;
548	} */ bsd_args;
549	int error;
550
551	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
552		return (error);
553
554	bsd_args.fdes = linux_args.s;
555	bsd_args.asa = (caddr_t) linux_args.addr;
556	bsd_args.alen = linux_args.namelen;
557	return (ogetsockname(p, &bsd_args));
558}
559
560struct linux_getpeername_args {
561	int s;
562	struct sockaddr *addr;
563	int *namelen;
564};
565
566static int
567linux_getpeername(struct proc *p, struct linux_getpeername_args *args)
568{
569	struct linux_getpeername_args linux_args;
570	struct ogetpeername_args /* {
571		int fdes;
572		caddr_t asa;
573		int *alen;
574	} */ bsd_args;
575	int error;
576
577	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
578		return (error);
579
580	bsd_args.fdes = linux_args.s;
581	bsd_args.asa = (caddr_t) linux_args.addr;
582	bsd_args.alen = linux_args.namelen;
583	return (ogetpeername(p, &bsd_args));
584}
585
586struct linux_socketpair_args {
587	int domain;
588	int type;
589	int protocol;
590	int *rsv;
591};
592
593static int
594linux_socketpair(struct proc *p, struct linux_socketpair_args *args)
595{
596	struct linux_socketpair_args linux_args;
597	struct socketpair_args /* {
598		int domain;
599		int type;
600		int protocol;
601		int *rsv;
602	} */ bsd_args;
603	int error;
604
605	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
606		return (error);
607
608	bsd_args.domain = linux_to_bsd_domain(linux_args.domain);
609	if (bsd_args.domain == -1)
610		return (EINVAL);
611
612	bsd_args.type = linux_args.type;
613	bsd_args.protocol = linux_args.protocol;
614	bsd_args.rsv = linux_args.rsv;
615	return (socketpair(p, &bsd_args));
616}
617
618struct linux_send_args {
619	int s;
620	void *msg;
621	int len;
622	int flags;
623};
624
625static int
626linux_send(struct proc *p, struct linux_send_args *args)
627{
628	struct linux_send_args linux_args;
629	struct osend_args /* {
630		int s;
631		caddr_t buf;
632		int len;
633		int flags;
634	} */ bsd_args;
635	int error;
636
637	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
638		return (error);
639
640	bsd_args.s = linux_args.s;
641	bsd_args.buf = linux_args.msg;
642	bsd_args.len = linux_args.len;
643	bsd_args.flags = linux_args.flags;
644	return (osend(p, &bsd_args));
645}
646
647struct linux_recv_args {
648	int s;
649	void *msg;
650	int len;
651	int flags;
652};
653
654static int
655linux_recv(struct proc *p, struct linux_recv_args *args)
656{
657	struct linux_recv_args linux_args;
658	struct orecv_args /* {
659		int s;
660		caddr_t buf;
661		int len;
662		int flags;
663	} */ bsd_args;
664	int error;
665
666	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
667		return (error);
668
669	bsd_args.s = linux_args.s;
670	bsd_args.buf = linux_args.msg;
671	bsd_args.len = linux_args.len;
672	bsd_args.flags = linux_args.flags;
673	return (orecv(p, &bsd_args));
674}
675
676struct linux_sendto_args {
677	int s;
678	void *msg;
679	int len;
680	int flags;
681	caddr_t to;
682	int tolen;
683};
684
685static int
686linux_sendto(struct proc *p, struct linux_sendto_args *args)
687{
688	struct linux_sendto_args linux_args;
689	struct sendto_args /* {
690		int s;
691		caddr_t buf;
692		size_t len;
693		int flags;
694		caddr_t to;
695		int tolen;
696	} */ bsd_args;
697	int error;
698
699	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
700		return (error);
701
702	bsd_args.s = linux_args.s;
703	bsd_args.buf = linux_args.msg;
704	bsd_args.len = linux_args.len;
705	bsd_args.flags = linux_args.flags;
706	bsd_args.to = linux_args.to;
707	bsd_args.tolen = linux_args.tolen;
708
709	if (linux_check_hdrincl(p, linux_args.s) == 0)
710		/* IP_HDRINCL set, tweak the packet before sending */
711		return (linux_sendto_hdrincl(p, &bsd_args));
712
713	return (sendto(p, &bsd_args));
714}
715
716struct linux_recvfrom_args {
717	int s;
718	void *buf;
719	int len;
720	int flags;
721	caddr_t from;
722	int *fromlen;
723};
724
725static int
726linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args)
727{
728	struct linux_recvfrom_args linux_args;
729	struct recvfrom_args /* {
730		int s;
731		caddr_t buf;
732		size_t len;
733		int flags;
734		caddr_t from;
735		int *fromlenaddr;
736	} */ bsd_args;
737	int error;
738
739	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
740		return (error);
741
742	bsd_args.s = linux_args.s;
743	bsd_args.buf = linux_args.buf;
744	bsd_args.len = linux_args.len;
745	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
746	bsd_args.from = linux_args.from;
747	bsd_args.fromlenaddr = linux_args.fromlen;
748	return (orecvfrom(p, &bsd_args));
749}
750
751struct linux_recvmsg_args {
752	int s;
753	struct msghdr *msg;
754	int flags;
755};
756
757static int
758linux_recvmsg(struct proc *p, struct linux_recvmsg_args *args)
759{
760	struct linux_recvmsg_args linux_args;
761	struct recvmsg_args /* {
762		int	s;
763		struct	msghdr *msg;
764		int	flags;
765	} */ bsd_args;
766	int error;
767
768	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
769		return (error);
770
771	bsd_args.s = linux_args.s;
772	bsd_args.msg = linux_args.msg;
773	bsd_args.flags = linux_to_bsd_msg_flags(linux_args.flags);
774	return (recvmsg(p, &bsd_args));
775}
776
777struct linux_shutdown_args {
778	int s;
779	int how;
780};
781
782static int
783linux_shutdown(struct proc *p, struct linux_shutdown_args *args)
784{
785	struct linux_shutdown_args linux_args;
786	struct shutdown_args /* {
787		int s;
788		int how;
789	} */ bsd_args;
790	int error;
791
792	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
793		return (error);
794
795	bsd_args.s = linux_args.s;
796	bsd_args.how = linux_args.how;
797	return (shutdown(p, &bsd_args));
798}
799
800struct linux_setsockopt_args {
801	int s;
802	int level;
803	int optname;
804	void *optval;
805	int optlen;
806};
807
808static int
809linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args)
810{
811	struct linux_setsockopt_args linux_args;
812	struct setsockopt_args /* {
813		int s;
814		int level;
815		int name;
816		caddr_t val;
817		int valsize;
818	} */ bsd_args;
819	int error, name;
820
821	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
822		return (error);
823
824	bsd_args.s = linux_args.s;
825	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
826	switch (bsd_args.level) {
827	case SOL_SOCKET:
828		name = linux_to_bsd_so_sockopt(linux_args.optname);
829		break;
830	case IPPROTO_IP:
831		name = linux_to_bsd_ip_sockopt(linux_args.optname);
832		break;
833	case IPPROTO_TCP:
834		/* Linux TCP option values match BSD's */
835		name = linux_args.optname;
836		break;
837	default:
838		name = -1;
839		break;
840	}
841	if (name == -1)
842		return (EINVAL);
843
844	bsd_args.name = name;
845	bsd_args.val = linux_args.optval;
846	bsd_args.valsize = linux_args.optlen;
847	return (setsockopt(p, &bsd_args));
848}
849
850struct linux_getsockopt_args {
851	int s;
852	int level;
853	int optname;
854	void *optval;
855	int *optlen;
856};
857
858static int
859linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args)
860{
861	struct linux_getsockopt_args linux_args;
862	struct getsockopt_args /* {
863		int s;
864		int level;
865		int name;
866		caddr_t val;
867		int *avalsize;
868	} */ bsd_args;
869	int error, name;
870
871	if ((error = copyin(args, &linux_args, sizeof(linux_args))))
872		return (error);
873
874	bsd_args.s = linux_args.s;
875	bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level);
876	switch (bsd_args.level) {
877	case SOL_SOCKET:
878		name = linux_to_bsd_so_sockopt(linux_args.optname);
879		break;
880	case IPPROTO_IP:
881		name = linux_to_bsd_ip_sockopt(linux_args.optname);
882		break;
883	case IPPROTO_TCP:
884		/* Linux TCP option values match BSD's */
885		name = linux_args.optname;
886		break;
887	default:
888		name = -1;
889		break;
890	}
891	if (name == -1)
892		return (EINVAL);
893
894	bsd_args.name = name;
895	bsd_args.val = linux_args.optval;
896	bsd_args.avalsize = linux_args.optlen;
897	return (getsockopt(p, &bsd_args));
898}
899
900int
901linux_socketcall(struct proc *p, struct linux_socketcall_args *args)
902{
903
904	switch (args->what) {
905	case LINUX_SOCKET:
906		return (linux_socket(p, args->args));
907	case LINUX_BIND:
908		return (linux_bind(p, args->args));
909	case LINUX_CONNECT:
910		return (linux_connect(p, args->args));
911	case LINUX_LISTEN:
912		return (linux_listen(p, args->args));
913	case LINUX_ACCEPT:
914		return (linux_accept(p, args->args));
915	case LINUX_GETSOCKNAME:
916		return (linux_getsockname(p, args->args));
917	case LINUX_GETPEERNAME:
918		return (linux_getpeername(p, args->args));
919	case LINUX_SOCKETPAIR:
920		return (linux_socketpair(p, args->args));
921	case LINUX_SEND:
922		return (linux_send(p, args->args));
923	case LINUX_RECV:
924		return (linux_recv(p, args->args));
925	case LINUX_SENDTO:
926		return (linux_sendto(p, args->args));
927	case LINUX_RECVFROM:
928		return (linux_recvfrom(p, args->args));
929	case LINUX_SHUTDOWN:
930		return (linux_shutdown(p, args->args));
931	case LINUX_SETSOCKOPT:
932		return (linux_setsockopt(p, args->args));
933	case LINUX_GETSOCKOPT:
934		return (linux_getsockopt(p, args->args));
935	case LINUX_SENDMSG:
936		do {
937			int error;
938			int level;
939			caddr_t control;
940			struct {
941				int s;
942				const struct msghdr *msg;
943				int flags;
944			} *uap = args->args;
945
946			error = copyin(&uap->msg->msg_control, &control,
947			    sizeof(caddr_t));
948			if (error)
949				return (error);
950
951			if (control == NULL)
952				goto done;
953
954			error = copyin(&((struct cmsghdr*)control)->cmsg_level,
955			    &level, sizeof(int));
956			if (error)
957				return (error);
958
959			if (level == 1) {
960				/*
961				 * Linux thinks that SOL_SOCKET is 1; we know
962				 * that it's really 0xffff, of course.
963				 */
964				level = SOL_SOCKET;
965				error = copyout(&level,
966				    &((struct cmsghdr *)control)->cmsg_level,
967				    sizeof(int));
968				if (error)
969					return (error);
970			}
971		done:
972			return (sendmsg(p, args->args));
973		} while (0);
974	case LINUX_RECVMSG:
975		return (linux_recvmsg(p, args->args));
976	}
977
978	uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
979	return (ENOSYS);
980}
981#endif	/*!__alpha__*/
982