[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linux/linux_socket.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  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: src/sys/compat/linux/linux_socket.c,v 1.80 2008/12/02 21:37:28 bz Exp $");
 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 #include <sys/vimage.h>
 54 
 55 #include <net/if.h>
 56 #include <netinet/in.h>
 57 #include <netinet/in_systm.h>
 58 #include <netinet/ip.h>
 59 #ifdef INET6
 60 #include <netinet/ip6.h>
 61 #include <netinet6/ip6_var.h>
 62 #include <netinet6/in6_var.h>
 63 #include <netinet6/vinet6.h>
 64 #endif
 65 
 66 #ifdef COMPAT_LINUX32
 67 #include <machine/../linux32/linux.h>
 68 #include <machine/../linux32/linux32_proto.h>
 69 #else
 70 #include <machine/../linux/linux.h>
 71 #include <machine/../linux/linux_proto.h>
 72 #endif
 73 #include <compat/linux/linux_socket.h>
 74 #include <compat/linux/linux_util.h>
 75 
 76 static int do_sa_get(struct sockaddr **, const struct osockaddr *, int *,
 77     struct malloc_type *);
 78 static int linux_to_bsd_domain(int);
 79 
 80 /*
 81  * Reads a linux sockaddr and does any necessary translation.
 82  * Linux sockaddrs don't have a length field, only a family.
 83  */
 84 static int
 85 linux_getsockaddr(struct sockaddr **sap, const struct osockaddr *osa, int len)
 86 {
 87         int osalen = len;
 88 
 89         return (do_sa_get(sap, osa, &osalen, M_SONAME));
 90 }
 91 
 92 /*
 93  * Copy the osockaddr structure pointed to by osa to kernel, adjust
 94  * family and convert to sockaddr.
 95  */
 96 static int
 97 do_sa_get(struct sockaddr **sap, const struct osockaddr *osa, int *osalen,
 98     struct malloc_type *mtype)
 99 {
100         int error=0, bdom;
101         struct sockaddr *sa;
102         struct osockaddr *kosa;
103         int alloclen;
104 #ifdef INET6
105         int oldv6size;
106         struct sockaddr_in6 *sin6;
107 #endif
108 
109         if (*osalen < 2 || *osalen > UCHAR_MAX || !osa)
110                 return (EINVAL);
111 
112         alloclen = *osalen;
113 #ifdef INET6
114         oldv6size = 0;
115         /*
116          * Check for old (pre-RFC2553) sockaddr_in6. We may accept it
117          * if it's a v4-mapped address, so reserve the proper space
118          * for it.
119          */
120         if (alloclen == sizeof (struct sockaddr_in6) - sizeof (u_int32_t)) {
121                 alloclen = sizeof (struct sockaddr_in6);
122                 oldv6size = 1;
123         }
124 #endif
125 
126         kosa = malloc(alloclen, mtype, M_WAITOK);
127 
128         if ((error = copyin(osa, kosa, *osalen)))
129                 goto out;
130 
131         bdom = linux_to_bsd_domain(kosa->sa_family);
132         if (bdom == -1) {
133                 error = EINVAL;
134                 goto out;
135         }
136 
137 #ifdef INET6
138         /*
139          * Older Linux IPv6 code uses obsolete RFC2133 struct sockaddr_in6,
140          * which lacks the scope id compared with RFC2553 one. If we detect
141          * the situation, reject the address and write a message to system log.
142          *
143          * Still accept addresses for which the scope id is not used.
144          */
145         if (oldv6size && bdom == AF_INET6) {
146                 sin6 = (struct sockaddr_in6 *)kosa;
147                 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr) ||
148                     (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) &&
149                      !IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr) &&
150                      !IN6_IS_ADDR_V4COMPAT(&sin6->sin6_addr) &&
151                      !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
152                      !IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))) {
153                         sin6->sin6_scope_id = 0;
154                 } else {
155                         log(LOG_DEBUG,
156                             "obsolete pre-RFC2553 sockaddr_in6 rejected\n");
157                         error = EINVAL;
158                         goto out;
159                 }
160         } else
161 #endif
162         if (bdom == AF_INET)
163                 alloclen = sizeof(struct sockaddr_in);
164 
165         sa = (struct sockaddr *) kosa;
166         sa->sa_family = bdom;
167         sa->sa_len = alloclen;
168 
169         *sap = sa;
170         *osalen = alloclen;
171         return (0);
172 
173 out:
174         free(kosa, mtype);
175         return (error);
176 }
177 
178 static int
179 linux_to_bsd_domain(int domain)
180 {
181 
182         switch (domain) {
183         case LINUX_AF_UNSPEC:
184                 return (AF_UNSPEC);
185         case LINUX_AF_UNIX:
186                 return (AF_LOCAL);
187         case LINUX_AF_INET:
188                 return (AF_INET);
189         case LINUX_AF_INET6:
190                 return (AF_INET6);
191         case LINUX_AF_AX25:
192                 return (AF_CCITT);
193         case LINUX_AF_IPX:
194                 return (AF_IPX);
195         case LINUX_AF_APPLETALK:
196                 return (AF_APPLETALK);
197         }
198         return (-1);
199 }
200 
201 static int
202 bsd_to_linux_domain(int domain)
203 {
204 
205         switch (domain) {
206         case AF_UNSPEC:
207                 return (LINUX_AF_UNSPEC);
208         case AF_LOCAL:
209                 return (LINUX_AF_UNIX);
210         case AF_INET:
211                 return (LINUX_AF_INET);
212         case AF_INET6:
213                 return (LINUX_AF_INET6);
214         case AF_CCITT:
215                 return (LINUX_AF_AX25);
216         case AF_IPX:
217                 return (LINUX_AF_IPX);
218         case AF_APPLETALK:
219                 return (LINUX_AF_APPLETALK);
220         }
221         return (-1);
222 }
223 
224 static int
225 linux_to_bsd_sockopt_level(int level)
226 {
227 
228         switch (level) {
229         case LINUX_SOL_SOCKET:
230                 return (SOL_SOCKET);
231         }
232         return (level);
233 }
234 
235 static int
236 bsd_to_linux_sockopt_level(int level)
237 {
238 
239         switch (level) {
240         case SOL_SOCKET:
241                 return (LINUX_SOL_SOCKET);
242         }
243         return (level);
244 }
245 
246 static int
247 linux_to_bsd_ip_sockopt(int opt)
248 {
249 
250         switch (opt) {
251         case LINUX_IP_TOS:
252                 return (IP_TOS);
253         case LINUX_IP_TTL:
254                 return (IP_TTL);
255         case LINUX_IP_OPTIONS:
256                 return (IP_OPTIONS);
257         case LINUX_IP_MULTICAST_IF:
258                 return (IP_MULTICAST_IF);
259         case LINUX_IP_MULTICAST_TTL:
260                 return (IP_MULTICAST_TTL);
261         case LINUX_IP_MULTICAST_LOOP:
262                 return (IP_MULTICAST_LOOP);
263         case LINUX_IP_ADD_MEMBERSHIP:
264                 return (IP_ADD_MEMBERSHIP);
265         case LINUX_IP_DROP_MEMBERSHIP:
266                 return (IP_DROP_MEMBERSHIP);
267         case LINUX_IP_HDRINCL:
268                 return (IP_HDRINCL);
269         }
270         return (-1);
271 }
272 
273 static int
274 linux_to_bsd_so_sockopt(int opt)
275 {
276 
277         switch (opt) {
278         case LINUX_SO_DEBUG:
279                 return (SO_DEBUG);
280         case LINUX_SO_REUSEADDR:
281                 return (SO_REUSEADDR);
282         case LINUX_SO_TYPE:
283                 return (SO_TYPE);
284         case LINUX_SO_ERROR:
285                 return (SO_ERROR);
286         case LINUX_SO_DONTROUTE:
287                 return (SO_DONTROUTE);
288         case LINUX_SO_BROADCAST:
289                 return (SO_BROADCAST);
290         case LINUX_SO_SNDBUF:
291                 return (SO_SNDBUF);
292         case LINUX_SO_RCVBUF:
293                 return (SO_RCVBUF);
294         case LINUX_SO_KEEPALIVE:
295                 return (SO_KEEPALIVE);
296         case LINUX_SO_OOBINLINE:
297                 return (SO_OOBINLINE);
298         case LINUX_SO_LINGER:
299                 return (SO_LINGER);
300         case LINUX_SO_PEERCRED:
301                 return (LOCAL_PEERCRED);
302         case LINUX_SO_RCVLOWAT:
303                 return (SO_RCVLOWAT);
304         case LINUX_SO_SNDLOWAT:
305                 return (SO_SNDLOWAT);
306         case LINUX_SO_RCVTIMEO:
307                 return (SO_RCVTIMEO);
308         case LINUX_SO_SNDTIMEO:
309                 return (SO_SNDTIMEO);
310         case LINUX_SO_TIMESTAMP:
311                 return (SO_TIMESTAMP);
312         case LINUX_SO_ACCEPTCONN:
313                 return (SO_ACCEPTCONN);
314         }
315         return (-1);
316 }
317 
318 static int
319 linux_to_bsd_msg_flags(int flags)
320 {
321         int ret_flags = 0;
322 
323         if (flags & LINUX_MSG_OOB)
324                 ret_flags |= MSG_OOB;
325         if (flags & LINUX_MSG_PEEK)
326                 ret_flags |= MSG_PEEK;
327         if (flags & LINUX_MSG_DONTROUTE)
328                 ret_flags |= MSG_DONTROUTE;
329         if (flags & LINUX_MSG_CTRUNC)
330                 ret_flags |= MSG_CTRUNC;
331         if (flags & LINUX_MSG_TRUNC)
332                 ret_flags |= MSG_TRUNC;
333         if (flags & LINUX_MSG_DONTWAIT)
334                 ret_flags |= MSG_DONTWAIT;
335         if (flags & LINUX_MSG_EOR)
336                 ret_flags |= MSG_EOR;
337         if (flags & LINUX_MSG_WAITALL)
338                 ret_flags |= MSG_WAITALL;
339         if (flags & LINUX_MSG_NOSIGNAL)
340                 ret_flags |= MSG_NOSIGNAL;
341 #if 0 /* not handled */
342         if (flags & LINUX_MSG_PROXY)
343                 ;
344         if (flags & LINUX_MSG_FIN)
345                 ;
346         if (flags & LINUX_MSG_SYN)
347                 ;
348         if (flags & LINUX_MSG_CONFIRM)
349                 ;
350         if (flags & LINUX_MSG_RST)
351                 ;
352         if (flags & LINUX_MSG_ERRQUEUE)
353                 ;
354 #endif
355         return ret_flags;
356 }
357 
358 /*
359 * If bsd_to_linux_sockaddr() or linux_to_bsd_sockaddr() faults, then the
360 * native syscall will fault.  Thus, we don't really need to check the
361 * return values for these functions.
362 */
363 
364 static int
365 bsd_to_linux_sockaddr(struct sockaddr *arg)
366 {
367         struct sockaddr sa;
368         size_t sa_len = sizeof(struct sockaddr);
369         int error;
370         
371         if ((error = copyin(arg, &sa, sa_len)))
372                 return (error);
373         
374         *(u_short *)&sa = sa.sa_family;
375         
376         error = copyout(&sa, arg, sa_len);
377         
378         return (error);
379 }
380 
381 static int
382 linux_to_bsd_sockaddr(struct sockaddr *arg, int len)
383 {
384         struct sockaddr sa;
385         size_t sa_len = sizeof(struct sockaddr);
386         int error;
387 
388         if ((error = copyin(arg, &sa, sa_len)))
389                 return (error);
390 
391         sa.sa_family = *(sa_family_t *)&sa;
392         sa.sa_len = len;
393 
394         error = copyout(&sa, arg, sa_len);
395 
396         return (error);
397 }
398 
399 
400 static int
401 linux_sa_put(struct osockaddr *osa)
402 {
403         struct osockaddr sa;
404         int error, bdom;
405 
406         /*
407          * Only read/write the osockaddr family part, the rest is
408          * not changed.
409          */
410         error = copyin(osa, &sa, sizeof(sa.sa_family));
411         if (error)
412                 return (error);
413 
414         bdom = bsd_to_linux_domain(sa.sa_family);
415         if (bdom == -1)
416                 return (EINVAL);
417 
418         sa.sa_family = bdom;
419         error = copyout(&sa, osa, sizeof(sa.sa_family));
420         if (error)
421                 return (error);
422 
423         return (0);
424 }
425 
426 static int
427 linux_to_bsd_cmsg_type(int cmsg_type)
428 {
429 
430         switch (cmsg_type) {
431         case LINUX_SCM_RIGHTS:
432                 return (SCM_RIGHTS);
433         }
434         return (-1);
435 }
436 
437 static int
438 bsd_to_linux_cmsg_type(int cmsg_type)
439 {
440 
441         switch (cmsg_type) {
442         case SCM_RIGHTS:
443                 return (LINUX_SCM_RIGHTS);
444         }
445         return (-1);
446 }
447 
448 
449 
450 static int
451 linux_to_bsd_msghdr(struct msghdr *bhdr, const struct l_msghdr *lhdr)
452 {
453         if (lhdr->msg_controllen > INT_MAX)
454                 return (ENOBUFS);
455 
456         bhdr->msg_name          = PTRIN(lhdr->msg_name);
457         bhdr->msg_namelen       = lhdr->msg_namelen;
458         bhdr->msg_iov           = PTRIN(lhdr->msg_iov);
459         bhdr->msg_iovlen        = lhdr->msg_iovlen;
460         bhdr->msg_control       = PTRIN(lhdr->msg_control);
461         bhdr->msg_controllen    = lhdr->msg_controllen;
462         bhdr->msg_flags         = linux_to_bsd_msg_flags(lhdr->msg_flags);
463         return (0);
464 }
465 
466 static int
467 bsd_to_linux_msghdr(const struct msghdr *bhdr, struct l_msghdr *lhdr)
468 {
469         lhdr->msg_name          = PTROUT(bhdr->msg_name);
470         lhdr->msg_namelen       = bhdr->msg_namelen;
471         lhdr->msg_iov           = PTROUT(bhdr->msg_iov);
472         lhdr->msg_iovlen        = bhdr->msg_iovlen;
473         lhdr->msg_control       = PTROUT(bhdr->msg_control);
474         lhdr->msg_controllen    = bhdr->msg_controllen;
475         /* msg_flags skipped */
476         return (0);
477 }
478 
479 static int
480 linux_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
481     struct mbuf *control, enum uio_seg segflg)
482 {
483         struct sockaddr *to;
484         int error;
485 
486         if (mp->msg_name != NULL) {
487                 error = linux_getsockaddr(&to, mp->msg_name, mp->msg_namelen);
488                 if (error)
489                         return (error);
490                 mp->msg_name = to;
491         } else
492                 to = NULL;
493 
494         error = kern_sendit(td, s, mp, linux_to_bsd_msg_flags(flags), control,
495             segflg);
496 
497         if (to)
498                 free(to, M_SONAME);
499         return (error);
500 }
501 
502 /* Return 0 if IP_HDRINCL is set for the given socket. */
503 static int
504 linux_check_hdrincl(struct thread *td, int s)
505 {
506         int error, optval, size_val;
507 
508         size_val = sizeof(optval);
509         error = kern_getsockopt(td, s, IPPROTO_IP, IP_HDRINCL,
510             &optval, UIO_SYSSPACE, &size_val);
511         if (error)
512                 return (error);
513 
514         return (optval == 0);
515 }
516 
517 struct linux_sendto_args {
518         int s;
519         l_uintptr_t msg;
520         int len;
521         int flags;
522         l_uintptr_t to;
523         int tolen;
524 };
525 
526 /*
527  * Updated sendto() when IP_HDRINCL is set:
528  * tweak endian-dependent fields in the IP packet.
529  */
530 static int
531 linux_sendto_hdrincl(struct thread *td, struct linux_sendto_args *linux_args)
532 {
533 /*
534  * linux_ip_copysize defines how many bytes we should copy
535  * from the beginning of the IP packet before we customize it for BSD.
536  * It should include all the fields we modify (ip_len and ip_off).
537  */
538 #define linux_ip_copysize       8
539 
540         struct ip *packet;
541         struct msghdr msg;
542         struct iovec aiov[1];
543         int error;
544 
545         /* Check that the packet isn't too big or too small. */
546         if (linux_args->len < linux_ip_copysize ||
547             linux_args->len > IP_MAXPACKET)
548                 return (EINVAL);
549 
550         packet = (struct ip *)malloc(linux_args->len, M_TEMP, M_WAITOK);
551 
552         /* Make kernel copy of the packet to be sent */
553         if ((error = copyin(PTRIN(linux_args->msg), packet,
554             linux_args->len)))
555                 goto goout;
556 
557         /* Convert fields from Linux to BSD raw IP socket format */
558         packet->ip_len = linux_args->len;
559         packet->ip_off = ntohs(packet->ip_off);
560 
561         /* Prepare the msghdr and iovec structures describing the new packet */
562         msg.msg_name = PTRIN(linux_args->to);
563         msg.msg_namelen = linux_args->tolen;
564         msg.msg_iov = aiov;
565         msg.msg_iovlen = 1;
566         msg.msg_control = NULL;
567         msg.msg_flags = 0;
568         aiov[0].iov_base = (char *)packet;
569         aiov[0].iov_len = linux_args->len;
570         error = linux_sendit(td, linux_args->s, &msg, linux_args->flags,
571             NULL, UIO_SYSSPACE);
572 goout:
573         free(packet, M_TEMP);
574         return (error);
575 }
576 
577 struct linux_socket_args {
578         int domain;
579         int type;
580         int protocol;
581 };
582 
583 static int
584 linux_socket(struct thread *td, struct linux_socket_args *args)
585 {
586 #ifdef INET6
587         INIT_VNET_INET6(curvnet);
588 #endif
589         struct socket_args /* {
590                 int domain;
591                 int type;
592                 int protocol;
593         } */ bsd_args;
594         int retval_socket;
595 
596         bsd_args.protocol = args->protocol;
597         bsd_args.type = args->type;
598         bsd_args.domain = linux_to_bsd_domain(args->domain);
599         if (bsd_args.domain == -1)
600                 return (EINVAL);
601 
602         retval_socket = socket(td, &bsd_args);
603         if (bsd_args.type == SOCK_RAW
604             && (bsd_args.protocol == IPPROTO_RAW || bsd_args.protocol == 0)
605             && bsd_args.domain == AF_INET
606             && retval_socket >= 0) {
607                 /* It's a raw IP socket: set the IP_HDRINCL option. */
608                 int hdrincl;
609 
610                 hdrincl = 1;
611                 /* We ignore any error returned by kern_setsockopt() */
612                 kern_setsockopt(td, td->td_retval[0], IPPROTO_IP, IP_HDRINCL,
613                     &hdrincl, UIO_SYSSPACE, sizeof(hdrincl));
614         }
615 #ifdef INET6
616         /*
617          * Linux AF_INET6 socket has IPV6_V6ONLY setsockopt set to 0 by
618          * default and some apps depend on this. So, set V6ONLY to 0
619          * for Linux apps if the sysctl value is set to 1.
620          */
621         if (bsd_args.domain == PF_INET6 && retval_socket >= 0
622 #ifndef KLD_MODULE
623             /*
624              * XXX: Avoid undefined symbol error with an IPv4 only
625              * kernel.
626              */
627             && V_ip6_v6only
628 #endif
629             ) {
630                 int v6only;
631 
632                 v6only = 0;
633                 /* We ignore any error returned by setsockopt() */
634                 kern_setsockopt(td, td->td_retval[0], IPPROTO_IPV6, IPV6_V6ONLY,
635                     &v6only, UIO_SYSSPACE, sizeof(v6only));
636         }
637 #endif
638 
639         return (retval_socket);
640 }
641 
642 struct linux_bind_args {
643         int s;
644         l_uintptr_t name;
645         int namelen;
646 };
647 
648 static int
649 linux_bind(struct thread *td, struct linux_bind_args *args)
650 {
651         struct sockaddr *sa;
652         int error;
653 
654         error = linux_getsockaddr(&sa, PTRIN(args->name),
655             args->namelen);
656         if (error)
657                 return (error);
658 
659         error = kern_bind(td, args->s, sa);
660         free(sa, M_SONAME);
661         if (error == EADDRNOTAVAIL && args->namelen != sizeof(struct sockaddr_in))
662                 return (EINVAL);
663         return (error);
664 }
665 
666 struct linux_connect_args {
667         int s;
668         l_uintptr_t name;
669         int namelen;
670 };
671 int linux_connect(struct thread *, struct linux_connect_args *);
672 
673 int
674 linux_connect(struct thread *td, struct linux_connect_args *args)
675 {
676         struct socket *so;
677         struct sockaddr *sa;
678         u_int fflag;
679         int error;
680 
681         error = linux_getsockaddr(&sa, (struct osockaddr *)PTRIN(args->name),
682             args->namelen);
683         if (error)
684                 return (error);
685 
686         error = kern_connect(td, args->s, sa);
687         free(sa, M_SONAME);
688         if (error != EISCONN)
689                 return (error);
690 
691         /*
692          * Linux doesn't return EISCONN the first time it occurs,
693          * when on a non-blocking socket. Instead it returns the
694          * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD.
695          *
696          * XXXRW: Instead of using fgetsock(), check that it is a
697          * socket and use the file descriptor reference instead of
698          * creating a new one.
699          */
700         error = fgetsock(td, args->s, &so, &fflag);
701         if (error == 0) {
702                 error = EISCONN;
703                 if (fflag & FNONBLOCK) {
704                         SOCK_LOCK(so);
705                         if (so->so_emuldata == 0)
706                                 error = so->so_error;
707                         so->so_emuldata = (void *)1;
708                         SOCK_UNLOCK(so);
709                 }
710                 fputsock(so);
711         }
712         return (error);
713 }
714 
715 struct linux_listen_args {
716         int s;
717         int backlog;
718 };
719 
720 static int
721 linux_listen(struct thread *td, struct linux_listen_args *args)
722 {
723         struct listen_args /* {
724                 int s;
725                 int backlog;
726         } */ bsd_args;
727 
728         bsd_args.s = args->s;
729         bsd_args.backlog = args->backlog;
730         return (listen(td, &bsd_args));
731 }
732 
733 struct linux_accept_args {
734         int s;
735         l_uintptr_t addr;
736         l_uintptr_t namelen;
737 };
738 
739 static int
740 linux_accept(struct thread *td, struct linux_accept_args *args)
741 {
742         struct accept_args /* {
743                 int     s;
744                 struct sockaddr * __restrict name;
745                 socklen_t * __restrict anamelen;
746         } */ bsd_args;
747         int error, fd;
748 
749         bsd_args.s = args->s;
750         /* XXX: */
751         bsd_args.name = (struct sockaddr * __restrict)PTRIN(args->addr);
752         bsd_args.anamelen = PTRIN(args->namelen);/* XXX */
753         error = accept(td, &bsd_args);
754         bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.name);
755         if (error) {
756                 if (error == EFAULT && args->namelen != sizeof(struct sockaddr_in))
757                         return (EINVAL);
758                 return (error);
759         }
760         if (args->addr) {
761                 error = linux_sa_put(PTRIN(args->addr));
762                 if (error) {
763                         (void)kern_close(td, td->td_retval[0]);
764                         return (error);
765                 }
766         }
767 
768         /*
769          * linux appears not to copy flags from the parent socket to the
770          * accepted one, so we must clear the flags in the new descriptor.
771          * Ignore any errors, because we already have an open fd.
772          */
773         fd = td->td_retval[0];
774         (void)kern_fcntl(td, fd, F_SETFL, 0);
775         td->td_retval[0] = fd;
776         return (0);
777 }
778 
779 struct linux_getsockname_args {
780         int s;
781         l_uintptr_t addr;
782         l_uintptr_t namelen;
783 };
784 
785 static int
786 linux_getsockname(struct thread *td, struct linux_getsockname_args *args)
787 {
788         struct getsockname_args /* {
789                 int     fdes;
790                 struct sockaddr * __restrict asa;
791                 socklen_t * __restrict alen;
792         } */ bsd_args;
793         int error;
794 
795         bsd_args.fdes = args->s;
796         /* XXX: */
797         bsd_args.asa = (struct sockaddr * __restrict)PTRIN(args->addr);
798         bsd_args.alen = PTRIN(args->namelen);   /* XXX */
799         error = getsockname(td, &bsd_args);
800         bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
801         if (error)
802                 return (error);
803         error = linux_sa_put(PTRIN(args->addr));
804         if (error)
805                 return (error);
806         return (0);
807 }
808 
809 struct linux_getpeername_args {
810         int s;
811         l_uintptr_t addr;
812         l_uintptr_t namelen;
813 };
814 
815 static int
816 linux_getpeername(struct thread *td, struct linux_getpeername_args *args)
817 {
818         struct getpeername_args /* {
819                 int fdes;
820                 caddr_t asa;
821                 int *alen;
822         } */ bsd_args;
823         int error;
824 
825         bsd_args.fdes = args->s;
826         bsd_args.asa = (struct sockaddr *)PTRIN(args->addr);
827         bsd_args.alen = (int *)PTRIN(args->namelen);
828         error = getpeername(td, &bsd_args);
829         bsd_to_linux_sockaddr((struct sockaddr *)bsd_args.asa);
830         if (error)
831                 return (error);
832         error = linux_sa_put(PTRIN(args->addr));
833         if (error)
834                 return (error);
835         return (0);
836 }
837 
838 struct linux_socketpair_args {
839         int domain;
840         int type;
841         int protocol;
842         l_uintptr_t rsv;
843 };
844 
845 static int
846 linux_socketpair(struct thread *td, struct linux_socketpair_args *args)
847 {
848         struct socketpair_args /* {
849                 int domain;
850                 int type;
851                 int protocol;
852                 int *rsv;
853         } */ bsd_args;
854 
855         bsd_args.domain = linux_to_bsd_domain(args->domain);
856         if (bsd_args.domain == -1)
857                 return (EINVAL);
858 
859         bsd_args.type = args->type;
860         bsd_args.protocol = args->protocol;
861         bsd_args.rsv = (int *)PTRIN(args->rsv);
862         return (socketpair(td, &bsd_args));
863 }
864 
865 struct linux_send_args {
866         int s;
867         l_uintptr_t msg;
868         int len;
869         int flags;
870 };
871 
872 static int
873 linux_send(struct thread *td, struct linux_send_args *args)
874 {
875         struct sendto_args /* {
876                 int s;
877                 caddr_t buf;
878                 int len;
879                 int flags;
880                 caddr_t to;
881                 int tolen;
882         } */ bsd_args;
883 
884         bsd_args.s = args->s;
885         bsd_args.buf = (caddr_t)PTRIN(args->msg);
886         bsd_args.len = args->len;
887         bsd_args.flags = args->flags;
888         bsd_args.to = NULL;
889         bsd_args.tolen = 0;
890         return sendto(td, &bsd_args);
891 }
892 
893 struct linux_recv_args {
894         int s;
895         l_uintptr_t msg;
896         int len;
897         int flags;
898 };
899 
900 static int
901 linux_recv(struct thread *td, struct linux_recv_args *args)
902 {
903         struct recvfrom_args /* {
904                 int s;
905                 caddr_t buf;
906                 int len;
907                 int flags;
908                 struct sockaddr *from;
909                 socklen_t fromlenaddr;
910         } */ bsd_args;
911 
912         bsd_args.s = args->s;
913         bsd_args.buf = (caddr_t)PTRIN(args->msg);
914         bsd_args.len = args->len;
915         bsd_args.flags = args->flags;
916         bsd_args.from = NULL;
917         bsd_args.fromlenaddr = 0;
918         return (recvfrom(td, &bsd_args));
919 }
920 
921 static int
922 linux_sendto(struct thread *td, struct linux_sendto_args *args)
923 {
924         struct msghdr msg;
925         struct iovec aiov;
926         int error;
927 
928         if (linux_check_hdrincl(td, args->s) == 0)
929                 /* IP_HDRINCL set, tweak the packet before sending */
930                 return (linux_sendto_hdrincl(td, args));
931 
932         msg.msg_name = PTRIN(args->to);
933         msg.msg_namelen = args->tolen;
934         msg.msg_iov = &aiov;
935         msg.msg_iovlen = 1;
936         msg.msg_control = NULL;
937         msg.msg_flags = 0;
938         aiov.iov_base = PTRIN(args->msg);
939         aiov.iov_len = args->len;
940         error = linux_sendit(td, args->s, &msg, args->flags, NULL,
941             UIO_USERSPACE);
942         return (error);
943 }
944 
945 struct linux_recvfrom_args {
946         int s;
947         l_uintptr_t buf;
948         int len;
949         int flags;
950         l_uintptr_t from;
951         l_uintptr_t fromlen;
952 };
953 
954 static int
955 linux_recvfrom(struct thread *td, struct linux_recvfrom_args *args)
956 {
957         struct recvfrom_args /* {
958                 int     s;
959                 caddr_t buf;
960                 size_t  len;
961                 int     flags;
962                 struct sockaddr * __restrict from;
963                 socklen_t * __restrict fromlenaddr;
964         } */ bsd_args;
965         size_t len;
966         int error;
967 
968         if ((error = copyin(PTRIN(args->fromlen), &len, sizeof(size_t))))
969                 return (error);
970 
971         bsd_args.s = args->s;
972         bsd_args.buf = PTRIN(args->buf);
973         bsd_args.len = args->len;
974         bsd_args.flags = linux_to_bsd_msg_flags(args->flags);
975         /* XXX: */
976         bsd_args.from = (struct sockaddr * __restrict)PTRIN(args->from);
977         bsd_args.fromlenaddr = PTRIN(args->fromlen);/* XXX */
978         
979         linux_to_bsd_sockaddr((struct sockaddr *)bsd_args.from, len);
980         error = recvfrom(td, &bsd_args);