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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 /* XXX we use functions that might not exist. */
33 #include "opt_compat.h"
34 #include "opt_inet6.h"
35
36 #include <sys/param.h>
37 #include <sys/proc.h>
38 #include <sys/systm.h>
39 #include <sys/sysproto.h>
40 #include <sys/fcntl.h>
41 #include <sys/file.h>
42 #include <sys/limits.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mutex.h>
46 #include <sys/mbuf.h>
47 #include <sys/socket.h>
48 #include <sys/socketvar.h>
49 #include <sys/syscallsubr.h>
50 #include <sys/uio.h>
51 #include <sys/syslog.h>
52 #include <sys/un.h>
53
54 #include <netinet/in.h>
55 #include <netinet/in_systm.h>
56 #include <netinet/ip.h>
57 #ifdef INET6
58 #include <netinet/ip6.h>
59 #include <netinet6/ip6_var.h>
60 #endif
61
62 #ifdef COMPAT_LINUX32
63 #include <machine/../linux32/linux.h>
64 #include <machine/../linux32/linux32_proto.h>
65 #else
66 #include <machine/../linux/linux.h>
67 #include <machine/../linux/linux_proto.h>
68 #endif
69 #include <compat/linux/linux_socket.h>
70 #include <compat/linux/linux_util.h>
71
72 static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
73 struct malloc_type *);
74 static int linux_to_bsd_domain(int);
75
76 /*
77 * Reads a linux sockaddr and does any necessary translation.
78 * Linux sockaddrs don't have a length field, only a family.
79 */
80 static int
81 linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
82 {
83 int osalen = len;
84
85 return (do_sa_get(sap, osa, &osalen, M_SONAME));
86 }
87
88 /*
89 * Copy the osockaddr structure pointed to by osa to kernel, adjust
90 * family and convert to sockaddr.
91 */
92 static int
93 do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
94 struct malloc_type *mtype)
95 {
96 int error=0, bdom;
97 struct sockaddr *sa;
98 struct osockaddr *kosa;
99 int alloclen;
100 #ifdef INET6
101 int oldv6size;
102 struct sockaddr_in6 *sin6;
103 #endif
104 int namelen;
105
106 if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
107 return (EINVAL);
108
109 alloclen = *osalen;
110 #ifdef INET6
111 oldv6size = 0;
112 /*
113 * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
114 * if it's a v4-mapped address, so reserve the proper space
115 * for it.
116 */
117 if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
118 alloclen = sizeof (struct sockaddr_in6);
119 oldv6size = 1;
120 }
121 #endif
122
123 MALLOC(kosa, struct osockaddr *, alloclen, mtype, M_WAITOK);
124
125 if ((error = copyin(osa, kosa, *osalen)))
126 goto out;
127
128 bdom = linux_to_bsd_domain(kosa->sa_family);
129 if (bdom == -1) {
130 error = EAFNOSUPPORT;
131 goto out;
132 }
133
134 #ifdef INET6
135 /*
136 * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
137 * which lacks the scope id compared with RFC2553 one. If we detect
138 * the situation, reject the address and write a message to system log.
139 *
140 * Still accept addresses for which the scope id is not used.
141 */
142 if (oldv6size && bdom == AF_INET6) {
143 sin6 = (struct sockaddr_in6 *)kosa;
144 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
145 (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
146 !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
147 !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
148 !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
149 !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
150 sin6->sin6_scope_id = 0;
151 } else {
152 log(LOG_DEBUG,
153 "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
154 error = EINVAL;
155 goto out;
156 }
157 } else
158 #endif
159 if (bdom == AF_INET) {
160 alloclen = sizeof(struct sockaddr_in);
161 if (*osalen < alloclen) {
162 error = EINVAL;
163 goto out;
164 }
165 }
166
167 if ((bdom == AF_LOCAL) && (*osalen > sizeof(struct sockaddr_un))) {
168 for (namelen = 0;
169 namelen < *osalen - offsetof(struct sockaddr_un, sun_path);
170 namelen++)
171 if (!((struct sockaddr_un *)kosa)->sun_path[namelen])
172 break;
173 if (namelen + offsetof(struct sockaddr_un, sun_path) >
174 sizeof(struct sockaddr_un)) {
175 error = EINVAL;
176 goto out;
177 }
178 alloclen = sizeof(struct sockaddr_un);
179 }
180
181 sa = (struct sockaddr *) kosa;
182 sa->sa_family = bdom;
183 sa->sa_len = alloclen;
184
185 *sap = sa;
186 *osalen = alloclen;
187 return (0);
188
189 out:
190 FREE(kosa, mtype);
191 return (error);
192 }
193
194 static int
195 linux_to_bsd_domain(int domain)
196 {
197
198 switch (domain) {
199 case LINUX_AF_UNSPEC:
200 return (AF_UNSPEC);
201 case LINUX_AF_UNIX:
202 return (AF_LOCAL);
203 case LINUX_AF_INET:
204 return (AF_INET);
205 case LINUX_AF_INET6:
206 return (AF_INET6);
207 case LINUX_AF_AX25:
208 return (AF_CCITT);
209 case LINUX_AF_IPX:
210 return (AF_IPX);
211 case LINUX_AF_APPLETALK:
212 return (AF_APPLETALK);
213 }
214 return (-1);
215 }
216
217 static int
218 bsd_to_linux_domain(int domain)
219 {
220
221 switch (domain) {
222 case AF_UNSPEC:
223 return (LINUX_AF_UNSPEC);
224 case AF_LOCAL:
225 return (LINUX_AF_UNIX);
226 case AF_INET:
227 return (LINUX_AF_INET);
228 case AF_INET6:
229 return (LINUX_AF_INET6);
230 case AF_CCITT:
231 return (LINUX_AF_AX25);
232 case AF_IPX:
233 return (LINUX_AF_IPX);
234 case AF_APPLETALK:
235 return (LINUX_AF_APPLETALK);
236 }
237 return (-1);
238 }
239
240 static int
241 linux_to_bsd_sockopt_level(int level)
242 {
243
244 switch (level) {
245 case LINUX_SOL_SOCKET:
246 return (SOL_SOCKET);
247 }
248 return (level);
249 }
250
251 static int
252 bsd_to_linux_sockopt_level(int level)
253 {
254
255 switch (level) {
256 case SOL_SOCKET:
257 return (LINUX_SOL_SOCKET);
258 }
259 return (level);
260 }
261
262 static int
263 linux_to_bsd_ip_sockopt(int opt)
264 {
265
266 switch (opt) {
267 case LINUX_IP_TOS:
268 return (IP_TOS);
269 case LINUX_IP_TTL:
270 return (IP_TTL);
271 case LINUX_IP_OPTIONS:
272 return (IP_OPTIONS);
273 case LINUX_IP_MULTICAST_IF:
274 return (IP_MULTICAST_IF);
275 case LINUX_IP_MULTICAST_TTL:
276 return (IP_MULTICAST_TTL);
277 case LINUX_IP_MULTICAST_LOOP:
278 return (IP_MULTICAST_LOOP);
279 case LINUX_IP_ADD_MEMBERSHIP:
280 return (IP_ADD_MEMBERSHIP);
281 case LINUX_IP_DROP_MEMBERSHIP:
282 return (IP_DROP_MEMBERSHIP);
283 case LINUX_IP_HDRINCL:
284 return (IP_HDRINCL);
285 }
286 return (-1);
287 }
288
289 static int
290 linux_to_bsd_so_sockopt(int opt)
291 {
292
293 switch (opt) {
294 case LINUX_SO_DEBUG:
295 return (SO_DEBUG);
296 case LINUX_SO_REUSEADDR:
297 return (SO_REUSEADDR);
298 case LINUX_SO_TYPE:
299 return (SO_TYPE);
300 case LINUX_SO_ERROR:
301 return (SO_ERROR);
302 case LINUX_SO_DONTROUTE:
303 return (SO_DONTROUTE);
304 case LINUX_SO_BROADCAST:
305 return (SO_BROADCAST);
306 case LINUX_SO_SNDBUF:
307 return (SO_SNDBUF);
308 case LINUX_SO_RCVBUF:
309 return (SO_RCVBUF);
310 case LINUX_SO_KEEPALIVE:
311 return (SO_KEEPALIVE);
312 case LINUX_SO_OOBINLINE:
313 return (SO_OOBINLINE);
314 case LINUX_SO_LINGER:
315 return (SO_LINGER);
316 case LINUX_SO_PEERCRED:
317 return (LOCAL_PEERCRED);
318 case LINUX_SO_RCVLOWAT:
319 return (SO_RCVLOWAT);
320 case LINUX_SO_SNDLOWAT:
321 return (SO_SNDLOWAT);
322 case LINUX_SO_RCVTIMEO:
323 return (SO_RCVTIMEO);
324 case LINUX_SO_SNDTIMEO:
325 return (SO_SNDTIMEO);
326 case LINUX_SO_TIMESTAMP:
327 return (SO_TIMESTAMP);
328 case LINUX_SO_ACCEPTCONN:
329 return (SO_ACCEPTCONN);
330 }
331 return (-1);
332 }
333
334 static int
335 linux_to_bsd_msg_flags(int flags)
336 {
337 int ret_flags = 0;
338
339 if (flags & LINUX_MSG_OOB)
340 ret_flags |= MSG_OOB;
341 if (flags & LINUX_MSG_PEEK)
342 ret_flags |= MSG_PEEK;
343 if (flags & LINUX_MSG_DONTROUTE)
344 ret_flags |= MSG_DONTROUTE;
345 if (flags & LINUX_MSG_CTRUNC)
346 ret_flags |= MSG_CTRUNC;
347 if (flags & LINUX_MSG_TRUNC)
348 ret_flags |= MSG_TRUNC;
349 if (flags & LINUX_MSG_DONTWAIT)
350 ret_flags |= MSG_DONTWAIT;
351 if (flags & LINUX_MSG_EOR)
352 ret_flags |= MSG_EOR;
353 if (flags & LINUX_MSG_WAITALL)
354 ret_flags |= MSG_WAITALL;
355 if (flags & LINUX_MSG_NOSIGNAL)
356 ret_flags |= MSG_NOSIGNAL;
357 #if 0 /* not handled */
358 if (flags & LINUX_MSG_PROXY)
359 ;
360 if (flags & LINUX_MSG_FIN)
361 ;
362 if (flags & LINUX_MSG_SYN)
363 ;
364 if (flags & LINUX_MSG_CONFIRM)
365 ;
366 if (flags & LINUX_MSG_RST)
367 ;
368 if (flags & LINUX_MSG_ERRQUEUE)
369 ;
370 #endif
371 return ret_flags;
372 }
373
374 /*
375 * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
376 * native syscall will fault. Thus, we don't really need to check the
377 * return values for these functions.
378 */
379
380 static int
381 bsd_to_linux_sockaddr(struct sockaddr *arg)
382 {
383 struct sockaddr sa;
384 size_t sa_len = sizeof(struct sockaddr);
385 int error;
386
387 if ((error = copyin(arg, &sa, sa_len)))
388 return (error);
389
390 *(u_short *)&sa = sa.sa_family;
391
392 error = copyout(&sa, arg, sa_len);
393
394 return (error);
395 }
396
397 static int
398 linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
399 {
400 struct sockaddr sa;
401 size_t sa_len = sizeof(struct sockaddr);
402 int error;
403
404 if ((error = copyin(arg, &sa, sa_len)))
405 return (error);
406
407 sa.sa_family = *(sa_family_t *)&sa;
408 sa.sa_len = len;
409
410 error = copyout(&sa, arg, sa_len);
411
412 return (error);
413 }
414
415
416 static int
417 linux_sa_put(struct osockaddr *osa)
418 {
419 struct osockaddr sa;
420 int error, bdom;
421
422 /*
423 * Only read/write the osockaddr family part, the rest is
424 * not changed.
425 */
426 error = copyin(osa, &sa, sizeof(sa.sa_family));
427 if (error)
428 return (error);
429
430 bdom = bsd_to_linux_domain(sa.sa_family);
431 if (bdom == -1)
432 return (EINVAL);
433
434 sa.sa_family = bdom;
435 error = copyout(&sa, osa, sizeof(sa.sa_family));
436 if (error)
437 return (error);
438
439 return (0);
440 }
441
442 static int
443 linux_to_bsd_cmsg_type(int cmsg_type)
444 {
445
446 switch (cmsg_type) {
447 case LINUX_SCM_RIGHTS:
448 return (SCM_RIGHTS);
449 case LINUX_SCM_CREDENTIALS:
450 return (SCM_CREDS);
451 }
452 return (-1);
453 }
454
455 static int
456 bsd_to_linux_cmsg_type(int cmsg_type)
457 {
458
459 switch (cmsg_type) {
460 case SCM_RIGHTS:
461 return (LINUX_SCM_RIGHTS);
462 case SCM_CREDS:
463 return (LINUX_SCM_CREDENTIALS);
464 }
465 return (-1);
466 }
467
468
469
470 static int
471 linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
472 {
473 if (lhdr->msg_controllen > INT_MAX)
474 return (ENOBUFS);
475
476 bhdr->msg_name = PTRIN(lhdr->msg_name);
477 bhdr->msg_namelen = lhdr->msg_namelen;
478 bhdr->msg_iov = PTRIN(lhdr->msg_iov);
479 bhdr->msg_iovlen = lhdr->msg_iovlen;
480 bhdr->msg_control = PTRIN(lhdr->msg_control);
481
482 /*
483 * msg_controllen is skipped since BSD and LINUX control messages
484 * are potentially different sizes (e.g. the cred structure used
485 * by SCM_CREDS is different between the two operating system).
486 *
487 * The caller can set it (if necessary) after converting all the
488 * control messages.
489 */
490
491 bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags);
492 return (0);
493 }
494
495 static int
496 bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
497 {
498 lhdr->msg_name = PTROUT(bhdr->msg_name);
499 lhdr->msg_namelen = bhdr->msg_namelen;
500 lhdr->msg_iov = PTROUT(bhdr->msg_iov);
501 lhdr->msg_iovlen = bhdr->msg_iovlen;
502 lhdr->msg_control = PTROUT(bhdr->msg_control);
503
504 /*
505 * msg_controllen is skipped since BSD and LINUX control messages
506 * are potentially different sizes (e.g. the cred structure used
507 * by SCM_CREDS is different between the two operating system).
508 *
509 * The caller can set it (if necessary) after converting all the
510 * control messages.
511 */
512
513 /* msg_flags skipped */
514 return (0);
515 }
516
517 static int
518 linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
519 struct mbuf *control, enum uio_seg segflg)
520 {
521 struct sockaddr *to;
522 int error;
523
524 if (mp->msg_name != NULL) {
525 error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
526 if (error)
527 return (error);
528 mp->msg_name = to;
529 } else
530 to = NULL;
531
532 error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
533 segflg);
534
535 if (to)
536 FREE(to, M_SONAME);
537 return (error);
538 }
539
540 /* Return 0 if IP_HDRINCL is set for the given socket. */
541 static int
542 linux_check_hdrincl(struct thread *td, int s)
543 {
544 int error, optval, size_val;
545
546 size_val = sizeof(optval);
547 error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
548 &optval, UIO_SYSSPACE, &size_val);
549 if (error)
550 return (error);
551
552 return (optval == 0);
553 }
554
555 struct linux_sendto_args {
556 int s;
557 l_uintptr_t msg;
558 int len;
559 int flags;
560 l_uintptr_t to;
561 int tolen;
562 };
563
564 /*
565 * Updated sendto() when IP_HDRINCL is set:
566 * tweak endian-dependent fields in the IP packet.
567 */
568 static int
569 linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
570 {
571 /*
572 * linux_ip_copysize defines how many bytes we should copy
573 * from the beginning of the IP packet before we customize it for BSD.
574 * It should include all the fields we modify (ip_len and ip_off).
575 */
576 #define linux_ip_copysize 8
577
578 struct ip *packet;
579 struct msghdr msg;
580 struct iovec aiov[1];
581 int error;
582
583 /* Check that the packet isn't too big or too small. */
584 if (linux_args->len < linux_ip_copysize ||
585 linux_args->len > IP_MAXPACKET)
586 return (EINVAL);
587
588 packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
589
590 /* Make kernel copy of the packet to be sent */
591 if ((error = copyin(PTRIN(linux_args->msg), packet,
592 linux_args->len)))
593 goto goout;
594
595 /* Convert fields from Linux to BSD raw IP socket format */
596 packet->ip_len = linux_args->len;
597 packet->ip_off = ntohs(packet->ip_off);
598
599 /* Prepare the msghdr and iovec structures describing the new packet */
600 msg.msg_name = PTRIN(linux_args->to);
601 msg.msg_namelen = linux_args->tolen;
602 msg.msg_iov = aiov;
603 msg.msg_iovlen = 1;
604 msg.msg_control = NULL;
605 msg.msg_flags = 0;
606 aiov[0].iov_base = (char *)packet;
607 aiov[0].iov_len = linux_args->len;
608 error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
609 NULL, UIO_SYSSPACE);
610 goout:
611 free(packet, M_TEMP);
612 return (error);
613 }
614
615 struct linux_socket_args {
616 int domain;
617 int type;
618 int protocol;
619 };
620
621 static int
622 linux_socket(struct thread *td, struct linux_socket_args *args)
623 {
624 struct socket_args /* {
625 int domain;
626 int type;
627 int protocol;
628 } */ bsd_args;
629 int retval_socket, socket_flags;
630
631 bsd_args.protocol = args->protocol;
632 socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK;
633 if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
634 return (EINVAL);
635 bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
636 if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
637 return (EINVAL);
638 bsd_args.domain = linux_to_bsd_domain(args->domain);
639 if (bsd_args.domain == -1)
640 return (EAFNOSUPPORT);
641
642 retval_socket = socket(td, &bsd_args);
643 if (retval_socket)
644 return (retval_socket);
645
646 if (socket_flags & LINUX_SOCK_NONBLOCK) {
647 retval_socket = kern_fcntl(td, td->td_retval[0],
648 F_SETFL, O_NONBLOCK);
649 if (retval_socket) {
650 (void)kern_close(td, td->td_retval[0]);
651 goto out;
652 }
653 }
654 if (socket_flags & LINUX_SOCK_CLOEXEC) {
655 retval_socket = kern_fcntl(td, td->td_retval[0],
656 F_SETFD, FD_CLOEXEC);
657 if (retval_socket) {
658 (void)kern_close(td, td->td_retval[0]);
659 goto out;
660 }
661 }
662
663 if (bsd_args.type == SOCK_RAW
664 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
665 && bsd_args.domain == PF_INET) {
666 /* It's a raw IP socket: set the IP_HDRINCL option. */
667 int hdrincl;
668
669 hdrincl = 1;
670 /* We ignore any error returned by kern_setsockopt() */
671 kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
672 &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
673 }
674 #ifdef INET6
675 /*
676 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
677 * default and some apps depend on this. So, set V6ONLY to 0
678 * for Linux apps if the sysctl value is set to 1.
679 */
680 if (bsd_args.domain == PF_INET6
681 #ifndef KLD_MODULE
682 /*
683 * XXX: Avoid undefined symbol error with an IPv4 only
684 * kernel.
685 */
686 && ip6_v6only
687 #endif
688 ) {
689 int v6only;
690
691 v6only = 0;
692 /* We ignore any error returned by setsockopt() */
693 kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
694 &v6only, UIO_SYSSPACE, sizeof(v6only));
695 }
696 #endif
697
698 out:
699 return (retval_socket);
700 }
701
702 struct linux_bind_args {
703 int s;
704 l_uintptr_t name;
705 int namelen;
706 };
707
708 static int
709 linux_bind(struct thread *td, struct linux_bind_args *args)
710 {
711 struct sockaddr *sa;
712 int error;
713
714 error = linux_getsockaddr(&sa, PTRIN(args->name),
715 args->namelen);
716 if (error)
717 return (error);
718
719 error = kern_bind(td, args->s, sa);
720 free(sa, M_SONAME);
721 if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
722 return (EINVAL);
723 return (error);
724 }
725
726 struct linux_connect_args {
727 int s;
728 l_uintptr_t name;
729 int namelen;
730 };
731 int linux_connect(struct thread *, struct linux_connect_args *);
732
733 int
734 linux_connect(struct thread *td, struct linux_connect_args *args)
735 {
736 struct socket *so;
737 struct sockaddr *sa;
738 u_int fflag;
739 int error;
740
741 error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
742 args->namelen);
743 if (error)
744 return (error);
745
746 error = kern_connect(td, args->s, sa);
747 free(sa, M_SONAME);
748 if (error != EISCONN)
749 return (error);
750
751 /*
752 * Linux doesn't return EISCONN the first time it occurs,
753 * when on a non-blocking socket. Instead it returns the
754 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
755 *
756 * XXXRW: Instead of using fgetsock(), check that it is a
757 * socket and use the file descriptor reference instead of
758 * creating a new one.
759 */
760 error = fgetsock(td, args->s, &so, &fflag);
761 if (error == 0) {
762 error = EISCONN;
763 if (fflag & FNONBLOCK) {
764 SOCK_LOCK(so);
765 if (so->so_emuldata == 0)
766 error = so->so_error;
767 so->so_emuldata = (void *)1;
768 SOCK_UNLOCK(so);
769 }
770 fputsock(so);
771 }
772 return (error);
773 }
774
775 struct linux_listen_args {
776 int s;
777 int backlog;
778 };
779
780 static int
781 linux_listen(struct thread *td, struct linux_listen_args *args)
782 {
783 struct listen_args /* {
784 int s;
785 int backlog;
786 } */ bsd_args;
787
788 bsd_args.s = args->s;
789 bsd_args.backlog = args->backlog;
790 return (listen(td, &bsd_args));
791 }
792
793 struct linux_accept_args {
794 int s;
795 l_uintptr_t addr;
796 l_uintptr_t namelen;
797 };
798
799 static int
800 linux_accept(struct thread *td, struct linux_accept_args *args)
801 {
802 struct accept_args /* {
803 int s;
804 struct sockaddr * __restrict name;
805 socklen_t * __restrict anamelen;
806 } */ bsd_args;
807 int error, fd;
808
809 bsd_args.s = args->s;
810 /* XXX: */
811 bsd_args.name = (struct sockaddr * __restrict)PTRIN(args->addr);
812 bsd_args.anamelen = PTRIN(args->namelen);/* XXX */
813 error = accept(td, &bsd_args);
814 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
815 if (error) {
816 if (error == EFAULT && args->namelen != sizeof(struct sockaddr_in))
817 return (EINVAL);
818 return (error);
819 }
820 if (args->addr) {
821 error = linux_sa_put(PTRIN(args->addr));
822 if (error) {
823 (void)kern_close(td, td->td_retval[0]);
824 return (error);
825 }
826 }
827
828 /*
829 * linux appears not to copy flags from the parent socket to the
830 * accepted one, so we must clear the flags in the new descriptor.
831 * Ignore any errors, because we already have an open fd.
832 */
833 fd = td->td_retval[0];
834 (void)kern_fcntl(td, fd, F_SETFL, 0);
835 td->td_retval[0] = fd;
836 return (0);
837 }
838
839 struct linux_getsockname_args {
840 int s;
841 l_uintptr_t addr;
842 l_uintptr_t namelen;
843 };
844
845 static int
846 linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
847 {
848 struct getsockname_args /* {
849 int fdes;
850 struct sockaddr * __restrict asa;
851 socklen_t * __restrict alen;
852 } */ bsd_args;
853 int error;
854
855 bsd_args.fdes = args->s;
856 /* XXX: */
857 bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
858 bsd_args.alen = PTRIN(args->namelen); /* XXX */
859 error = getsockname(td, &bsd_args);
860 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
861 if (error)
862 return (error);
863 error = linux_sa_put(PTRIN(args->addr));
864 if (error)
865 return (error);
866 return (0);
867 }
868
869 struct linux_getpeername_args {
870 int s;
871 l_uintptr_t addr;
872 l_uintptr_t namelen;
873 };
874
875 static int
876 linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
877 {
878 struct getpeername_args /* {
879 int fdes;
880 caddr_t asa;
881 int *alen;
882 } */ bsd_args;
883 int error;
884
885 bsd_args.fdes = args->s;
886 bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
887 bsd_args.alen = (int *)PTRIN(args->namelen);
888 error = getpeername(td, &bsd_args);
889 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
890 if (error)
891 return (error);
892 error = linux_sa_put(PTRIN(args->addr));
893 if (error)
894 return (error);
895 return (0);
896 }
897
898 struct linux_socketpair_args {
899 int domain;
900 int type;
901 int protocol;
902 l_uintptr_t rsv;
903 };
904
905 static int
906 linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
907 {
908 struct socketpair_args /* {
909 int domain;
910 int type;
911 int protocol;
912 int *rsv;
913 } */ bsd_args;
914
915 bsd_args.domain = linux_to_bsd_domain(args->domain);
916 if (bsd_args.domain != PF_LOCAL)
917 return (EAFNOSUPPORT);
918
919 bsd_args.type = args->type;
920 if (args->protocol != 0 && args->protocol != PF_UNIX)
921
922 /*
923 * Use of PF_UNIX as protocol argument is not right,
924 * but Linux does it.
925 * Do not map PF_UNIX as its Linux value is identical
926 * to FreeBSD one.
927 */
928 return (EPROTONOSUPPORT);
929 else
930 bsd_args.protocol = 0;
931 bsd_args.rsv = (int *)PTRIN(args->rsv);
932 return (socketpair(td, &bsd_args));
933 }
934
935 struct linux_send_args {
936 int s;
937 l_uintptr_t msg;
938 int len;
939 int flags;
940 };
941
942 static int
943 linux_send(struct thread *td, struct linux_send_args *args)
944 {
945 struct sendto_args /* {
946 int s;
947 caddr_t buf;
948 int len;
949 int flags;
950 caddr_t to;
951 int tolen;
952 } */ bsd_args;
953
954 bsd_args.s = args->s;
955 bsd_args.buf = (caddr_t)PTRIN(args->msg);
956 bsd_args.len = args->len;
957 bsd_args.flags = args->flags;
958 bsd_args.to = NULL;
959 bsd_args.tolen = 0;
960 return sendto(td, &bsd_args);
961 }
962
963 struct linux_recv_args {
964 int s;
965 l_uintptr_t msg;
966 int len;
967 int flags;
968 };
969
970 static int
971 linux_recv(struct thread *td, struct linux_recv_args *args)
972 {
973 struct recvfrom_args /* {
974 int s;
975 caddr_t buf;
976 int len;
977 int flags;
978 struct sockaddr *from;
979 socklen_t fromlenaddr;
980 } */ bsd_args;
981
982 bsd_args.s = args->s;
983 bsd_args.buf = (caddr_t)PTRIN(args->msg);
984 bsd_args.len = args->len;
985 bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
986 bsd_args.from = NULL;
987 bsd_args.fromlenaddr = 0;
988 return (recvfrom(td, &bsd_args));
989 }
990
991 static int
992 linux_sendto(struct thread *td, struct linux_sendto_args *args)
993 {
994 struct msghdr msg;
995 struct iovec aiov;
996 int error;
997
998 if (linux_check_hdrincl(td, args->s) == 0)
999 /* IP_HDRINCL set, tweak the packet before sending */
1000 return (linux_sendto_hdrincl(td, args));
1001
1002 msg.msg_name = PTRIN(args->to);
1003 msg.msg_namelen = args->tolen;
1004 msg.msg_iov = &aiov;
1005 msg.msg_iovlen = 1;
1006 msg.msg_control = NULL;
1007 msg.msg_flags = 0;
1008 aiov.iov_base = PTRIN(args->msg);
1009 aiov.iov_len = args->len;
1010 error = linux_sendit(td, args->s, &msg, args->flags, NULL,
1011 UIO_USERSPACE);
1012 return (error);
1013 }
1014
1015 struct linux_recvfrom_args {
1016 int s;
1017 l_uintptr_t buf;
1018 int len;
1019 int flags;
1020 l_uintptr_t from;
1021 l_uintptr_t fromlen;
1022 };
1023
1024 static int
1025 linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
1026 {
1027 struct recvfrom_args /* {
1028 int s;
1029 caddr_t buf;
1030 size_t len;
1031 int flags;
1032 struct sockaddr * __restrict from;
1033 socklen_t * __restrict fromlenaddr;
1034 } */ bsd_args;
1035 size_t len;
1036 int error;
1037
1038 if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t))))
1039 return (error);
1040
1041 bsd_args.s = args->s;
1042 bsd_args.buf = PTRIN(args->buf);
1043 bsd_args.len = args->len;
1044 bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
1045 /* XXX: */
1046 bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from);
1047 bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */
1048
1049 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
1050 error = recvfrom(td, &bsd_args);
1051 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
1052
1053 if (error)
1054 return (error);
1055 if (args->from) {
1056 error = linux_sa_put((struct osockaddr *)
1057 PTRIN(args->from));
1058 if (error)
1059 return (error);
1060 }
1061 return (0);
1062 }
1063
1064 struct linux_sendmsg_args {
1065 int s;
1066 l_uintptr_t msg;
1067 int flags;
1068 };
1069
1070 static int
1071 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1072 {
1073 struct cmsghdr *cmsg;
1074 struct cmsgcred cmcred;
1075 struct mbuf *control;
1076 struct msghdr msg;
1077 struct l_cmsghdr linux_cmsg;
1078 struct l_cmsghdr *ptr_cmsg;
1079 struct l_msghdr linux_msg;
1080 struct iovec *iov;
1081 socklen_t datalen;
1082 struct sockaddr *sa;
1083 sa_family_t sa_family;
1084 void *data;
1085 int error;
1086
1087 error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
1088 if (error)
1089 return (error);
1090
1091 /*
1092 * Some Linux applications (ping) define a non-NULL control data
1093 * pointer, but a msg_controllen of 0, which is not allowed in the
1094 * FreeBSD system call interface. NULL the msg_control pointer in
1095 * order to handle this case. This should be checked, but allows the
1096 * Linux ping to work.
1097 */
1098 if (PTRIN(linux_msg.msg_control) != NULL && linux_msg.msg_controllen == 0)
1099 linux_msg.msg_control = PTROUT(NULL);
1100
1101 error = linux_to_bsd_msghdr(&msg, &linux_msg);
1102 if (error)
1103 return (error);
1104
1105 #ifdef COMPAT_LINUX32
1106 error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
1107 &iov, EMSGSIZE);
1108 #else
1109 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1110 #endif
1111 if (error)
1112 return (error);
1113
1114 control = NULL;
1115 cmsg = NULL;
1116
1117 if ((ptr_cmsg = LINUX_CMSG_FIRSTHDR(&linux_msg)) != NULL) {
1118 error = kern_getsockname(td, args->s, &sa, &datalen);
1119 if (error)
1120 goto bad;
1121 sa_family = sa->sa_family;
1122 free(sa, M_SONAME);
1123
1124 error = ENOBUFS;
1125 cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
1126 control = m_get(M_WAIT, MT_CONTROL);
1127 if (control == NULL)
1128 goto bad;
1129
1130 do {
1131 error = copyin(ptr_cmsg, &linux_cmsg,
1132 sizeof(struct l_cmsghdr));
1133 if (error)
1134 goto bad;
1135
1136 error = EINVAL;
1137 if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr))
1138 goto bad;
1139
1140 /*
1141 * Now we support only SCM_RIGHTS and SCM_CRED,
1142 * so return EINVAL in any other cmsg_type
1143 */
1144 cmsg->cmsg_type =
1145 linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type);
1146 cmsg->cmsg_level =
1147 linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
1148 if (cmsg->cmsg_type == -1
1149 || cmsg->cmsg_level != SOL_SOCKET)
1150 goto bad;
1151
1152 /*
1153 * Some applications (e.g. pulseaudio) attempt to
1154 * send ancillary data even if the underlying protocol
1155 * doesn't support it which is not allowed in the
1156 * FreeBSD system call interface.
1157 */
1158 if (sa_family != AF_UNIX)
1159 continue;
1160
1161 data = LINUX_CMSG_DATA(ptr_cmsg);
1162 datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
1163
1164 switch (cmsg->cmsg_type)
1165 {
1166 case SCM_RIGHTS:
1167 break;
1168
1169 case SCM_CREDS:
1170 data = &cmcred;
1171 datalen = sizeof(cmcred);
1172
1173 /*
1174 * The lower levels will fill in the structure
1175 */
1176 bzero(data, datalen);
1177 break;
1178 }
1179
1180 cmsg->cmsg_len = CMSG_LEN(datalen);
1181
1182 error = ENOBUFS;
1183 if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
1184 goto bad;
1185 if (!m_append(control, datalen, (c_caddr_t) data))
1186 goto bad;
1187 } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&linux_msg, ptr_cmsg)));
1188
1189 if (m_length(control, NULL) == 0) {
1190 m_freem(control);
1191 control = NULL;
1192 }
1193 }
1194
1195 msg.msg_iov = iov;
1196 msg.msg_flags = 0;
1197 error = linux_sendit(td, args->s, &msg, args->flags, control,
1198 UIO_USERSPACE);
1199
1200 bad:
1201 free(iov, M_IOV);
1202 if (cmsg)
1203 free(cmsg, M_TEMP);
1204 return (error);
1205 }
1206
1207 struct linux_recvmsg_args {
1208 int s;
1209 l_uintptr_t msg;
1210 int flags;
1211 };
1212
1213 static int
1214 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
1215 {
1216 struct cmsghdr *cm;
1217 struct cmsgcred *cmcred;
1218 struct msghdr msg;
1219 struct l_cmsghdr *linux_cmsg = NULL;
1220 struct l_ucred linux_ucred;
1221 socklen_t datalen, outlen;
1222 struct l_msghdr linux_msg;
1223 struct iovec *iov, *uiov;
1224 struct mbuf *control = NULL;
1225 struct mbuf **controlp;
1226 caddr_t outbuf;
1227 void *data;
1228 int error, i, fd, fds, *fdp;
1229
1230 error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
1231 if (error)
1232 return (error);
1233
1234 error = linux_to_bsd_msghdr(&msg, &linux_msg);
1235 if (error)
1236 return (error);
1237
1238 #ifdef COMPAT_LINUX32
1239 error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
1240 &iov, EMSGSIZE);
1241 #else
1242 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1243 #endif
1244 if (error)
1245 return (error);
1246
1247 if (msg.msg_name) {
1248 error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
1249 msg.msg_namelen);
1250 if (error)
1251 goto bad;
1252 }
1253
1254 uiov = msg.msg_iov;
1255 msg.msg_iov = iov;
1256 controlp = (msg.msg_control != NULL) ? &control : NULL;
1257 error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp);
1258 msg.msg_iov = uiov;
1259 if (error)
1260 goto bad;
1261
1262 error = bsd_to_linux_msghdr(&msg, &linux_msg);
1263 if (error)
1264 goto bad;
1265
1266 if (linux_msg.msg_name) {
1267 error = bsd_to_linux_sockaddr((struct sockaddr *)
1268 PTRIN(linux_msg.msg_name));
1269 if (error)
1270 goto bad;
1271 }
1272 if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
1273 error = linux_sa_put(PTRIN(linux_msg.msg_name));
1274 if (error)
1275 goto bad;
1276 }
1277
1278 outbuf = PTRIN(linux_msg.msg_control);
1279 outlen = 0;
1280
1281 if (control) {
1282 linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
1283
1284 msg.msg_control = mtod(control, struct cmsghdr *);
1285 msg.msg_controllen = control->m_len;
1286
1287 cm = CMSG_FIRSTHDR(&msg);
1288
1289 while (cm != NULL) {
1290 linux_cmsg->cmsg_type =
1291 bsd_to_linux_cmsg_type(cm->cmsg_type);
1292 linux_cmsg->cmsg_level =
1293 bsd_to_linux_sockopt_level(cm->cmsg_level);
1294 if (linux_cmsg->cmsg_type == -1
1295 || cm->cmsg_level != SOL_SOCKET)
1296 {
1297 error = EINVAL;
1298 goto bad;
1299 }
1300
1301 data = CMSG_DATA(cm);
1302 datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
1303
1304 switch (cm->cmsg_type)
1305 {
1306 case SCM_RIGHTS:
1307 if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
1308 fds = datalen / sizeof(int);
1309 fdp = data;
1310 for (i = 0; i < fds; i++) {
1311 fd = *fdp++;
1312 (void)kern_fcntl(td, fd,
1313 F_SETFD, FD_CLOEXEC);
1314 }
1315 }
1316 break;
1317
1318 case SCM_CREDS:
1319 /*
1320 * Currently LOCAL_CREDS is never in
1321 * effect for Linux so no need to worry
1322 * about sockcred
1323 */
1324 if (datalen != sizeof (*cmcred)) {
1325 error = EMSGSIZE;
1326 goto bad;
1327 }
1328 cmcred = (struct cmsgcred *)data;
1329 bzero(&linux_ucred, sizeof(linux_ucred));
1330 linux_ucred.pid = cmcred->cmcred_pid;
1331 linux_ucred.uid = cmcred->cmcred_uid;
1332 linux_ucred.gid = cmcred->cmcred_gid;
1333 data = &linux_ucred;
1334 datalen = sizeof(linux_ucred);
1335 break;
1336 }
1337
1338 if (outlen + LINUX_CMSG_LEN(datalen) >
1339 linux_msg.msg_controllen) {
1340 if (outlen == 0) {
1341 error = EMSGSIZE;
1342 goto bad;
1343 } else {
1344 linux_msg.msg_flags |=
1345 LINUX_MSG_CTRUNC;
1346 goto out;
1347 }
1348 }
1349
1350 linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
1351
1352 error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
1353 if (error)
1354 goto bad;
1355 outbuf += L_CMSG_HDRSZ;
1356
1357 error = copyout(data, outbuf, datalen);
1358 if (error)
1359 goto bad;
1360
1361 outbuf += LINUX_CMSG_ALIGN(datalen);
1362 outlen += LINUX_CMSG_LEN(datalen);
1363
1364 cm = CMSG_NXTHDR(&msg, cm);
1365 }
1366 }
1367
1368 out:
1369 linux_msg.msg_controllen = outlen;
1370 error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
1371
1372 bad:
1373 free(iov, M_IOV);
1374 if (control != NULL)
1375 m_freem(control);
1376 if (linux_cmsg != NULL)
1377 free(linux_cmsg, M_TEMP);
1378
1379 return (error);
1380 }
1381
1382 struct linux_shutdown_args {
1383 int s;
1384 int how;
1385 };
1386
1387 static int
1388 linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1389 {
1390 struct shutdown_args /* {
1391 int s;
1392 int how;
1393 } */ bsd_args;
1394
1395 bsd_args.s = args->s;
1396 bsd_args.how = args->how;
1397 return (shutdown(td, &bsd_args));
1398 }
1399
1400 struct linux_setsockopt_args {
1401 int s;
1402 int level;
1403 int optname;
1404 l_uintptr_t optval;
1405 int optlen;
1406 };
1407
1408 static int
1409 linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1410 {
1411 struct setsockopt_args /* {
1412 int s;
1413 int level;
1414 int name;
1415 caddr_t val;
1416 int valsize;
1417 } */ bsd_args;
1418 l_timeval linux_tv;
1419 struct timeval tv;
1420 int error, name;
1421
1422 bsd_args.s = args->s;
1423 bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1424 switch (bsd_args.level) {
1425 case SOL_SOCKET:
1426 name = linux_to_bsd_so_sockopt(args->optname);
1427 switch (name) {
1428 case SO_RCVTIMEO:
1429 /* FALLTHROUGH */
1430 case SO_SNDTIMEO:
1431 error = copyin(PTRIN(args->optval), &linux_tv,
1432 sizeof(linux_tv));
1433 if (error)
1434 return (error);
1435 tv.tv_sec = linux_tv.tv_sec;
1436 tv.tv_usec = linux_tv.tv_usec;
1437 return (kern_setsockopt(td, args->s, bsd_args.level,
1438 name, &tv, UIO_SYSSPACE, sizeof(tv)));
1439 /* NOTREACHED */
1440 break;
1441 default:
1442 break;
1443 }
1444 break;
1445 case IPPROTO_IP:
1446 name = linux_to_bsd_ip_sockopt(args->optname);
1447 break;
1448 case IPPROTO_TCP:
1449 /* Linux TCP option values match BSD's */
1450 name = args->optname;
1451 break;
1452 default:
1453 name = -1;
1454 break;
1455 }
1456 if (name == -1)
1457 return (ENOPROTOOPT);
1458
1459 bsd_args.name = name;
1460 bsd_args.val = PTRIN(args->optval);
1461 bsd_args.valsize = args->optlen;
1462
1463 if (name == IPV6_NEXTHOP) {
1464 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
1465 bsd_args.valsize);
1466 error = setsockopt(td, &bsd_args);
1467 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1468 } else
1469 error = setsockopt(td, &bsd_args);
1470
1471 return (error);
1472 }
1473
1474 struct linux_getsockopt_args {
1475 int s;
1476 int level;
1477 int optname;
1478 l_uintptr_t optval;
1479 l_uintptr_t optlen;
1480 };
1481
1482 static int
1483 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1484 {
1485 struct getsockopt_args /* {
1486 int s;
1487 int level;
1488 int name;
1489 caddr_t val;
1490 int *avalsize;
1491 } */ bsd_args;
1492 l_timeval linux_tv;
1493 struct timeval tv;
1494 socklen_t tv_len, xulen;
1495 struct xucred xu;
1496 struct l_ucred lxu;
1497 int error, name;
1498
1499 bsd_args.s = args->s;
1500 bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1501 switch (bsd_args.level) {
1502 case SOL_SOCKET:
1503 name = linux_to_bsd_so_sockopt(args->optname);
1504 switch (name) {
1505 case SO_RCVTIMEO:
1506 /* FALLTHROUGH */
1507 case SO_SNDTIMEO:
1508 tv_len = sizeof(tv);
1509 error = kern_getsockopt(td, args->s, bsd_args.level,
1510 name, &tv, UIO_SYSSPACE, &tv_len);
1511 if (error)
1512 return (error);
1513 linux_tv.tv_sec = tv.tv_sec;
1514 linux_tv.tv_usec = tv.tv_usec;
1515 return (copyout(&linux_tv, PTRIN(args->optval),
1516 sizeof(linux_tv)));
1517 /* NOTREACHED */
1518 break;
1519 case LOCAL_PEERCRED:
1520 if (args->optlen != sizeof(lxu))
1521 return (EINVAL);
1522 xulen = sizeof(xu);
1523 error = kern_getsockopt(td, args->s, bsd_args.level,
1524 name, &xu, UIO_SYSSPACE, &xulen);
1525 if (error)
1526 return (error);
1527 /*
1528 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1529 */
1530 lxu.pid = 0;
1531 lxu.uid = xu.cr_uid;
1532 lxu.gid = xu.cr_gid;
1533 return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
1534 /* NOTREACHED */
1535 break;
1536 default:
1537 break;
1538 }
1539 break;
1540 case IPPROTO_IP:
1541 name = linux_to_bsd_ip_sockopt(args->optname);
1542 break;
1543 case IPPROTO_TCP:
1544 /* Linux TCP option values match BSD's */
1545 name = args->optname;
1546 break;
1547 default:
1548 name = -1;
1549 break;
1550 }
1551 if (name == -1)
1552 return (EINVAL);
1553
1554 bsd_args.name = name;
1555 bsd_args.val = PTRIN(args->optval);
1556 bsd_args.avalsize = PTRIN(args->optlen);
1557
1558 if (name == IPV6_NEXTHOP) {
1559 error = getsockopt(td, &bsd_args);
1560 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1561 } else
1562 error = getsockopt(td, &bsd_args);
1563
1564 return (error);
1565 }
1566
1567 /* Argument list sizes for linux_socketcall */
1568
1569 #define LINUX_AL(x) ((x) * sizeof(l_ulong))
1570
1571 static const unsigned char lxs_args[] = {
1572 LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */,
1573 LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */,
1574 LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */,
1575 LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */,
1576 LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */,
1577 LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */,
1578 LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */,
1579 LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */,
1580 LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */
1581 };
1582
1583 #define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1
1584
1585 int
1586 linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1587 {
1588 l_ulong a[6];
1589 void *arg;
1590 int error;
1591
1592 if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE)
1593 return (EINVAL);
1594 error = copyin(PTRIN(args->args), a, lxs_args[args->what]);
1595 if (error)
1596 return (error);
1597
1598 arg = a;
1599 switch (args->what) {
1600 case LINUX_SOCKET:
1601 return (linux_socket(td, arg));
1602 case LINUX_BIND:
1603 return (linux_bind(td, arg));
1604 case LINUX_CONNECT:
1605 return (linux_connect(td, arg));
1606 case LINUX_LISTEN:
1607 return (linux_listen(td, arg));
1608 case LINUX_ACCEPT:
1609 return (linux_accept(td, arg));
1610 case LINUX_GETSOCKNAME:
1611 return (linux_getsockname(td, arg));
1612 case LINUX_GETPEERNAME:
1613 return (linux_getpeername(td, arg));
1614 case LINUX_SOCKETPAIR:
1615 return (linux_socketpair(td, arg));
1616 case LINUX_SEND:
1617 return (linux_send(td, arg));
1618 case LINUX_RECV:
1619 return (linux_recv(td, arg));
1620 case LINUX_SENDTO:
1621 return (linux_sendto(td, arg));
1622 case LINUX_RECVFROM:
1623 return (linux_recvfrom(td, arg));
1624 case LINUX_SHUTDOWN:
1625 return (linux_shutdown(td, arg));
1626 case LINUX_SETSOCKOPT:
1627 return (linux_setsockopt(td, arg));
1628 case LINUX_GETSOCKOPT:
1629 return (linux_getsockopt(td, arg));
1630 case LINUX_SENDMSG:
1631 return (linux_sendmsg(td, arg));
1632 case LINUX_RECVMSG:
1633 return (linux_recvmsg(td, arg));
1634 }
1635
1636 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1637 return (ENOSYS);
1638 }
Cache object: ab09da9e7708187415989e8a36d0d4ee
|