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