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