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: releng/7.4/sys/compat/linux/linux_socket.c 226023 2011-10-04 19:07:38Z cperciva $");
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 }
450 return (-1);
451 }
452
453 static int
454 bsd_to_linux_cmsg_type(int cmsg_type)
455 {
456
457 switch (cmsg_type) {
458 case SCM_RIGHTS:
459 return (LINUX_SCM_RIGHTS);
460 }
461 return (-1);
462 }
463
464
465
466 static int
467 linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
468 {
469 if (lhdr->msg_controllen > INT_MAX)
470 return (ENOBUFS);
471
472 bhdr->msg_name = PTRIN(lhdr->msg_name);
473 bhdr->msg_namelen = lhdr->msg_namelen;
474 bhdr->msg_iov = PTRIN(lhdr->msg_iov);
475 bhdr->msg_iovlen = lhdr->msg_iovlen;
476 bhdr->msg_control = PTRIN(lhdr->msg_control);
477 bhdr->msg_controllen = lhdr->msg_controllen;
478 bhdr->msg_flags = linux_to_bsd_msg_flags(lhdr->msg_flags);
479 return (0);
480 }
481
482 static int
483 bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
484 {
485 lhdr->msg_name = PTROUT(bhdr->msg_name);
486 lhdr->msg_namelen = bhdr->msg_namelen;
487 lhdr->msg_iov = PTROUT(bhdr->msg_iov);
488 lhdr->msg_iovlen = bhdr->msg_iovlen;
489 lhdr->msg_control = PTROUT(bhdr->msg_control);
490 lhdr->msg_controllen = bhdr->msg_controllen;
491 /* msg_flags skipped */
492 return (0);
493 }
494
495 static int
496 linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
497 struct mbuf *control, enum uio_seg segflg)
498 {
499 struct sockaddr *to;
500 int error;
501
502 if (mp->msg_name != NULL) {
503 error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
504 if (error)
505 return (error);
506 mp->msg_name = to;
507 } else
508 to = NULL;
509
510 error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
511 segflg);
512
513 if (to)
514 FREE(to, M_SONAME);
515 return (error);
516 }
517
518 /* Return 0 if IP_HDRINCL is set for the given socket. */
519 static int
520 linux_check_hdrincl(struct thread *td, int s)
521 {
522 int error, optval, size_val;
523
524 size_val = sizeof(optval);
525 error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
526 &optval, UIO_SYSSPACE, &size_val);
527 if (error)
528 return (error);
529
530 return (optval == 0);
531 }
532
533 struct linux_sendto_args {
534 int s;
535 l_uintptr_t msg;
536 int len;
537 int flags;
538 l_uintptr_t to;
539 int tolen;
540 };
541
542 /*
543 * Updated sendto() when IP_HDRINCL is set:
544 * tweak endian-dependent fields in the IP packet.
545 */
546 static int
547 linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
548 {
549 /*
550 * linux_ip_copysize defines how many bytes we should copy
551 * from the beginning of the IP packet before we customize it for BSD.
552 * It should include all the fields we modify (ip_len and ip_off).
553 */
554 #define linux_ip_copysize 8
555
556 struct ip *packet;
557 struct msghdr msg;
558 struct iovec aiov[1];
559 int error;
560
561 /* Check that the packet isn't too big or too small. */
562 if (linux_args->len < linux_ip_copysize ||
563 linux_args->len > IP_MAXPACKET)
564 return (EINVAL);
565
566 packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
567
568 /* Make kernel copy of the packet to be sent */
569 if ((error = copyin(PTRIN(linux_args->msg), packet,
570 linux_args->len)))
571 goto goout;
572
573 /* Convert fields from Linux to BSD raw IP socket format */
574 packet->ip_len = linux_args->len;
575 packet->ip_off = ntohs(packet->ip_off);
576
577 /* Prepare the msghdr and iovec structures describing the new packet */
578 msg.msg_name = PTRIN(linux_args->to);
579 msg.msg_namelen = linux_args->tolen;
580 msg.msg_iov = aiov;
581 msg.msg_iovlen = 1;
582 msg.msg_control = NULL;
583 msg.msg_flags = 0;
584 aiov[0].iov_base = (char *)packet;
585 aiov[0].iov_len = linux_args->len;
586 error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
587 NULL, UIO_SYSSPACE);
588 goout:
589 free(packet, M_TEMP);
590 return (error);
591 }
592
593 struct linux_socket_args {
594 int domain;
595 int type;
596 int protocol;
597 };
598
599 static int
600 linux_socket(struct thread *td, struct linux_socket_args *args)
601 {
602 struct socket_args /* {
603 int domain;
604 int type;
605 int protocol;
606 } */ bsd_args;
607 int retval_socket, socket_flags;
608
609 bsd_args.protocol = args->protocol;
610 socket_flags = args->type & ~LINUX_SOCK_TYPE_MASK;
611 if (socket_flags & ~(LINUX_SOCK_CLOEXEC | LINUX_SOCK_NONBLOCK))
612 return (EINVAL);
613 bsd_args.type = args->type & LINUX_SOCK_TYPE_MASK;
614 if (bsd_args.type < 0 || bsd_args.type > LINUX_SOCK_MAX)
615 return (EINVAL);
616 bsd_args.domain = linux_to_bsd_domain(args->domain);
617 if (bsd_args.domain == -1)
618 return (EAFNOSUPPORT);
619
620 retval_socket = socket(td, &bsd_args);
621 if (retval_socket)
622 return (retval_socket);
623
624 if (socket_flags & LINUX_SOCK_NONBLOCK) {
625 retval_socket = kern_fcntl(td, td->td_retval[0],
626 F_SETFL, O_NONBLOCK);
627 if (retval_socket) {
628 (void)kern_close(td, td->td_retval[0]);
629 goto out;
630 }
631 }
632 if (socket_flags & LINUX_SOCK_CLOEXEC) {
633 retval_socket = kern_fcntl(td, td->td_retval[0],
634 F_SETFD, FD_CLOEXEC);
635 if (retval_socket) {
636 (void)kern_close(td, td->td_retval[0]);
637 goto out;
638 }
639 }
640
641 if (bsd_args.type == SOCK_RAW
642 && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
643 && bsd_args.domain == PF_INET) {
644 /* It's a raw IP socket: set the IP_HDRINCL option. */
645 int hdrincl;
646
647 hdrincl = 1;
648 /* We ignore any error returned by kern_setsockopt() */
649 kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
650 &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
651 }
652 #ifdef INET6
653 /*
654 * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
655 * default and some apps depend on this. So, set V6ONLY to 0
656 * for Linux apps if the sysctl value is set to 1.
657 */
658 if (bsd_args.domain == PF_INET6
659 #ifndef KLD_MODULE
660 /*
661 * XXX: Avoid undefined symbol error with an IPv4 only
662 * kernel.
663 */
664 && ip6_v6only
665 #endif
666 ) {
667 int v6only;
668
669 v6only = 0;
670 /* We ignore any error returned by setsockopt() */
671 kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
672 &v6only, UIO_SYSSPACE, sizeof(v6only));
673 }
674 #endif
675
676 out:
677 return (retval_socket);
678 }
679
680 struct linux_bind_args {
681 int s;
682 l_uintptr_t name;
683 int namelen;
684 };
685
686 static int
687 linux_bind(struct thread *td, struct linux_bind_args *args)
688 {
689 struct sockaddr *sa;
690 int error;
691
692 error = linux_getsockaddr(&sa, PTRIN(args->name),
693 args->namelen);
694 if (error)
695 return (error);
696
697 error = kern_bind(td, args->s, sa);
698 free(sa, M_SONAME);
699 if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
700 return (EINVAL);
701 return (error);
702 }
703
704 struct linux_connect_args {
705 int s;
706 l_uintptr_t name;
707 int namelen;
708 };
709 int linux_connect(struct thread *, struct linux_connect_args *);
710
711 int
712 linux_connect(struct thread *td, struct linux_connect_args *args)
713 {
714 struct socket *so;
715 struct sockaddr *sa;
716 u_int fflag;
717 int error;
718
719 error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
720 args->namelen);
721 if (error)
722 return (error);
723
724 error = kern_connect(td, args->s, sa);
725 free(sa, M_SONAME);
726 if (error != EISCONN)
727 return (error);
728
729 /*
730 * Linux doesn't return EISCONN the first time it occurs,
731 * when on a non-blocking socket. Instead it returns the
732 * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
733 *
734 * XXXRW: Instead of using fgetsock(), check that it is a
735 * socket and use the file descriptor reference instead of
736 * creating a new one.
737 */
738 error = fgetsock(td, args->s, &so, &fflag);
739 if (error == 0) {
740 error = EISCONN;
741 if (fflag & FNONBLOCK) {
742 SOCK_LOCK(so);
743 if (so->so_emuldata == 0)
744 error = so->so_error;
745 so->so_emuldata = (void *)1;
746 SOCK_UNLOCK(so);
747 }
748 fputsock(so);
749 }
750 return (error);
751 }
752
753 struct linux_listen_args {
754 int s;
755 int backlog;
756 };
757
758 static int
759 linux_listen(struct thread *td, struct linux_listen_args *args)
760 {
761 struct listen_args /* {
762 int s;
763 int backlog;
764 } */ bsd_args;
765
766 bsd_args.s = args->s;
767 bsd_args.backlog = args->backlog;
768 return (listen(td, &bsd_args));
769 }
770
771 struct linux_accept_args {
772 int s;
773 l_uintptr_t addr;
774 l_uintptr_t namelen;
775 };
776
777 static int
778 linux_accept(struct thread *td, struct linux_accept_args *args)
779 {
780 struct accept_args /* {
781 int s;
782 struct sockaddr * __restrict name;
783 socklen_t * __restrict anamelen;
784 } */ bsd_args;
785 int error, fd;
786
787 bsd_args.s = args->s;
788 /* XXX: */
789 bsd_args.name = (struct sockaddr * __restrict)PTRIN(args->addr);
790 bsd_args.anamelen = PTRIN(args->namelen);/* XXX */
791 error = accept(td, &bsd_args);
792 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
793 if (error) {
794 if (error == EFAULT && args->namelen != sizeof(struct sockaddr_in))
795 return (EINVAL);
796 return (error);
797 }
798 if (args->addr) {
799 error = linux_sa_put(PTRIN(args->addr));
800 if (error) {
801 (void)kern_close(td, td->td_retval[0]);
802 return (error);
803 }
804 }
805
806 /*
807 * linux appears not to copy flags from the parent socket to the
808 * accepted one, so we must clear the flags in the new descriptor.
809 * Ignore any errors, because we already have an open fd.
810 */
811 fd = td->td_retval[0];
812 (void)kern_fcntl(td, fd, F_SETFL, 0);
813 td->td_retval[0] = fd;
814 return (0);
815 }
816
817 struct linux_getsockname_args {
818 int s;
819 l_uintptr_t addr;
820 l_uintptr_t namelen;
821 };
822
823 static int
824 linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
825 {
826 struct getsockname_args /* {
827 int fdes;
828 struct sockaddr * __restrict asa;
829 socklen_t * __restrict alen;
830 } */ bsd_args;
831 int error;
832
833 bsd_args.fdes = args->s;
834 /* XXX: */
835 bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
836 bsd_args.alen = PTRIN(args->namelen); /* XXX */
837 error = getsockname(td, &bsd_args);
838 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
839 if (error)
840 return (error);
841 error = linux_sa_put(PTRIN(args->addr));
842 if (error)
843 return (error);
844 return (0);
845 }
846
847 struct linux_getpeername_args {
848 int s;
849 l_uintptr_t addr;
850 l_uintptr_t namelen;
851 };
852
853 static int
854 linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
855 {
856 struct getpeername_args /* {
857 int fdes;
858 caddr_t asa;
859 int *alen;
860 } */ bsd_args;
861 int error;
862
863 bsd_args.fdes = args->s;
864 bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
865 bsd_args.alen = (int *)PTRIN(args->namelen);
866 error = getpeername(td, &bsd_args);
867 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
868 if (error)
869 return (error);
870 error = linux_sa_put(PTRIN(args->addr));
871 if (error)
872 return (error);
873 return (0);
874 }
875
876 struct linux_socketpair_args {
877 int domain;
878 int type;
879 int protocol;
880 l_uintptr_t rsv;
881 };
882
883 static int
884 linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
885 {
886 struct socketpair_args /* {
887 int domain;
888 int type;
889 int protocol;
890 int *rsv;
891 } */ bsd_args;
892
893 bsd_args.domain = linux_to_bsd_domain(args->domain);
894 if (bsd_args.domain != PF_LOCAL)
895 return (EAFNOSUPPORT);
896
897 bsd_args.type = args->type;
898 if (args->protocol != 0 && args->protocol != PF_UNIX)
899
900 /*
901 * Use of PF_UNIX as protocol argument is not right,
902 * but Linux does it.
903 * Do not map PF_UNIX as its Linux value is identical
904 * to FreeBSD one.
905 */
906 return (EPROTONOSUPPORT);
907 else
908 bsd_args.protocol = 0;
909 bsd_args.rsv = (int *)PTRIN(args->rsv);
910 return (socketpair(td, &bsd_args));
911 }
912
913 struct linux_send_args {
914 int s;
915 l_uintptr_t msg;
916 int len;
917 int flags;
918 };
919
920 static int
921 linux_send(struct thread *td, struct linux_send_args *args)
922 {
923 struct sendto_args /* {
924 int s;
925 caddr_t buf;
926 int len;
927 int flags;
928 caddr_t to;
929 int tolen;
930 } */ bsd_args;
931
932 bsd_args.s = args->s;
933 bsd_args.buf = (caddr_t)PTRIN(args->msg);
934 bsd_args.len = args->len;
935 bsd_args.flags = args->flags;
936 bsd_args.to = NULL;
937 bsd_args.tolen = 0;
938 return sendto(td, &bsd_args);
939 }
940
941 struct linux_recv_args {
942 int s;
943 l_uintptr_t msg;
944 int len;
945 int flags;
946 };
947
948 static int
949 linux_recv(struct thread *td, struct linux_recv_args *args)
950 {
951 struct recvfrom_args /* {
952 int s;
953 caddr_t buf;
954 int len;
955 int flags;
956 struct sockaddr *from;
957 socklen_t fromlenaddr;
958 } */ bsd_args;
959
960 bsd_args.s = args->s;
961 bsd_args.buf = (caddr_t)PTRIN(args->msg);
962 bsd_args.len = args->len;
963 bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
964 bsd_args.from = NULL;
965 bsd_args.fromlenaddr = 0;
966 return (recvfrom(td, &bsd_args));
967 }
968
969 static int
970 linux_sendto(struct thread *td, struct linux_sendto_args *args)
971 {
972 struct msghdr msg;
973 struct iovec aiov;
974 int error;
975
976 if (linux_check_hdrincl(td, args->s) == 0)
977 /* IP_HDRINCL set, tweak the packet before sending */
978 return (linux_sendto_hdrincl(td, args));
979
980 msg.msg_name = PTRIN(args->to);
981 msg.msg_namelen = args->tolen;
982 msg.msg_iov = &aiov;
983 msg.msg_iovlen = 1;
984 msg.msg_control = NULL;
985 msg.msg_flags = 0;
986 aiov.iov_base = PTRIN(args->msg);
987 aiov.iov_len = args->len;
988 error = linux_sendit(td, args->s, &msg, args->flags, NULL,
989 UIO_USERSPACE);
990 return (error);
991 }
992
993 struct linux_recvfrom_args {
994 int s;
995 l_uintptr_t buf;
996 int len;
997 int flags;
998 l_uintptr_t from;
999 l_uintptr_t fromlen;
1000 };
1001
1002 static int
1003 linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
1004 {
1005 struct recvfrom_args /* {
1006 int s;
1007 caddr_t buf;
1008 size_t len;
1009 int flags;
1010 struct sockaddr * __restrict from;
1011 socklen_t * __restrict fromlenaddr;
1012 } */ bsd_args;
1013 size_t len;
1014 int error;
1015
1016 if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t))))
1017 return (error);
1018
1019 bsd_args.s = args->s;
1020 bsd_args.buf = PTRIN(args->buf);
1021 bsd_args.len = args->len;
1022 bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
1023 /* XXX: */
1024 bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from);
1025 bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */
1026
1027 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
1028 error = recvfrom(td, &bsd_args);
1029 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.from);
1030
1031 if (error)
1032 return (error);
1033 if (args->from) {
1034 error = linux_sa_put((struct osockaddr *)
1035 PTRIN(args->from));
1036 if (error)
1037 return (error);
1038 }
1039 return (0);
1040 }
1041
1042 struct linux_sendmsg_args {
1043 int s;
1044 l_uintptr_t msg;
1045 int flags;
1046 };
1047
1048 static int
1049 linux_sendmsg(struct thread *td, struct linux_sendmsg_args *args)
1050 {
1051 struct cmsghdr *cmsg;
1052 struct mbuf *control;
1053 struct msghdr msg;
1054 struct l_cmsghdr linux_cmsg;
1055 struct l_cmsghdr *ptr_cmsg;
1056 struct l_msghdr linux_msg;
1057 struct iovec *iov;
1058 socklen_t datalen;
1059 void *data;
1060 int error;
1061
1062 error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
1063 if (error)
1064 return (error);
1065 error = linux_to_bsd_msghdr(&msg, &linux_msg);
1066 if (error)
1067 return (error);
1068
1069 /*
1070 * Some Linux applications (ping) define a non-NULL control data
1071 * pointer, but a msg_controllen of 0, which is not allowed in the
1072 * FreeBSD system call interface. NULL the msg_control pointer in
1073 * order to handle this case. This should be checked, but allows the
1074 * Linux ping to work.
1075 */
1076 if (msg.msg_control != NULL && msg.msg_controllen == 0)
1077 msg.msg_control = NULL;
1078
1079 #ifdef COMPAT_LINUX32
1080 error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
1081 &iov, EMSGSIZE);
1082 #else
1083 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1084 #endif
1085 if (error)
1086 return (error);
1087
1088 if (msg.msg_control != NULL) {
1089 error = ENOBUFS;
1090 cmsg = malloc(CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
1091 control = m_get(M_WAIT, MT_CONTROL);
1092 if (control == NULL)
1093 goto bad;
1094 ptr_cmsg = LINUX_CMSG_FIRSTHDR(&msg);
1095
1096 do {
1097 error = copyin(ptr_cmsg, &linux_cmsg,
1098 sizeof(struct l_cmsghdr));
1099 if (error)
1100 goto bad;
1101
1102 error = EINVAL;
1103 if (linux_cmsg.cmsg_len < sizeof(struct l_cmsghdr))
1104 goto bad;
1105
1106 /*
1107 * Now we support only SCM_RIGHTS, so return EINVAL
1108 * in any other cmsg_type
1109 */
1110 if ((cmsg->cmsg_type =
1111 linux_to_bsd_cmsg_type(linux_cmsg.cmsg_type)) == -1)
1112 goto bad;
1113 cmsg->cmsg_level =
1114 linux_to_bsd_sockopt_level(linux_cmsg.cmsg_level);
1115
1116 datalen = linux_cmsg.cmsg_len - L_CMSG_HDRSZ;
1117 cmsg->cmsg_len = CMSG_LEN(datalen);
1118 data = LINUX_CMSG_DATA(ptr_cmsg);
1119
1120 error = ENOBUFS;
1121 if (!m_append(control, CMSG_HDRSZ, (c_caddr_t) cmsg))
1122 goto bad;
1123 if (!m_append(control, datalen, (c_caddr_t) data))
1124 goto bad;
1125 } while ((ptr_cmsg = LINUX_CMSG_NXTHDR(&msg, ptr_cmsg)));
1126 } else {
1127 control = NULL;
1128 cmsg = NULL;
1129 }
1130
1131 msg.msg_iov = iov;
1132 msg.msg_flags = 0;
1133 error = linux_sendit(td, args->s, &msg, args->flags, control,
1134 UIO_USERSPACE);
1135
1136 bad:
1137 free(iov, M_IOV);
1138 if (cmsg)
1139 free(cmsg, M_TEMP);
1140 return (error);
1141 }
1142
1143 struct linux_recvmsg_args {
1144 int s;
1145 l_uintptr_t msg;
1146 int flags;
1147 };
1148
1149 static int
1150 linux_recvmsg(struct thread *td, struct linux_recvmsg_args *args)
1151 {
1152 struct cmsghdr *cm;
1153 struct msghdr msg;
1154 struct l_cmsghdr *linux_cmsg = NULL;
1155 socklen_t datalen, outlen, clen;
1156 struct l_msghdr linux_msg;
1157 struct iovec *iov, *uiov;
1158 struct mbuf *control = NULL;
1159 struct mbuf **controlp;
1160 caddr_t outbuf;
1161 void *data;
1162 int error, i, fd, fds, *fdp;
1163
1164 error = copyin(PTRIN(args->msg), &linux_msg, sizeof(linux_msg));
1165 if (error)
1166 return (error);
1167
1168 error = linux_to_bsd_msghdr(&msg, &linux_msg);
1169 if (error)
1170 return (error);
1171
1172 #ifdef COMPAT_LINUX32
1173 error = linux32_copyiniov(PTRIN(msg.msg_iov), msg.msg_iovlen,
1174 &iov, EMSGSIZE);
1175 #else
1176 error = copyiniov(msg.msg_iov, msg.msg_iovlen, &iov, EMSGSIZE);
1177 #endif
1178 if (error)
1179 return (error);
1180
1181 if (msg.msg_name) {
1182 error = linux_to_bsd_sockaddr((struct sockaddr *)msg.msg_name,
1183 msg.msg_namelen);
1184 if (error)
1185 goto bad;
1186 }
1187
1188 uiov = msg.msg_iov;
1189 msg.msg_iov = iov;
1190 controlp = (msg.msg_control != NULL) ? &control : NULL;
1191 error = kern_recvit(td, args->s, &msg, UIO_USERSPACE, controlp);
1192 msg.msg_iov = uiov;
1193 if (error)
1194 goto bad;
1195
1196 error = bsd_to_linux_msghdr(&msg, &linux_msg);
1197 if (error)
1198 goto bad;
1199
1200 if (linux_msg.msg_name) {
1201 error = bsd_to_linux_sockaddr((struct sockaddr *)
1202 PTRIN(linux_msg.msg_name));
1203 if (error)
1204 goto bad;
1205 }
1206 if (linux_msg.msg_name && linux_msg.msg_namelen > 2) {
1207 error = linux_sa_put(PTRIN(linux_msg.msg_name));
1208 if (error)
1209 goto bad;
1210 }
1211
1212 if (control) {
1213
1214 linux_cmsg = malloc(L_CMSG_HDRSZ, M_TEMP, M_WAITOK | M_ZERO);
1215 outbuf = PTRIN(linux_msg.msg_control);
1216 cm = mtod(control, struct cmsghdr *);
1217 outlen = 0;
1218 clen = control->m_len;
1219
1220 while (cm != NULL) {
1221
1222 if ((linux_cmsg->cmsg_type =
1223 bsd_to_linux_cmsg_type(cm->cmsg_type)) == -1)
1224 {
1225 error = EINVAL;
1226 goto bad;
1227 }
1228 data = CMSG_DATA(cm);
1229 datalen = (caddr_t)cm + cm->cmsg_len - (caddr_t)data;
1230
1231 switch (linux_cmsg->cmsg_type)
1232 {
1233 case LINUX_SCM_RIGHTS:
1234 if (outlen + LINUX_CMSG_LEN(datalen) >
1235 linux_msg.msg_controllen) {
1236 if (outlen == 0) {
1237 error = EMSGSIZE;
1238 goto bad;
1239 } else {
1240 linux_msg.msg_flags |=
1241 LINUX_MSG_CTRUNC;
1242 goto out;
1243 }
1244 }
1245 if (args->flags & LINUX_MSG_CMSG_CLOEXEC) {
1246 fds = datalen / sizeof(int);
1247 fdp = data;
1248 for (i = 0; i < fds; i++) {
1249 fd = *fdp++;
1250 (void)kern_fcntl(td, fd,
1251 F_SETFD, FD_CLOEXEC);
1252 }
1253 }
1254 break;
1255 }
1256
1257 linux_cmsg->cmsg_len = LINUX_CMSG_LEN(datalen);
1258 linux_cmsg->cmsg_level =
1259 bsd_to_linux_sockopt_level(cm->cmsg_level);
1260
1261 error = copyout(linux_cmsg, outbuf, L_CMSG_HDRSZ);
1262 if (error)
1263 goto bad;
1264 outbuf += L_CMSG_HDRSZ;
1265
1266 error = copyout(data, outbuf, datalen);
1267 if (error)
1268 goto bad;
1269
1270 outbuf += LINUX_CMSG_ALIGN(datalen);
1271 outlen += LINUX_CMSG_LEN(datalen);
1272 linux_msg.msg_controllen = outlen;
1273
1274 if (CMSG_SPACE(datalen) < clen) {
1275 clen -= CMSG_SPACE(datalen);
1276 cm = (struct cmsghdr *)
1277 ((caddr_t)cm + CMSG_SPACE(datalen));
1278 } else
1279 cm = NULL;
1280 }
1281 }
1282
1283 out:
1284 error = copyout(&linux_msg, PTRIN(args->msg), sizeof(linux_msg));
1285
1286 bad:
1287 free(iov, M_IOV);
1288 if (control != NULL)
1289 m_freem(control);
1290 if (linux_cmsg != NULL)
1291 free(linux_cmsg, M_TEMP);
1292
1293 return (error);
1294 }
1295
1296 struct linux_shutdown_args {
1297 int s;
1298 int how;
1299 };
1300
1301 static int
1302 linux_shutdown(struct thread *td, struct linux_shutdown_args *args)
1303 {
1304 struct shutdown_args /* {
1305 int s;
1306 int how;
1307 } */ bsd_args;
1308
1309 bsd_args.s = args->s;
1310 bsd_args.how = args->how;
1311 return (shutdown(td, &bsd_args));
1312 }
1313
1314 struct linux_setsockopt_args {
1315 int s;
1316 int level;
1317 int optname;
1318 l_uintptr_t optval;
1319 int optlen;
1320 };
1321
1322 static int
1323 linux_setsockopt(struct thread *td, struct linux_setsockopt_args *args)
1324 {
1325 struct setsockopt_args /* {
1326 int s;
1327 int level;
1328 int name;
1329 caddr_t val;
1330 int valsize;
1331 } */ bsd_args;
1332 l_timeval linux_tv;
1333 struct timeval tv;
1334 int error, name;
1335
1336 bsd_args.s = args->s;
1337 bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1338 switch (bsd_args.level) {
1339 case SOL_SOCKET:
1340 name = linux_to_bsd_so_sockopt(args->optname);
1341 switch (name) {
1342 case SO_RCVTIMEO:
1343 /* FALLTHROUGH */
1344 case SO_SNDTIMEO:
1345 error = copyin(PTRIN(args->optval), &linux_tv,
1346 sizeof(linux_tv));
1347 if (error)
1348 return (error);
1349 tv.tv_sec = linux_tv.tv_sec;
1350 tv.tv_usec = linux_tv.tv_usec;
1351 return (kern_setsockopt(td, args->s, bsd_args.level,
1352 name, &tv, UIO_SYSSPACE, sizeof(tv)));
1353 /* NOTREACHED */
1354 break;
1355 default:
1356 break;
1357 }
1358 break;
1359 case IPPROTO_IP:
1360 name = linux_to_bsd_ip_sockopt(args->optname);
1361 break;
1362 case IPPROTO_TCP:
1363 /* Linux TCP option values match BSD's */
1364 name = args->optname;
1365 break;
1366 default:
1367 name = -1;
1368 break;
1369 }
1370 if (name == -1)
1371 return (ENOPROTOOPT);
1372
1373 bsd_args.name = name;
1374 bsd_args.val = PTRIN(args->optval);
1375 bsd_args.valsize = args->optlen;
1376
1377 if (name == IPV6_NEXTHOP) {
1378 linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.val,
1379 bsd_args.valsize);
1380 error = setsockopt(td, &bsd_args);
1381 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1382 } else
1383 error = setsockopt(td, &bsd_args);
1384
1385 return (error);
1386 }
1387
1388 struct linux_getsockopt_args {
1389 int s;
1390 int level;
1391 int optname;
1392 l_uintptr_t optval;
1393 l_uintptr_t optlen;
1394 };
1395
1396 static int
1397 linux_getsockopt(struct thread *td, struct linux_getsockopt_args *args)
1398 {
1399 struct getsockopt_args /* {
1400 int s;
1401 int level;
1402 int name;
1403 caddr_t val;
1404 int *avalsize;
1405 } */ bsd_args;
1406 l_timeval linux_tv;
1407 struct timeval tv;
1408 socklen_t tv_len, xulen;
1409 struct xucred xu;
1410 struct l_ucred lxu;
1411 int error, name;
1412
1413 bsd_args.s = args->s;
1414 bsd_args.level = linux_to_bsd_sockopt_level(args->level);
1415 switch (bsd_args.level) {
1416 case SOL_SOCKET:
1417 name = linux_to_bsd_so_sockopt(args->optname);
1418 switch (name) {
1419 case SO_RCVTIMEO:
1420 /* FALLTHROUGH */
1421 case SO_SNDTIMEO:
1422 tv_len = sizeof(tv);
1423 error = kern_getsockopt(td, args->s, bsd_args.level,
1424 name, &tv, UIO_SYSSPACE, &tv_len);
1425 if (error)
1426 return (error);
1427 linux_tv.tv_sec = tv.tv_sec;
1428 linux_tv.tv_usec = tv.tv_usec;
1429 return (copyout(&linux_tv, PTRIN(args->optval),
1430 sizeof(linux_tv)));
1431 /* NOTREACHED */
1432 break;
1433 case LOCAL_PEERCRED:
1434 if (args->optlen != sizeof(lxu))
1435 return (EINVAL);
1436 xulen = sizeof(xu);
1437 error = kern_getsockopt(td, args->s, bsd_args.level,
1438 name, &xu, UIO_SYSSPACE, &xulen);
1439 if (error)
1440 return (error);
1441 /*
1442 * XXX Use 0 for pid as the FreeBSD does not cache peer pid.
1443 */
1444 lxu.pid = 0;
1445 lxu.uid = xu.cr_uid;
1446 lxu.gid = xu.cr_gid;
1447 return (copyout(&lxu, PTRIN(args->optval), sizeof(lxu)));
1448 /* NOTREACHED */
1449 break;
1450 default:
1451 break;
1452 }
1453 break;
1454 case IPPROTO_IP:
1455 name = linux_to_bsd_ip_sockopt(args->optname);
1456 break;
1457 case IPPROTO_TCP:
1458 /* Linux TCP option values match BSD's */
1459 name = args->optname;
1460 break;
1461 default:
1462 name = -1;
1463 break;
1464 }
1465 if (name == -1)
1466 return (EINVAL);
1467
1468 bsd_args.name = name;
1469 bsd_args.val = PTRIN(args->optval);
1470 bsd_args.avalsize = PTRIN(args->optlen);
1471
1472 if (name == IPV6_NEXTHOP) {
1473 error = getsockopt(td, &bsd_args);
1474 bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.val);
1475 } else
1476 error = getsockopt(td, &bsd_args);
1477
1478 return (error);
1479 }
1480
1481 /* Argument list sizes for linux_socketcall */
1482
1483 #define LINUX_AL(x) ((x) * sizeof(l_ulong))
1484
1485 static const unsigned char lxs_args[] = {
1486 LINUX_AL(0) /* unused*/, LINUX_AL(3) /* socket */,
1487 LINUX_AL(3) /* bind */, LINUX_AL(3) /* connect */,
1488 LINUX_AL(2) /* listen */, LINUX_AL(3) /* accept */,
1489 LINUX_AL(3) /* getsockname */, LINUX_AL(3) /* getpeername */,
1490 LINUX_AL(4) /* socketpair */, LINUX_AL(4) /* send */,
1491 LINUX_AL(4) /* recv */, LINUX_AL(6) /* sendto */,
1492 LINUX_AL(6) /* recvfrom */, LINUX_AL(2) /* shutdown */,
1493 LINUX_AL(5) /* setsockopt */, LINUX_AL(5) /* getsockopt */,
1494 LINUX_AL(3) /* sendmsg */, LINUX_AL(3) /* recvmsg */
1495 };
1496
1497 #define LINUX_AL_SIZE sizeof(lxs_args) / sizeof(lxs_args[0]) - 1
1498
1499 int
1500 linux_socketcall(struct thread *td, struct linux_socketcall_args *args)
1501 {
1502 l_ulong a[6];
1503 void *arg;
1504 int error;
1505
1506 if (args->what < LINUX_SOCKET || args->what > LINUX_AL_SIZE)
1507 return (EINVAL);
1508 error = copyin(PTRIN(args->args), a, lxs_args[args->what]);
1509 if (error)
1510 return (error);
1511
1512 arg = a;
1513 switch (args->what) {
1514 case LINUX_SOCKET:
1515 return (linux_socket(td, arg));
1516 case LINUX_BIND:
1517 return (linux_bind(td, arg));
1518 case LINUX_CONNECT:
1519 return (linux_connect(td, arg));
1520 case LINUX_LISTEN:
1521 return (linux_listen(td, arg));
1522 case LINUX_ACCEPT:
1523 return (linux_accept(td, arg));
1524 case LINUX_GETSOCKNAME:
1525 return (linux_getsockname(td, arg));
1526 case LINUX_GETPEERNAME:
1527 return (linux_getpeername(td, arg));
1528 case LINUX_SOCKETPAIR:
1529 return (linux_socketpair(td, arg));
1530 case LINUX_SEND:
1531 return (linux_send(td, arg));
1532 case LINUX_RECV:
1533 return (linux_recv(td, arg));
1534 case LINUX_SENDTO:
1535 return (linux_sendto(td, arg));
1536 case LINUX_RECVFROM:
1537 return (linux_recvfrom(td, arg));
1538 case LINUX_SHUTDOWN:
1539 return (linux_shutdown(td, arg));
1540 case LINUX_SETSOCKOPT:
1541 return (linux_setsockopt(td, arg));
1542 case LINUX_GETSOCKOPT:
1543 return (linux_getsockopt(td, arg));
1544 case LINUX_SENDMSG:
1545 return (linux_sendmsg(td, arg));
1546 case LINUX_RECVMSG:
1547 return (linux_recvmsg(td, arg));
1548 }
1549
1550 uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what);
1551 return (ENOSYS);
1552 }
Cache object: a18fe53d32ac8538781a33d665adf99e
|