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