xref: /freebsd/sys/compat/linux/linux_socket.c (revision cdee49f9867734b89831039db7f39baa0b1f9412)
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/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__
56 static int
57 linux_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 
77 static int
78 linux_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 
88 static int
89 linux_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 
115 static int
116 linux_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 
146 static int
147 linux_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. */
187 static int
188 linux_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  */
227 static int
228 linux_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 
292 struct linux_socket_args {
293 	int domain;
294 	int type;
295 	int protocol;
296 };
297 
298 static int
299 linux_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 
352 struct linux_bind_args {
353 	int s;
354 	struct sockaddr *name;
355 	int namelen;
356 };
357 
358 static int
359 linux_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 
378 struct linux_connect_args {
379 	int s;
380 	struct sockaddr * name;
381 	int namelen;
382 };
383 int linux_connect(struct proc *, struct linux_connect_args *);
384 #endif /* !__alpha__*/
385 
386 int
387 linux_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 
466 struct linux_listen_args {
467 	int s;
468 	int backlog;
469 };
470 
471 static int
472 linux_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 
489 struct linux_accept_args {
490 	int s;
491 	struct sockaddr *addr;
492 	int *namelen;
493 };
494 
495 static int
496 linux_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 
534 struct linux_getsockname_args {
535 	int s;
536 	struct sockaddr *addr;
537 	int *namelen;
538 };
539 
540 static int
541 linux_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 
560 struct linux_getpeername_args {
561 	int s;
562 	struct sockaddr *addr;
563 	int *namelen;
564 };
565 
566 static int
567 linux_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 
586 struct linux_socketpair_args {
587 	int domain;
588 	int type;
589 	int protocol;
590 	int *rsv;
591 };
592 
593 static int
594 linux_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 
618 struct linux_send_args {
619 	int s;
620 	void *msg;
621 	int len;
622 	int flags;
623 };
624 
625 static int
626 linux_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 
647 struct linux_recv_args {
648 	int s;
649 	void *msg;
650 	int len;
651 	int flags;
652 };
653 
654 static int
655 linux_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 
676 struct linux_sendto_args {
677 	int s;
678 	void *msg;
679 	int len;
680 	int flags;
681 	caddr_t to;
682 	int tolen;
683 };
684 
685 static int
686 linux_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 
716 struct linux_recvfrom_args {
717 	int s;
718 	void *buf;
719 	int len;
720 	int flags;
721 	caddr_t from;
722 	int *fromlen;
723 };
724 
725 static int
726 linux_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 
751 struct linux_recvmsg_args {
752 	int s;
753 	struct msghdr *msg;
754 	int flags;
755 };
756 
757 static int
758 linux_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 
777 struct linux_shutdown_args {
778 	int s;
779 	int how;
780 };
781 
782 static int
783 linux_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 
800 struct linux_setsockopt_args {
801 	int s;
802 	int level;
803 	int optname;
804 	void *optval;
805 	int optlen;
806 };
807 
808 static int
809 linux_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 
850 struct linux_getsockopt_args {
851 	int s;
852 	int level;
853 	int optname;
854 	void *optval;
855 	int *optlen;
856 };
857 
858 static int
859 linux_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 
900 int
901 linux_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