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 without 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: src/sys/compat/linux/linux_socket.c,v 1.19.2.8 2001/11/07 20:33:55 marcel Exp $
29 */
30
31 #include <sys/param.h>
32 #include <sys/proc.h>
33 #include <sys/systm.h>
34 #include <sys/sysproto.h>
35 #include <sys/fcntl.h>
36 #include <sys/file.h>
37 #include <sys/kern_syscall.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
40 #include <sys/uio.h>
41 #include <sys/malloc.h>
42 #include <sys/mbuf.h>
43 #include <sys/un.h>
44
45 #include <sys/mplock2.h>
46
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/ip.h>
50
51 #include <arch_linux/linux.h>
52 #include <arch_linux/linux_proto.h>
53 #include "linux_socket.h"
54 #include "linux_util.h"
55
56 /*
57 * Copyin a sockaddr structure provided by a Linux binary. Linux uses
58 * the 4.3BSD sockaddr structure which has no sa_len field. We must
59 * pass 4.4BSD sockaddr structures when we call native functions in the
60 * BSD kernel. This function does the conversion for us.
61 *
62 * Also, our socket calls require the sockaddr structure length to agree
63 * with the address family. Linux does not, so we must force it.
64 *
65 * This function should only need to be called from linux_connect()
66 * and linux_bind().
67 */
68 static int
69 linux_getsockaddr(struct sockaddr **namp, struct sockaddr *uaddr, size_t len)
70 {
71 struct sockaddr *sa;
72 uint16_t family; /* XXX: must match Linux sockaddr */
73 int error;
74 int sa_len;
75
76 *namp = NULL;
77
78 if (len > SOCK_MAXADDRLEN)
79 return ENAMETOOLONG;
80 error = copyin(uaddr, &family, sizeof(family));
81 if (error)
82 return (error);
83
84 /*
85 * Force the sa_len field to match the address family.
86 */
87 switch (family) {
88 case AF_INET:
89 sa_len = sizeof(struct sockaddr_in);
90 break;
91 case AF_INET6:
92 sa_len = sizeof(struct sockaddr_in6);
93 break;
94 default:
95 /*
96 * This is the default behavior of the old
97 * linux_to_bsd_namelen() function. NOTE! The
98 * minimum length we allocate must cover sa->sa_len and
99 * sa->sa_family.
100 */
101 sa_len = offsetof(struct sockaddr, sa_data[0]);
102 if (sa_len < len)
103 sa_len = len;
104 break;
105 }
106
107 sa = kmalloc(sa_len, M_SONAME, M_WAITOK);
108 error = copyin(uaddr, sa, sa_len);
109 if (error) {
110 kfree(sa, M_SONAME);
111 } else {
112 /*
113 * Convert to the 4.4BSD sockaddr structure.
114 */
115 sa->sa_family = *(sa_family_t *)sa;
116 sa->sa_len = sa_len;
117 *namp = sa;
118 }
119
120 return (error);
121 }
122
123 /*
124 * Transform a 4.4BSD sockaddr structure into a Linux sockaddr structure
125 * and copy it out to a user address.
126 */
127 static int
128 linux_copyout_sockaddr(struct sockaddr *sa, struct sockaddr *uaddr, int sa_len)
129 {
130 int error;
131
132 if (sa_len < (int)sizeof(u_short))
133 return (EINVAL);
134
135 *(u_short *)sa = sa->sa_family;
136 error = copyout(sa, uaddr, sa_len);
137
138 return (error);
139 }
140
141 static int
142 linux_to_bsd_domain(int domain)
143 {
144
145 switch (domain) {
146 case LINUX_AF_UNSPEC:
147 return (AF_UNSPEC);
148 case LINUX_AF_UNIX:
149 return (AF_LOCAL);
150 case LINUX_AF_INET:
151 return (AF_INET);
152 case LINUX_AF_AX25:
153 return (AF_CCITT);
154 case LINUX_AF_IPX:
155 return (AF_IPX);
156 }
157 return (-1);
158 }
159
160 static int
161 linux_to_bsd_sockopt_level(int level)
162 {
163
164 switch (level) {
165 case LINUX_SOL_SOCKET:
166 return (SOL_SOCKET);
167 }
168 return (level);
169 }
170
171 static int
172 linux_to_bsd_ip_sockopt(int opt)
173 {
174
175 switch (opt) {
176 case LINUX_IP_TOS:
177 return (IP_TOS);
178 case LINUX_IP_TTL:
179 return (IP_TTL);
180 case LINUX_IP_OPTIONS:
181 return (IP_OPTIONS);
182 case LINUX_IP_MULTICAST_IF:
183 return (IP_MULTICAST_IF);
184 case LINUX_IP_MULTICAST_TTL:
185 return (IP_MULTICAST_TTL);
186 case LINUX_IP_MULTICAST_LOOP:
187 return (IP_MULTICAST_LOOP);
188 case LINUX_IP_ADD_MEMBERSHIP:
189 return (IP_ADD_MEMBERSHIP);
190 case LINUX_IP_DROP_MEMBERSHIP:
191 return (IP_DROP_MEMBERSHIP);
192 case LINUX_IP_HDRINCL:
193 return (IP_HDRINCL);
194 }
195 return (-1);
196 }
197
198 static int
199 linux_to_bsd_so_sockopt(int opt)
200 {
201
202 switch (opt) {
203 case LINUX_SO_DEBUG:
204 return (SO_DEBUG);
205 case LINUX_SO_REUSEADDR:
206 return (SO_REUSEADDR);
207 case LINUX_SO_TYPE:
208 return (SO_TYPE);
209 case LINUX_SO_ERROR:
210 return (SO_ERROR);
211 case LINUX_SO_DONTROUTE:
212 return (SO_DONTROUTE);
213 case LINUX_SO_BROADCAST:
214 return (SO_BROADCAST);
215 case LINUX_SO_SNDBUF:
216 return (SO_SNDBUF);
217 case LINUX_SO_RCVBUF:
218 return (SO_RCVBUF);
219 case LINUX_SO_KEEPALIVE:
220 return (SO_KEEPALIVE);
221 case LINUX_SO_OOBINLINE:
222 return (SO_OOBINLINE);
223 case LINUX_SO_LINGER:
224 return (SO_LINGER);
225 case LINUX_SO_PEERCRED:
226 return (LOCAL_PEERCRED);
227 }
228 return (-1);
229 }
230
231 static int
232 linux_to_bsd_msg_flags(int flags)
233 {
234 int ret_flags = 0;
235
236 if (flags & LINUX_MSG_OOB)
237 ret_flags |= MSG_OOB;
238 if (flags & LINUX_MSG_PEEK)
239 ret_flags |= MSG_PEEK;
240 if (flags & LINUX_MSG_DONTROUTE)
241 ret_flags |= MSG_DONTROUTE;
242 if (flags & LINUX_MSG_CTRUNC)
243 ret_flags |= MSG_CTRUNC;
244 if (flags & LINUX_MSG_TRUNC)
245 ret_flags |= MSG_TRUNC;
246 if (flags & LINUX_MSG_DONTWAIT)
247 ret_flags |= MSG_DONTWAIT;
248 if (flags & LINUX_MSG_EOR)
249 ret_flags |= MSG_EOR;
250 if (flags & LINUX_MSG_WAITALL)
251 ret_flags |= MSG_WAITALL;
252 #if 0 /* not handled */
253 if (flags & LINUX_MSG_PROXY)
254 ;
255 if (flags & LINUX_MSG_FIN)
256 ;
257 if (flags & LINUX_MSG_SYN)
258 ;
259 if (flags & LINUX_MSG_CONFIRM)
260 ;
261 if (flags & LINUX_MSG_RST)
262 ;
263 if (flags & LINUX_MSG_ERRQUEUE)
264 ;
265 if (flags & LINUX_MSG_NOSIGNAL)
266 ;
267 #endif
268 return ret_flags;
269 }
270
271 struct linux_socket_args {
272 int domain;
273 int type;
274 int protocol;
275 };
276
277 static int
278 linux_socket(struct linux_socket_args *args, int *res)
279 {
280 struct linux_socket_args linux_args;
281 struct sockopt sopt;
282 int error, domain, optval;
283
284 error = copyin(args, &linux_args, sizeof(linux_args));
285 if (error)
286 return (error);
287
288 domain = linux_to_bsd_domain(linux_args.domain);
289 if (domain == -1)
290 return (EINVAL);
291
292 error = kern_socket(domain, linux_args.type, linux_args.protocol, res);
293
294 /* Copy back the return value from socket() */
295 if (error == 0 && linux_args.type == SOCK_RAW &&
296 (linux_args.protocol == IPPROTO_RAW || linux_args.protocol == 0) &&
297 linux_args.domain == AF_INET) {
298 /* It's a raw IP socket: set the IP_HDRINCL option. */
299 optval = 1;
300 sopt.sopt_dir = SOPT_SET;
301 sopt.sopt_level = IPPROTO_IP;
302 sopt.sopt_name = IP_HDRINCL;
303 sopt.sopt_val = &optval;
304 sopt.sopt_valsize = sizeof(optval);
305 sopt.sopt_td = NULL;
306
307 /* We ignore any error returned by setsockopt() */
308 kern_setsockopt(*res, &sopt);
309 }
310
311 return (error);
312 }
313
314 struct linux_bind_args {
315 int s;
316 struct sockaddr *name;
317 int namelen;
318 };
319
320 static int
321 linux_bind(struct linux_bind_args *args, int *res)
322 {
323 struct linux_bind_args linux_args;
324 struct sockaddr *sa;
325 int error;
326
327 error = copyin(args, &linux_args, sizeof(linux_args));
328 if (error)
329 return (error);
330 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
331 if (error)
332 return (error);
333
334 error = kern_bind(linux_args.s, sa);
335 kfree(sa, M_SONAME);
336
337 return (error);
338 }
339
340 struct linux_connect_args {
341 int s;
342 struct sockaddr * name;
343 int namelen;
344 };
345
346 static int
347 linux_connect(struct linux_connect_args *args, int *res)
348 {
349 struct thread *td = curthread; /* XXX */
350 struct proc *p = td->td_proc;
351 struct linux_connect_args linux_args;
352 struct sockaddr *sa;
353 struct socket *so;
354 struct file *fp;
355 int error;
356
357 KKASSERT(p);
358
359 error = copyin(args, &linux_args, sizeof(linux_args));
360 if (error)
361 return (error);
362 error = linux_getsockaddr(&sa, linux_args.name, linux_args.namelen);
363 if (error)
364 return (error);
365
366 error = kern_connect(linux_args.s, 0, sa);
367 kfree(sa, M_SONAME);
368
369 if (error != EISCONN)
370 return (error);
371
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 error = holdsock(p->p_fd, linux_args.s, &fp);
378 if (error)
379 return (error);
380 error = EISCONN;
381 if (fp->f_flag & FNONBLOCK) {
382 so = (struct socket *)fp->f_data;
383 if (so->so_emuldata == 0)
384 error = so->so_error;
385 so->so_emuldata = (void *)1;
386 }
387 fdrop(fp);
388 return (error);
389 }
390
391 struct linux_listen_args {
392 int s;
393 int backlog;
394 };
395
396 static int
397 linux_listen(struct linux_listen_args *args, int *res)
398 {
399 struct linux_listen_args linux_args;
400 int error;
401
402 error = copyin(args, &linux_args, sizeof(linux_args));
403 if (error)
404 return (error);
405
406 error = kern_listen(linux_args.s, linux_args.backlog);
407
408 return(error);
409 }
410
411 struct linux_accept_args {
412 int s;
413 struct sockaddr *addr;
414 int *namelen;
415 };
416
417 static int
418 linux_accept(struct linux_accept_args *args, int *res)
419 {
420 struct thread *td = curthread;
421 struct linux_accept_args linux_args;
422 struct sockaddr *sa = NULL;
423 union fcntl_dat dat = { 0 };
424 int error, sa_len;
425
426 error = copyin(args, &linux_args, sizeof(linux_args));
427 if (error)
428 return (error);
429
430 if (linux_args.addr) {
431 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
432 if (error)
433 return (error);
434
435 error = kern_accept(linux_args.s, 0, &sa, &sa_len, res);
436
437 if (error) {
438 /*
439 * Return a namelen of zero for older code which
440 * might ignore the return value from accept().
441 */
442 sa_len = 0;
443 copyout(&sa_len, linux_args.namelen,
444 sizeof(*linux_args.namelen));
445 } else {
446 error = linux_copyout_sockaddr(sa, linux_args.addr,
447 sa_len);
448 if (error == 0) {
449 error = copyout(&sa_len, linux_args.namelen,
450 sizeof(*linux_args.namelen));
451 }
452 }
453 if (sa)
454 kfree(sa, M_SONAME);
455 } else {
456 error = kern_accept(linux_args.s, 0, NULL, 0, res);
457 }
458
459 if (error)
460 return (error);
461
462 /*
463 * linux appears not to copy flags from the parent socket to the
464 * accepted one, so we must clear the flags in the new descriptor.
465 * Ignore any errors, because we already have an open fd.
466 */
467 kern_fcntl(*res, F_SETFL, &dat, td->td_ucred);
468 return (0);
469 }
470
471 struct linux_getsockname_args {
472 int s;
473 struct sockaddr *addr;
474 int *namelen;
475 };
476
477 static int
478 linux_getsockname(struct linux_getsockname_args *args, int *res)
479 {
480 struct linux_getsockname_args linux_args;
481 struct sockaddr *sa = NULL;
482 int error, sa_len;
483
484
485 error = copyin(args, &linux_args, sizeof(linux_args));
486 if (error)
487 return (error);
488 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
489 if (error)
490 return (error);
491
492 error = kern_getsockname(linux_args.s, &sa, &sa_len);
493
494 if (error == 0)
495 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
496 if (error == 0)
497 error = copyout(&sa_len, linux_args.namelen,
498 sizeof(*linux_args.namelen));
499 if (sa)
500 kfree(sa, M_SONAME);
501 return(error);
502 }
503
504 struct linux_getpeername_args {
505 int s;
506 struct sockaddr *addr;
507 int *namelen;
508 };
509
510 static int
511 linux_getpeername(struct linux_getpeername_args *args, int *res)
512 {
513 struct linux_getpeername_args linux_args;
514 struct sockaddr *sa = NULL;
515 int error, sa_len;
516
517 error = copyin(args, &linux_args, sizeof(linux_args));
518 if (error)
519 return (error);
520 error = copyin(linux_args.namelen, &sa_len, sizeof(sa_len));
521 if (error)
522 return (error);
523
524 error = kern_getpeername(linux_args.s, &sa, &sa_len);
525
526 if (error == 0)
527 error = linux_copyout_sockaddr(sa, linux_args.addr, sa_len);
528 if (error == 0)
529 error = copyout(&sa_len, linux_args.namelen,
530 sizeof(*linux_args.namelen));
531 if (sa)
532 kfree(sa, M_SONAME);
533 return(error);
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 linux_socketpair_args *args, int *res)
545 {
546 struct linux_socketpair_args linux_args;
547 int error, domain, sockv[2];
548
549 error = copyin(args, &linux_args, sizeof(linux_args));
550 if (error)
551 return (error);
552
553 domain = linux_to_bsd_domain(linux_args.domain);
554 if (domain == -1)
555 return (EINVAL);
556 error = kern_socketpair(domain, linux_args.type, linux_args.protocol,
557 sockv);
558
559 if (error == 0)
560 error = copyout(sockv, linux_args.rsv, sizeof(sockv));
561 return(error);
562 }
563
564 struct linux_send_args {
565 int s;
566 void *msg;
567 int len;
568 int flags;
569 };
570
571 static int
572 linux_send(struct linux_send_args *args, size_t *res)
573 {
574 struct linux_send_args linux_args;
575 struct thread *td = curthread;
576 struct uio auio;
577 struct iovec aiov;
578 int error;
579
580 error = copyin(args, &linux_args, sizeof(linux_args));
581 if (error)
582 return (error);
583
584 aiov.iov_base = linux_args.msg;
585 aiov.iov_len = linux_args.len;
586 auio.uio_iov = &aiov;
587 auio.uio_iovcnt = 1;
588 auio.uio_offset = 0;
589 auio.uio_resid = linux_args.len;
590 auio.uio_segflg = UIO_USERSPACE;
591 auio.uio_rw = UIO_WRITE;
592 auio.uio_td = td;
593
594 error = kern_sendmsg(linux_args.s, NULL, &auio, NULL,
595 linux_args.flags, res);
596
597 return(error);
598 }
599
600 struct linux_recv_args {
601 int s;
602 void *msg;
603 int len;
604 int flags;
605 };
606
607 static int
608 linux_recv(struct linux_recv_args *args, size_t *res)
609 {
610 struct linux_recv_args linux_args;
611 struct thread *td = curthread;
612 struct uio auio;
613 struct iovec aiov;
614 int error;
615
616 error = copyin(args, &linux_args, sizeof(linux_args));
617 if (error)
618 return (error);
619
620 aiov.iov_base = linux_args.msg;
621 aiov.iov_len = linux_args.len;
622 auio.uio_iov = &aiov;
623 auio.uio_iovcnt = 1;
624 auio.uio_offset = 0;
625 auio.uio_resid = linux_args.len;
626 auio.uio_segflg = UIO_USERSPACE;
627 auio.uio_rw = UIO_READ;
628 auio.uio_td = td;
629
630 error = kern_recvmsg(linux_args.s, NULL, &auio, NULL,
631 &linux_args.flags, res);
632
633 return(error);
634 }
635
636 struct linux_sendto_args {
637 int s;
638 void *msg;
639 int len;
640 int flags;
641 struct sockaddr *to;
642 int tolen;
643 };
644
645 static int
646 linux_sendto(struct linux_sendto_args *args, size_t *res)
647 {
648 struct linux_sendto_args linux_args;
649 struct thread *td = curthread;
650 struct uio auio;
651 struct iovec aiov;
652 struct sockopt sopt;
653 struct sockaddr *sa = NULL;
654 caddr_t msg = NULL;
655 int error, optval;
656
657 error = copyin(args, &linux_args, sizeof(linux_args));
658 if (error)
659 return (error);
660
661 if (linux_args.to) {
662 error = linux_getsockaddr(&sa, linux_args.to,
663 linux_args.tolen);
664 if (error)
665 return (error);
666 }
667
668 /*
669 * Check to see if the IP_HDRINCL option is set.
670 */
671 sopt.sopt_dir = SOPT_GET;
672 sopt.sopt_level = IPPROTO_IP;
673 sopt.sopt_name = IP_HDRINCL;
674 sopt.sopt_val = &optval;
675 sopt.sopt_valsize = sizeof(optval);
676 sopt.sopt_td = NULL;
677
678 if (kern_getsockopt(linux_args.s, &sopt) != 0)
679 optval = 0;
680
681 if (optval == 0) {
682 /*
683 * IP_HDRINCL is not set. Package the message as usual.
684 */
685 aiov.iov_base = linux_args.msg;
686 aiov.iov_len = linux_args.len;
687 auio.uio_iov = &aiov;
688 auio.uio_iovcnt = 1;
689 auio.uio_offset = 0;
690 auio.uio_resid = linux_args.len;
691 auio.uio_segflg = UIO_USERSPACE;
692 auio.uio_rw = UIO_WRITE;
693 auio.uio_td = td;
694 } else {
695 /*
696 * IP_HDRINCL is set. We must convert the beginning of
697 * the packet header so we can feed it to the BSD kernel.
698 */
699
700 /*
701 * Check that the packet header is long enough to contain
702 * the fields of interest. This relies on the fact that
703 * the fragment offset field comes after the length field.
704 */
705 if (linux_args.len < offsetof(struct ip, ip_off))
706 return (EINVAL);
707
708 msg = kmalloc(linux_args.len, M_LINUX, M_WAITOK);
709 error = copyin(linux_args.msg, msg, linux_args.len);
710 if (error)
711 goto cleanup;
712
713 /* Fix the ip_len and ip_off fields. */
714 ((struct ip *)msg)->ip_len = linux_args.len;
715 ((struct ip *)msg)->ip_off = ntohs(((struct ip *)msg)->ip_off);
716
717 aiov.iov_base = msg;
718 aiov.iov_len = linux_args.len;
719 auio.uio_iov = &aiov;
720 auio.uio_iovcnt = 1;
721 auio.uio_offset = 0;
722 auio.uio_resid = linux_args.len;
723 auio.uio_segflg = UIO_SYSSPACE;
724 auio.uio_rw = UIO_WRITE;
725 auio.uio_td = td;
726 }
727
728 error = kern_sendmsg(linux_args.s, sa, &auio, NULL,
729 linux_args.flags, res);
730
731 cleanup:
732 if (sa)
733 kfree(sa, M_SONAME);
734 if (msg)
735 kfree(msg, M_LINUX);
736 return(error);
737 }
738
739 struct linux_recvfrom_args {
740 int s;
741 void *buf;
742 int len;
743 int flags;
744 struct sockaddr *from;
745 int *fromlen;
746 };
747
748 static int
749 linux_recvfrom(struct linux_recvfrom_args *args, size_t *res)
750 {
751 struct linux_recvfrom_args linux_args;
752 struct thread *td = curthread;
753 struct uio auio;
754 struct iovec aiov;
755 struct sockaddr *sa = NULL;
756 int error, fromlen, flags;
757
758 error = copyin(args, &linux_args, sizeof(linux_args));
759 if (error)
760 return (error);
761
762 if (linux_args.from && linux_args.fromlen) {
763 error = copyin(linux_args.fromlen, &fromlen, sizeof(fromlen));
764 if (error)
765 return (error);
766 if (fromlen < 0)
767 return (EINVAL);
768 } else {
769 fromlen = 0;
770 }
771 aiov.iov_base = linux_args.buf;
772 aiov.iov_len = linux_args.len;
773 auio.uio_iov = &aiov;
774 auio.uio_iovcnt = 1;
775 auio.uio_offset = 0;
776 auio.uio_resid = linux_args.len;
777 auio.uio_segflg = UIO_USERSPACE;
778 auio.uio_rw = UIO_READ;
779 auio.uio_td = td;
780
781 flags = linux_to_bsd_msg_flags(linux_args.flags);
782
783 error = kern_recvmsg(linux_args.s, linux_args.from ? &sa : NULL, &auio,
784 NULL, &flags, res);
785
786 if (error == 0 && linux_args.from) {
787 if (sa != NULL) {
788 fromlen = MIN(fromlen, sa->sa_len);
789 error = linux_copyout_sockaddr(sa, linux_args.from,
790 fromlen);
791 } else
792 fromlen = 0;
793 if (error == 0)
794 copyout(&fromlen, linux_args.fromlen,
795 sizeof(fromlen));
796 }
797 if (sa)
798 kfree(sa, M_SONAME);
799
800 return(error);
801 }
802
803 struct linux_sendmsg_args {
804 int s;
805 struct msghdr *msg;
806 int flags;
807 };
808
809 static int
810 linux_sendmsg(struct linux_sendmsg_args *args, size_t *res)
811 {
812 struct linux_sendmsg_args linux_args;
813 struct thread *td = curthread;
814 struct msghdr msg;
815 struct uio auio;
816 struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
817 struct sockaddr *sa = NULL;
818 struct mbuf *control = NULL;
819 int error;
820
821 error = copyin(args, &linux_args, sizeof(linux_args));
822 if (error)
823 return (error);
824
825 error = copyin(linux_args.msg, &msg, sizeof(msg));
826 if (error)
827 return (error);
828
829 /*
830 * XXX: I'm not sure atm how this relates to dragonfly, but
831 * just in case, I put it in.
832 * Ping on linux does pass 0 in controllen which is forbidden
833 * by FreeBSD but seems to be ok on Linux. This needs some
834 * checking but now it lets ping work.
835 */
836 if (msg.msg_control && msg.msg_controllen == 0)
837 msg.msg_control = NULL;
838
839 /*
840 * Conditionally copyin msg.msg_name.
841 */
842 if (msg.msg_name) {
843 error = linux_getsockaddr(&sa, msg.msg_name, msg.msg_namelen);
844 if (error)
845 return (error);
846 }
847
848 /*
849 * Populate auio.
850 */
851 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
852 &auio.uio_resid);
853 if (error)
854 goto cleanup2;
855 auio.uio_iov = iov;
856 auio.uio_iovcnt = msg.msg_iovlen;
857 auio.uio_offset = 0;
858 auio.uio_segflg = UIO_USERSPACE;
859 auio.uio_rw = UIO_WRITE;
860 auio.uio_td = td;
861
862 /*
863 * Conditionally copyin msg.msg_control.
864 */
865 if (msg.msg_control) {
866 if (msg.msg_controllen < sizeof(struct cmsghdr) ||
867 msg.msg_controllen > MLEN) {
868 error = EINVAL;
869 goto cleanup;
870 }
871 control = m_get(MB_WAIT, MT_CONTROL);
872 if (control == NULL) {
873 error = ENOBUFS;
874 goto cleanup;
875 }
876 control->m_len = msg.msg_controllen;
877 error = copyin(msg.msg_control, mtod(control, caddr_t),
878 msg.msg_controllen);
879 if (error) {
880 m_free(control);
881 goto cleanup;
882 }
883 /*
884 * Linux and BSD both support SCM_RIGHTS. If a linux binary
885 * wants anything else with an option level of SOL_SOCKET,
886 * we don't support it.
887 */
888 if (mtod(control, struct cmsghdr *)->cmsg_level ==
889 SOL_SOCKET &&
890 mtod(control, struct cmsghdr *)->cmsg_type !=
891 SCM_RIGHTS) {
892 m_free(control);
893 error = EINVAL;
894 goto cleanup;
895 }
896 }
897
898 error = kern_sendmsg(linux_args.s, sa, &auio, control,
899 linux_args.flags, res);
900
901 cleanup:
902 iovec_free(&iov, aiov);
903 cleanup2:
904 if (sa)
905 kfree(sa, M_SONAME);
906 return (error);
907 }
908
909 struct linux_recvmsg_args {
910 int s;
911 struct msghdr *msg;
912 int flags;
913 };
914
915 static int
916 linux_recvmsg(struct linux_recvmsg_args *args, size_t *res)
917 {
918 struct linux_recvmsg_args linux_args;
919 struct thread *td = curthread;
920 struct msghdr msg;
921 struct uio auio;
922 struct iovec aiov[UIO_SMALLIOV], *iov = NULL;
923 struct mbuf *m, *control = NULL;
924 struct sockaddr *sa = NULL;
925 caddr_t ctlbuf;
926 socklen_t *ufromlenp, *ucontrollenp;
927 int error, fromlen, controllen, len, flags, *uflagsp;
928
929 error = copyin(args, &linux_args, sizeof(linux_args));
930 if (error)
931 return (error);
932
933 error = copyin(linux_args.msg, &msg, sizeof(struct msghdr));
934 if (error)
935 return (error);
936
937 if (msg.msg_name && msg.msg_namelen < 0)
938 return (EINVAL);
939 if (msg.msg_control && msg.msg_controllen < 0)
940 return (EINVAL);
941
942 ufromlenp = (socklen_t *)((caddr_t)linux_args.msg +
943 offsetof(struct msghdr, msg_namelen));
944 ucontrollenp = (socklen_t *)((caddr_t)linux_args.msg +
945 offsetof(struct msghdr, msg_controllen));
946 uflagsp = (int *)((caddr_t)linux_args.msg +
947 offsetof(struct msghdr, msg_flags));
948
949 /*
950 * Populate auio.
951 */
952 error = iovec_copyin(msg.msg_iov, &iov, aiov, msg.msg_iovlen,
953 &auio.uio_resid);
954 if (error)
955 return (error);
956 auio.uio_iov = iov;
957 auio.uio_iovcnt = msg.msg_iovlen;
958 auio.uio_offset = 0;
959 auio.uio_segflg = UIO_USERSPACE;
960 auio.uio_rw = UIO_READ;
961 auio.uio_td = td;
962
963 flags = linux_to_bsd_msg_flags(linux_args.flags);
964
965 error = kern_recvmsg(linux_args.s, msg.msg_name ? &sa : NULL, &auio,
966 msg.msg_control ? &control : NULL, &flags, res);
967
968 /*
969 * Copyout msg.msg_name and msg.msg_namelen.
970 */
971 if (error == 0 && msg.msg_name) {
972 if (sa != NULL) {
973 fromlen = MIN(msg.msg_namelen, sa->sa_len);
974 error = linux_copyout_sockaddr(sa, msg.msg_name,
975 fromlen);
976 } else
977 fromlen = 0;
978 if (error == 0)
979 error = copyout(&fromlen, ufromlenp,
980 sizeof(*ufromlenp));
981 }
982
983 /*
984 * Copyout msg.msg_control and msg.msg_controllen.
985 */
986 if (error == 0 && msg.msg_control) {
987 /*
988 * Linux and BSD both support SCM_RIGHTS. If a linux binary
989 * wants anything else with an option level of SOL_SOCKET,
990 * we don't support it.
991 */
992 if (mtod((struct mbuf *)msg.msg_control,
993 struct cmsghdr *)->cmsg_level == SOL_SOCKET &&
994 mtod((struct mbuf *)msg.msg_control,
995 struct cmsghdr *)->cmsg_type != SCM_RIGHTS) {
996 error = EINVAL;
997 goto cleanup;
998 }
999
1000 len = msg.msg_controllen;
1001 m = control;
1002 ctlbuf = (caddr_t)msg.msg_control;
1003
1004 while (m && len > 0) {
1005 unsigned int tocopy;
1006
1007 if (len >= m->m_len) {
1008 tocopy = m->m_len;
1009 } else {
1010 msg.msg_flags |= MSG_CTRUNC;
1011 tocopy = len;
1012 }
1013
1014 error = copyout(mtod(m, caddr_t), ctlbuf,
1015 tocopy);
1016 if (error)
1017 goto cleanup;
1018
1019 ctlbuf += tocopy;
1020 len -= tocopy;
1021 m = m->m_next;
1022 }
1023 controllen = ctlbuf - (caddr_t)msg.msg_control;
1024 error = copyout(&controllen, ucontrollenp,
1025 sizeof(*ucontrollenp));
1026 }
1027
1028 if (error == 0)
1029 error = copyout(&flags, uflagsp, sizeof(*uflagsp));
1030
1031 cleanup:
1032 if (sa)
1033 kfree(sa, M_SONAME);
1034 iovec_free(&iov, aiov);
1035 if (control)
1036 m_freem(control);
1037 return (error);
1038 }
1039
1040 struct linux_shutdown_args {
1041 int s;
1042 int how;
1043 };
1044
1045 static int
1046 linux_shutdown(struct linux_shutdown_args *args, int *res)
1047 {
1048 struct linux_shutdown_args linux_args;
1049 int error;
1050
1051 error = copyin(args, &linux_args, sizeof(linux_args));
1052 if (error)
1053 return (error);
1054
1055 error = kern_shutdown(linux_args.s, linux_args.how);
1056
1057 return (error);
1058 }
1059
1060 struct linux_setsockopt_args {
1061 int s;
1062 int level;
1063 int optname;
1064 void *optval;
1065 int optlen;
1066 };
1067
1068 static int
1069 linux_setsockopt(struct linux_setsockopt_args *args, int *res)
1070 {
1071 struct linux_setsockopt_args linux_args;
1072 struct thread *td = curthread;
1073 struct sockopt sopt;
1074 l_timeval linux_tv;
1075 struct timeval tv;
1076 int error, name, level;
1077
1078 error = copyin(args, &linux_args, sizeof(linux_args));
1079 if (error)
1080 return (error);
1081
1082 level = linux_to_bsd_sockopt_level(linux_args.level);
1083 switch (level) {
1084 case SOL_SOCKET:
1085 name = linux_to_bsd_so_sockopt(linux_args.optname);
1086 switch (name) {
1087 case SO_RCVTIMEO:
1088 /* FALLTHROUGH */
1089 case SO_SNDTIMEO:
1090 error = copyin(linux_args.optval, &linux_tv,
1091 sizeof(linux_tv));
1092 if (error)
1093 return (error);
1094 tv.tv_sec = linux_tv.tv_sec;
1095 tv.tv_usec = linux_tv.tv_usec;
1096 sopt.sopt_dir = SOPT_SET;
1097 sopt.sopt_level = level;
1098 sopt.sopt_name = name;
1099 sopt.sopt_valsize = sizeof(tv);
1100 sopt.sopt_val = &tv;
1101 sopt.sopt_td = td;
1102 return (kern_setsockopt(linux_args.s, &sopt));
1103 /* NOTREACHED */
1104 break;
1105 default:
1106 break;
1107 }
1108 break;
1109 case IPPROTO_IP:
1110 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1111 break;
1112 case IPPROTO_TCP:
1113 /* Linux TCP option values match BSD's */
1114 name = linux_args.optname;
1115 break;
1116 default:
1117 name = -1;
1118 break;
1119 }
1120 if (name == -1)
1121 return (ENOPROTOOPT);
1122
1123 if (linux_args.optlen < 0 || linux_args.optlen > SOMAXOPT_SIZE)
1124 return (EINVAL);
1125 if (linux_args.optval != NULL && linux_args.optlen == 0)
1126 return (EINVAL);
1127 if (linux_args.optval == NULL && linux_args.optlen != 0)
1128 return (EFAULT);
1129
1130 sopt.sopt_dir = SOPT_SET;
1131 sopt.sopt_level = level;
1132 sopt.sopt_name = name;
1133 sopt.sopt_valsize = linux_args.optlen;
1134 sopt.sopt_td = td;
1135
1136 if (linux_args.optval) {
1137 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1138 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1139 if (error)
1140 goto out;
1141 } else {
1142 sopt.sopt_val = NULL;
1143 }
1144 error = kern_setsockopt(linux_args.s, &sopt);
1145 if (error)
1146 goto out;
1147 if (linux_args.optval)
1148 error = copyout(sopt.sopt_val, linux_args.optval,
1149 sopt.sopt_valsize);
1150 out:
1151 if (linux_args.optval)
1152 kfree(sopt.sopt_val, M_TEMP);
1153 return(error);
1154 }
1155
1156 struct linux_getsockopt_args {
1157 int s;
1158 int level;
1159 int optname;
1160 void *optval;
1161 int *optlen;
1162 };
1163
1164 static int
1165 linux_getsockopt(struct linux_getsockopt_args *args, int *res)
1166 {
1167 struct linux_getsockopt_args linux_args;
1168 struct thread *td = curthread;
1169 struct sockopt sopt;
1170 l_timeval linux_tv;
1171 struct timeval tv;
1172 struct xucred xu;
1173 struct l_ucred lxu;
1174 int error, name, valsize, level;
1175
1176 error = copyin(args, &linux_args, sizeof(linux_args));
1177 if (error)
1178 return (error);
1179
1180 if (linux_args.optlen) {
1181 error = copyin(linux_args.optlen, &valsize, sizeof(valsize));
1182 if (error)
1183 return (error);
1184 } else {
1185 valsize = 0;
1186 }
1187
1188 if (valsize < 0 || valsize > SOMAXOPT_SIZE)
1189 return (EINVAL);
1190 if (linux_args.optval != NULL && valsize == 0)
1191 return (EFAULT);
1192 if (linux_args.optval == NULL && valsize != 0)
1193 return (EFAULT);
1194
1195 level = linux_to_bsd_sockopt_level(linux_args.level);
1196 switch (level) {
1197 case SOL_SOCKET:
1198 name = linux_to_bsd_so_sockopt(linux_args.optname);
1199 switch (name) {
1200 case SO_RCVTIMEO:
1201 /* FALLTHROUGH */
1202 case SO_SNDTIMEO:
1203 sopt.sopt_dir = SOPT_GET;
1204 sopt.sopt_level = level;
1205 sopt.sopt_name = name;
1206 sopt.sopt_valsize = sizeof(tv);
1207 sopt.sopt_td = td;
1208 sopt.sopt_val = &tv;
1209 error = kern_getsockopt(linux_args.s, &sopt);
1210 if (error)
1211 return (error);
1212 linux_tv.tv_sec = tv.tv_sec;
1213 linux_tv.tv_usec = tv.tv_usec;
1214 return (copyout(&linux_tv, linux_args.optval,
1215 sizeof(linux_tv)));
1216 /* NOTREACHED */
1217 break;
1218 case LOCAL_PEERCRED:
1219 if (valsize != sizeof(lxu))
1220 return (EINVAL);
1221 sopt.sopt_dir = SOPT_GET;
1222 sopt.sopt_level = level;
1223 sopt.sopt_name = name;
1224 sopt.sopt_valsize = sizeof(xu);
1225 sopt.sopt_td = td;
1226 sopt.sopt_val = &xu;
1227 error = kern_getsockopt(linux_args.s, &sopt);
1228 if (error)
1229 return (error);
1230 /*
1231 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1232 */
1233 lxu.pid = 0;
1234 lxu.uid = xu.cr_uid;
1235 lxu.gid = xu.cr_gid;
1236 return (copyout(&lxu, linux_args.optval, sizeof(lxu)));
1237 /* NOTREACHED */
1238 break;
1239 default:
1240 break;
1241 }
1242 break;
1243 case IPPROTO_IP:
1244 name = linux_to_bsd_ip_sockopt(linux_args.optname);
1245 break;
1246 case IPPROTO_TCP:
1247 /* Linux TCP option values match BSD's */
1248 name = linux_args.optname;
1249 break;
1250 default:
1251 name = -1;
1252 break;
1253 }
1254 if (name == -1)
1255 return (EOPNOTSUPP);
1256
1257
1258
1259 sopt.sopt_dir = SOPT_GET;
1260 sopt.sopt_level = level;
1261 sopt.sopt_name = name;
1262 sopt.sopt_valsize = valsize;
1263 sopt.sopt_td = td;
1264
1265 if (linux_args.optval) {
1266 sopt.sopt_val = kmalloc(sopt.sopt_valsize, M_TEMP, M_WAITOK);
1267 error = copyin(linux_args.optval, sopt.sopt_val, sopt.sopt_valsize);
1268 if (error)
1269 goto out;
1270 } else {
1271 sopt.sopt_val = NULL;
1272 }
1273 error = kern_getsockopt(linux_args.s, &sopt);
1274 if (error) {
1275 if (error == EINVAL)
1276 error = ENOPROTOOPT;
1277 goto out;
1278 }
1279 valsize = sopt.sopt_valsize;
1280 error = copyout(&valsize, linux_args.optlen, sizeof(valsize));
1281 if (error)
1282 goto out;
1283 if (linux_args.optval)
1284 error = copyout(sopt.sopt_val, linux_args.optval, sopt.sopt_valsize);
1285 out:
1286 if (linux_args.optval)
1287 kfree(sopt.sopt_val, M_TEMP);
1288 return(error);
1289 }
1290
1291 /*
1292 * MPALMOSTSAFE
1293 */
1294 int
1295 sys_linux_socketcall(struct linux_socketcall_args *args)
1296 {
1297 void *arg = (void *)args->args;
1298 int error;
1299
1300 get_mplock();
1301
1302 switch (args->what) {
1303 case LINUX_SOCKET:
1304 error = linux_socket(arg, &args->sysmsg_result);
1305 break;
1306 case LINUX_BIND:
1307 error = linux_bind(arg, &args->sysmsg_result);
1308 break;
1309 case LINUX_CONNECT:
1310 error = linux_connect(arg, &args->sysmsg_result);
1311 break;
1312 case LINUX_LISTEN:
1313 error = linux_listen(arg, &args->sysmsg_result);
1314 break;
1315 case LINUX_ACCEPT:
1316 error = linux_accept(arg, &args->sysmsg_result);
1317 break;
1318 case LINUX_GETSOCKNAME:
1319 error = linux_getsockname(arg, &args->sysmsg_result);
1320 break;
1321 case LINUX_GETPEERNAME:
1322 error = linux_getpeername(arg, &args->sysmsg_result);
1323 break;
1324 case LINUX_SOCKETPAIR:
1325 error = linux_socketpair(arg, &args->sysmsg_result);
1326 break;
1327 case LINUX_SEND:
1328 error = linux_send(arg, &args->sysmsg_szresult);
1329 break;
1330 case LINUX_RECV:
1331 error = linux_recv(arg, &args->sysmsg_szresult);
1332 break;
1333 case LINUX_SENDTO:
1334 error = linux_sendto(arg, &args->sysmsg_szresult);
1335 break;
1336 case LINUX_RECVFROM:
1337 error = linux_recvfrom(arg, &args->sysmsg_szresult);
1338 break;
1339 case LINUX_SHUTDOWN:
1340 error = linux_shutdown(arg, &args->sysmsg_result);
1341 break;
1342 case LINUX_SETSOCKOPT:
1343 error = linux_setsockopt(arg, &args->sysmsg_result);
1344 break;
1345 case LINUX_GETSOCKOPT:
1346 error = linux_getsockopt(arg, &args->sysmsg_result);
1347 break;
1348 case LINUX_SENDMSG:
1349 error = linux_sendmsg(arg, &args->sysmsg_szresult);
1350 break;
1351 case LINUX_RECVMSG:
1352 error = linux_recvmsg(arg, &args->sysmsg_szresult);
1353 break;
1354 default:
1355 uprintf("LINUX: 'socket' typ=%d not implemented\n",
1356 args->what);
1357 error = ENOSYS;
1358 break;
1359 }
1360 rel_mplock();
1361
1362 return (error);
1363 }
Cache object: 6961c93411ad5dc49b1ee27b1198faac
|