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