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