xref: /f-stack/lib/ff_syscall_wrapper.c (revision 92bcc6b4)
1 /*
2  * Copyright (c) 2010 Kip Macy. All rights reserved.
3  * Copyright (C) 2017 THL A29 Limited, a Tencent company.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  *   list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *   this list of conditions and the following disclaimer in the documentation
13  *   and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * Derived in part from libplebnet's pn_syscall_wrapper.c.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/limits.h>
31 #include <sys/uio.h>
32 #include <sys/proc.h>
33 #include <sys/syscallsubr.h>
34 #include <sys/module.h>
35 #include <sys/param.h>
36 #include <sys/malloc.h>
37 #include <sys/socketvar.h>
38 #include <sys/event.h>
39 #include <sys/kernel.h>
40 #include <sys/refcount.h>
41 #include <sys/sysctl.h>
42 #include <sys/pcpu.h>
43 #include <sys/select.h>
44 #include <sys/poll.h>
45 #include <sys/event.h>
46 #include <sys/file.h>
47 #include <netinet/in.h>
48 #include <netinet/tcp.h>
49 #include <sys/ttycom.h>
50 #include <sys/filio.h>
51 #include <sys/sysproto.h>
52 #include <sys/fcntl.h>
53 #include <net/route.h>
54 
55 #include <net/if.h>
56 #include <sys/sockio.h>
57 
58 #include <machine/stdarg.h>
59 
60 #include "ff_api.h"
61 #include "ff_host_interface.h"
62 
63 /* setsockopt/getsockopt define start */
64 
65 #define LINUX_SOL_SOCKET      1
66 
67 #define LINUX_SO_DEBUG        1
68 #define LINUX_SO_REUSEADDR    2
69 #define LINUX_SO_ERROR        4
70 #define LINUX_SO_DONTROUTE    5
71 #define LINUX_SO_BROADCAST    6
72 #define LINUX_SO_SNDBUF       7
73 #define LINUX_SO_RCVBUF       8
74 #define LINUX_SO_KEEPALIVE    9
75 #define LINUX_SO_OOBINLINE    10
76 #define LINUX_SO_LINGER       13
77 #define LINUX_SO_REUSEPORT    15
78 #define LINUX_SO_RCVLOWAT     18
79 #define LINUX_SO_SNDLOWAT     19
80 #define LINUX_SO_RCVTIMEO     20
81 #define LINUX_SO_SNDTIMEO     21
82 #define LINUX_SO_ACCEPTCONN   30
83 #define LINUX_SO_PROTOCOL     38
84 
85 
86 #define LINUX_IP_TOS        1
87 #define LINUX_IP_TTL        2
88 #define LINUX_IP_HDRINCL    3
89 #define LINUX_IP_OPTIONS    4
90 
91 #define LINUX_IP_MULTICAST_IF       32
92 #define LINUX_IP_MULTICAST_TTL      33
93 #define LINUX_IP_MULTICAST_LOOP     34
94 #define LINUX_IP_ADD_MEMBERSHIP     35
95 #define LINUX_IP_DROP_MEMBERSHIP    36
96 
97 #define LINUX_TCP_NODELAY     1
98 #define LINUX_TCP_MAXSEG      2
99 #define LINUX_TCP_KEEPIDLE    4
100 #define LINUX_TCP_KEEPINTVL   5
101 #define LINUX_TCP_KEEPCNT     6
102 #define LINUX_TCP_INFO        11
103 #define LINUX_TCP_MD5SIG      14
104 
105 /* setsockopt/getsockopt define end */
106 
107 
108 /* ioctl define start */
109 
110 #define LINUX_TIOCEXCL    0x540C
111 #define LINUX_TIOCNXCL    0x540D
112 #define LINUX_TIOCSCTTY   0x540E
113 #define LINUX_TIOCGPGRP   0x540F
114 #define LINUX_TIOCSPGRP   0x5410
115 #define LINUX_TIOCOUTQ    0x5411
116 #define LINUX_TIOCSTI     0x5412
117 #define LINUX_TIOCGWINSZ  0x5413
118 #define LINUX_TIOCSWINSZ  0x5414
119 #define LINUX_TIOCMGET    0x5415
120 #define LINUX_TIOCMBIS    0x5416
121 #define LINUX_TIOCMBIC    0x5417
122 #define LINUX_TIOCMSET    0x5418
123 
124 #define LINUX_FIONREAD    0x541B
125 #define LINUX_TIOCCONS    0x541D
126 #define LINUX_TIOCPKT     0x5420
127 #define LINUX_FIONBIO     0x5421
128 #define LINUX_TIOCNOTTY   0x5422
129 #define LINUX_TIOCSETD    0x5423
130 #define LINUX_TIOCGETD    0x5424
131 #define LINUX_TIOCSBRK    0x5427
132 #define LINUX_TIOCCBRK    0x5428
133 #define LINUX_TIOCGSID    0x5429
134 
135 #define LINUX_FIONCLEX    0x5450
136 #define LINUX_FIOCLEX     0x5451
137 #define LINUX_FIOASYNC    0x5452
138 
139 #define LINUX_TIOCPKT_DATA          0
140 #define LINUX_TIOCPKT_FLUSHREAD     1
141 #define LINUX_TIOCPKT_FLUSHWRITE    2
142 #define LINUX_TIOCPKT_STOP          4
143 #define LINUX_TIOCPKT_START         8
144 #define LINUX_TIOCPKT_NOSTOP        16
145 #define LINUX_TIOCPKT_DOSTOP        32
146 #define LINUX_TIOCPKT_IOCTL         64
147 
148 #define LINUX_SIOCGIFCONF     0x8912
149 #define LINUX_SIOCGIFFLAGS    0x8913
150 #define LINUX_SIOCSIFFLAGS    0x8914
151 #define LINUX_SIOCGIFADDR     0x8915
152 #define LINUX_SIOCSIFADDR     0x8916
153 #define LINUX_SIOCGIFDSTADDR  0x8917
154 #define LINUX_SIOCSIFDSTADDR  0x8918
155 #define LINUX_SIOCGIFBRDADDR  0x8919
156 #define LINUX_SIOCSIFBRDADDR  0x891a
157 #define LINUX_SIOCGIFNETMASK  0x891b
158 #define LINUX_SIOCSIFNETMASK  0x891c
159 #define LINUX_SIOCGIFMETRIC   0x891d
160 #define LINUX_SIOCSIFMETRIC   0x891e
161 #define LINUX_SIOCGIFMTU      0x8921
162 #define LINUX_SIOCSIFMTU      0x8922
163 #define LINUX_SIOCSIFNAME     0x8923
164 #define LINUX_SIOCADDMULTI    0x8931
165 #define LINUX_SIOCDELMULTI    0x8932
166 #define LINUX_SIOCGIFINDEX    0x8933
167 #define LINUX_SIOCDIFADDR     0x8936
168 
169 /* ioctl define end */
170 
171 /* af define start */
172 
173 #define LINUX_AF_INET6        10
174 
175 /* af define end */
176 
177 /* msghdr define start */
178 
179 struct linux_msghdr {
180     void *msg_name;             /* Address to send to/receive from.  */
181     socklen_t msg_namelen;      /* Length of address data.  */
182 
183     struct iovec *msg_iov;      /* Vector of data to send/receive into.  */
184     size_t msg_iovlen;          /* Number of elements in the vector.  */
185 
186     void *msg_control;          /* Ancillary data (eg BSD filedesc passing). */
187     size_t msg_controllen;      /* Ancillary data buffer length.
188                                    !! The type should be socklen_t but the
189                                    definition of the kernel is incompatible
190                                    with this.  */
191 
192     int msg_flags;              /* Flags on received message.  */
193 };
194 
195 /* msghdr define end */
196 
197 extern int sendit(struct thread *td, int s, struct msghdr *mp, int flags);
198 
199 static long
200 linux2freebsd_ioctl(unsigned long request)
201 {
202     switch(request) {
203         case LINUX_TIOCEXCL:
204             return TIOCEXCL;
205         case LINUX_TIOCNXCL:
206             return TIOCNXCL;
207         case LINUX_TIOCSCTTY:
208             return TIOCSCTTY;
209         case LINUX_TIOCGPGRP:
210             return TIOCGPGRP;
211         case LINUX_TIOCSPGRP:
212             return TIOCSPGRP;
213         case LINUX_TIOCOUTQ:
214             return TIOCOUTQ;
215         case LINUX_TIOCSTI:
216             return TIOCSTI;
217         case LINUX_TIOCGWINSZ:
218             return TIOCGWINSZ;
219         case LINUX_TIOCSWINSZ:
220             return TIOCSWINSZ;
221         case LINUX_TIOCMGET:
222             return TIOCMGET;
223         case LINUX_TIOCMBIS:
224             return TIOCMBIS;
225         case LINUX_TIOCMBIC:
226             return TIOCMBIC;
227         case LINUX_TIOCMSET:
228             return TIOCMSET;
229         case LINUX_FIONREAD:
230             return FIONREAD;
231         case LINUX_TIOCCONS:
232             return TIOCCONS;
233         case LINUX_TIOCPKT:
234             return TIOCPKT;
235         case LINUX_FIONBIO:
236             return FIONBIO;
237         case LINUX_TIOCNOTTY:
238             return TIOCNOTTY;
239         case LINUX_TIOCSETD:
240             return TIOCSETD;
241         case LINUX_TIOCGETD:
242             return TIOCGETD;
243         case LINUX_TIOCSBRK:
244             return TIOCSBRK;
245         case LINUX_TIOCCBRK:
246             return TIOCCBRK;
247         case LINUX_TIOCGSID:
248             return TIOCGSID;
249         case LINUX_FIONCLEX:
250             return FIONCLEX;
251         case LINUX_FIOCLEX:
252             return FIOCLEX;
253         case LINUX_FIOASYNC:
254             return FIOASYNC;
255         case LINUX_TIOCPKT_DATA:
256             return TIOCPKT_DATA;
257         case LINUX_TIOCPKT_FLUSHREAD:
258             return TIOCPKT_FLUSHREAD;
259         case LINUX_TIOCPKT_FLUSHWRITE:
260             return TIOCPKT_FLUSHWRITE;
261         case LINUX_TIOCPKT_STOP:
262             return TIOCPKT_STOP;
263         case LINUX_TIOCPKT_START:
264             return TIOCPKT_START;
265         case LINUX_TIOCPKT_NOSTOP:
266             return TIOCPKT_NOSTOP;
267         case LINUX_TIOCPKT_DOSTOP:
268             return TIOCPKT_DOSTOP;
269         case LINUX_TIOCPKT_IOCTL:
270             return TIOCPKT_IOCTL;
271         case LINUX_SIOCGIFCONF:
272             return SIOCGIFCONF;
273         case LINUX_SIOCGIFFLAGS:
274             return SIOCGIFFLAGS;
275         case LINUX_SIOCSIFFLAGS:
276             return SIOCSIFFLAGS;
277         case LINUX_SIOCGIFADDR:
278             return SIOCGIFADDR;
279         case LINUX_SIOCSIFADDR:
280             return SIOCSIFADDR;
281         case LINUX_SIOCGIFDSTADDR:
282             return SIOCGIFDSTADDR;
283         case LINUX_SIOCSIFDSTADDR:
284             return SIOCSIFDSTADDR;
285         case LINUX_SIOCGIFBRDADDR:
286             return SIOCGIFBRDADDR;
287         case LINUX_SIOCSIFBRDADDR:
288             return SIOCSIFBRDADDR;
289         case LINUX_SIOCGIFNETMASK:
290             return SIOCGIFNETMASK;
291         case LINUX_SIOCSIFNETMASK:
292             return SIOCSIFNETMASK;
293         case LINUX_SIOCGIFMETRIC:
294             return SIOCGIFMETRIC;
295         case LINUX_SIOCSIFMETRIC:
296             return SIOCSIFMETRIC;
297         case LINUX_SIOCGIFMTU:
298             return SIOCGIFMTU;
299         case LINUX_SIOCSIFMTU:
300             return SIOCSIFMTU;
301         case LINUX_SIOCSIFNAME:
302             return SIOCSIFNAME;
303         case LINUX_SIOCADDMULTI:
304             return SIOCADDMULTI;
305         case LINUX_SIOCDELMULTI:
306             return SIOCDELMULTI;
307         case LINUX_SIOCGIFINDEX:
308             return SIOCGIFINDEX;
309         case LINUX_SIOCDIFADDR:
310             return SIOCDIFADDR;
311         default:
312             return -1;
313     }
314 }
315 
316 static int
317 so_opt_convert(int optname)
318 {
319     switch(optname) {
320         case LINUX_SO_DEBUG:
321             return SO_DEBUG;
322         case LINUX_SO_REUSEADDR:
323             return SO_REUSEADDR;
324         case LINUX_SO_ERROR:
325             return SO_ERROR;
326         case LINUX_SO_DONTROUTE:
327             return SO_DONTROUTE;
328         case LINUX_SO_BROADCAST:
329             return SO_BROADCAST;
330         case LINUX_SO_SNDBUF:
331             return SO_SNDBUF;
332         case LINUX_SO_RCVBUF:
333             return SO_RCVBUF;
334         case LINUX_SO_KEEPALIVE:
335             return SO_KEEPALIVE;
336         case LINUX_SO_OOBINLINE:
337             return SO_OOBINLINE;
338         case LINUX_SO_LINGER:
339             return SO_LINGER;
340         case LINUX_SO_REUSEPORT:
341             return SO_REUSEPORT;
342         case LINUX_SO_RCVLOWAT:
343             return SO_RCVLOWAT;
344         case LINUX_SO_SNDLOWAT:
345             return SO_SNDLOWAT;
346         case LINUX_SO_RCVTIMEO:
347             return SO_RCVTIMEO;
348         case LINUX_SO_SNDTIMEO:
349             return SO_SNDTIMEO;
350         case LINUX_SO_ACCEPTCONN:
351             return SO_ACCEPTCONN;
352         case LINUX_SO_PROTOCOL:
353             return SO_PROTOCOL;
354         default:
355             return -1;
356     }
357 }
358 
359 static int
360 ip_opt_convert(int optname)
361 {
362     switch(optname) {
363         case LINUX_IP_TOS:
364             return IP_TOS;
365         case LINUX_IP_TTL:
366             return IP_TTL;
367         case LINUX_IP_HDRINCL:
368             return IP_HDRINCL;
369         case LINUX_IP_OPTIONS:
370             return IP_OPTIONS;
371         case LINUX_IP_MULTICAST_IF:
372             return IP_MULTICAST_IF;
373         case LINUX_IP_MULTICAST_TTL:
374             return IP_MULTICAST_TTL;
375         case LINUX_IP_MULTICAST_LOOP:
376             return IP_MULTICAST_LOOP;
377         case LINUX_IP_ADD_MEMBERSHIP:
378             return IP_ADD_MEMBERSHIP;
379         case LINUX_IP_DROP_MEMBERSHIP:
380             return IP_DROP_MEMBERSHIP;
381         default:
382             return optname;
383     }
384 }
385 
386 static int
387 tcp_opt_convert(int optname)
388 {
389     switch(optname) {
390         case LINUX_TCP_NODELAY:
391             return TCP_NODELAY;
392         case LINUX_TCP_MAXSEG:
393             return TCP_MAXSEG;
394         case LINUX_TCP_KEEPIDLE:
395             return TCP_KEEPIDLE;
396         case LINUX_TCP_KEEPINTVL:
397             return TCP_KEEPINTVL;
398         case LINUX_TCP_KEEPCNT:
399             return TCP_KEEPCNT;
400         case LINUX_TCP_INFO:
401             return TCP_INFO;
402         case LINUX_TCP_MD5SIG:
403             return TCP_MD5SIG;
404         default:
405             return -1;
406     }
407 }
408 
409 static int
410 linux2freebsd_opt(int level, int optname)
411 {
412     switch(level) {
413         case SOL_SOCKET:
414             return so_opt_convert(optname);
415         case IPPROTO_IP:
416             return ip_opt_convert(optname);
417         case IPPROTO_TCP:
418             return tcp_opt_convert(optname);
419         default:
420             return -1;
421     }
422 }
423 
424 static void
425 linux2freebsd_sockaddr(const struct linux_sockaddr *linux,
426     socklen_t addrlen, struct sockaddr *freebsd)
427 {
428     if (linux == NULL) {
429         return;
430     }
431 
432     /* #linux and #freebsd may point to the same address */
433     freebsd->sa_family = linux->sa_family == LINUX_AF_INET6 ? AF_INET6 : linux->sa_family;
434     freebsd->sa_len = addrlen;
435 
436     bcopy(linux->sa_data, freebsd->sa_data, addrlen - sizeof(linux->sa_family));
437 }
438 
439 static void
440 freebsd2linux_sockaddr(struct linux_sockaddr *linux,
441     struct sockaddr *freebsd)
442 {
443     if (linux == NULL) {
444         return;
445     }
446 
447     linux->sa_family = freebsd->sa_family == AF_INET6 ? LINUX_AF_INET6 : freebsd->sa_family;
448 
449     bcopy(freebsd->sa_data, linux->sa_data, freebsd->sa_len - sizeof(linux->sa_family));
450 }
451 
452 int
453 ff_socket(int domain, int type, int protocol)
454 {
455     int rc;
456     struct socket_args sa;
457     sa.domain = domain == LINUX_AF_INET6 ? AF_INET6 : domain;
458     sa.type = type;
459     sa.protocol = protocol;
460     if ((rc = sys_socket(curthread, &sa)))
461         goto kern_fail;
462 
463     return curthread->td_retval[0];
464 kern_fail:
465     ff_os_errno(rc);
466     return (-1);
467 }
468 
469 int
470 ff_getsockopt(int s, int level, int optname, void *optval,
471     socklen_t *optlen)
472 {
473     int rc;
474     if (level == LINUX_SOL_SOCKET)
475         level = SOL_SOCKET;
476 
477     optname = linux2freebsd_opt(level, optname);
478     if (optname < 0) {
479         rc = EINVAL;
480         goto kern_fail;
481     }
482 
483     if ((rc = kern_getsockopt(curthread, s, level, optname,
484             optval, UIO_USERSPACE, optlen)))
485         goto kern_fail;
486 
487     return (rc);
488 
489 kern_fail:
490     ff_os_errno(rc);
491     return (-1);
492 }
493 
494 int
495 ff_getsockopt_freebsd(int s, int level, int optname,
496     void *optval, socklen_t *optlen)
497 {
498     int rc;
499 
500     if ((rc = kern_getsockopt(curthread, s, level, optname,
501             optval, UIO_USERSPACE, optlen)))
502         goto kern_fail;
503 
504     return (rc);
505 
506 kern_fail:
507     ff_os_errno(rc);
508     return (-1);
509 }
510 
511 int
512 ff_setsockopt(int s, int level, int optname, const void *optval,
513     socklen_t optlen)
514 {
515     int rc;
516 
517     if (level == LINUX_SOL_SOCKET)
518         level = SOL_SOCKET;
519 
520     optname = linux2freebsd_opt(level, optname);
521     if (optname < 0) {
522         rc = EINVAL;
523         goto kern_fail;
524     }
525 
526     if ((rc = kern_setsockopt(curthread, s, level, optname,
527             __DECONST(void *, optval), UIO_USERSPACE, optlen)))
528         goto kern_fail;
529 
530     return (rc);
531 
532 kern_fail:
533     ff_os_errno(rc);
534     return (-1);
535 }
536 
537 int
538 ff_setsockopt_freebsd(int s, int level, int optname,
539     const void *optval, socklen_t optlen)
540 {
541     int rc;
542 
543     if ((rc = kern_setsockopt(curthread, s, level, optname,
544             __DECONST(void *, optval), UIO_USERSPACE, optlen)))
545         goto kern_fail;
546 
547     return (rc);
548 
549 kern_fail:
550     ff_os_errno(rc);
551     return (-1);
552 }
553 
554 int
555 ff_ioctl(int fd, unsigned long request, ...)
556 {
557     int rc;
558     va_list ap;
559     caddr_t argp;
560 
561     long req = linux2freebsd_ioctl(request);
562     if (req < 0) {
563         rc = EINVAL;
564         goto kern_fail;
565     }
566 
567     va_start(ap, request);
568 
569     argp = va_arg(ap, caddr_t);
570     va_end(ap);
571     if ((rc = kern_ioctl(curthread, fd, req, argp)))
572         goto kern_fail;
573 
574     return (rc);
575 
576 kern_fail:
577     ff_os_errno(rc);
578     return (-1);
579 }
580 
581 int
582 ff_ioctl_freebsd(int fd, unsigned long request, ...)
583 {
584     int rc;
585     va_list ap;
586     caddr_t argp;
587 
588     va_start(ap, request);
589 
590     argp = va_arg(ap, caddr_t);
591     va_end(ap);
592     if ((rc = kern_ioctl(curthread, fd, request, argp)))
593         goto kern_fail;
594 
595     return (rc);
596 
597 kern_fail:
598     ff_os_errno(rc);
599     return (-1);
600 }
601 
602 int
603 ff_close(int fd)
604 {
605     int rc;
606 
607     if ((rc = kern_close(curthread, fd)))
608         goto kern_fail;
609 
610     return (rc);
611 kern_fail:
612     ff_os_errno(rc);
613     return (-1);
614 }
615 
616 ssize_t
617 ff_read(int fd, void *buf, size_t nbytes)
618 {
619     struct uio auio;
620     struct iovec aiov;
621     int rc;
622 
623     if (nbytes > INT_MAX) {
624         rc = EINVAL;
625         goto kern_fail;
626     }
627 
628     aiov.iov_base = buf;
629     aiov.iov_len = nbytes;
630     auio.uio_iov = &aiov;
631     auio.uio_iovcnt = 1;
632     auio.uio_resid = nbytes;
633     auio.uio_segflg = UIO_SYSSPACE;
634     if ((rc = kern_readv(curthread, fd, &auio)))
635         goto kern_fail;
636     rc = curthread->td_retval[0];
637 
638     return (rc);
639 kern_fail:
640     ff_os_errno(rc);
641     return (-1);
642 }
643 
644 ssize_t
645 ff_readv(int fd, const struct iovec *iov, int iovcnt)
646 {
647     struct uio auio;
648     int rc, len, i;
649 
650     len = 0;
651     for (i = 0; i < iovcnt; i++)
652         len += iov[i].iov_len;
653     auio.uio_iov = __DECONST(struct iovec *, iov);
654     auio.uio_iovcnt = iovcnt;
655     auio.uio_resid = len;
656     auio.uio_segflg = UIO_SYSSPACE;
657 
658     if ((rc = kern_readv(curthread, fd, &auio)))
659         goto kern_fail;
660     rc = curthread->td_retval[0];
661 
662     return (rc);
663 kern_fail:
664     ff_os_errno(rc);
665     return (-1);
666 }
667 
668 ssize_t
669 ff_write(int fd, const void *buf, size_t nbytes)
670 {
671     struct uio auio;
672     struct iovec aiov;
673     int rc;
674 
675     if (nbytes > INT_MAX) {
676         rc = EINVAL;
677         goto kern_fail;
678     }
679 
680     aiov.iov_base = (void *)(uintptr_t)buf;
681     aiov.iov_len = nbytes;
682     auio.uio_iov = &aiov;
683     auio.uio_iovcnt = 1;
684     auio.uio_resid = nbytes;
685     auio.uio_segflg = UIO_SYSSPACE;
686     if ((rc = kern_writev(curthread, fd, &auio)))
687         goto kern_fail;
688     rc = curthread->td_retval[0];
689 
690     return (rc);
691 kern_fail:
692     ff_os_errno(rc);
693     return (-1);
694 }
695 
696 ssize_t
697 ff_writev(int fd, const struct iovec *iov, int iovcnt)
698 {
699     struct uio auio;
700     int i, rc, len;
701 
702     len = 0;
703     for (i = 0; i < iovcnt; i++)
704         len += iov[i].iov_len;
705     auio.uio_iov = __DECONST(struct iovec *, iov);
706     auio.uio_iovcnt = iovcnt;
707     auio.uio_resid = len;
708     auio.uio_segflg = UIO_SYSSPACE;
709     if ((rc = kern_writev(curthread, fd, &auio)))
710         goto kern_fail;
711     rc = curthread->td_retval[0];
712 
713     return (rc);
714 kern_fail:
715     ff_os_errno(rc);
716     return (-1);
717 }
718 
719 ssize_t
720 ff_send(int s, const void *buf, size_t len, int flags)
721 {
722     return (ff_sendto(s, buf, len, flags, NULL, 0));
723 }
724 
725 ssize_t
726 ff_sendto(int s, const void *buf, size_t len, int flags,
727          const struct linux_sockaddr *to, socklen_t tolen)
728 {
729     struct msghdr msg;
730     struct iovec aiov;
731     int rc;
732 
733     struct sockaddr_storage bsdaddr;
734     struct sockaddr *pf = (struct sockaddr *)&bsdaddr;
735 
736     if (to) {
737         linux2freebsd_sockaddr(to, tolen, pf);
738     } else {
739         pf = NULL;
740     }
741 
742     msg.msg_name = pf;
743     msg.msg_namelen = tolen;
744     msg.msg_iov = &aiov;
745     msg.msg_iovlen = 1;
746     msg.msg_control = 0;
747     aiov.iov_base = __DECONST(void *, buf);
748     aiov.iov_len = len;
749     if ((rc = sendit(curthread, s, &msg, flags)))
750         goto kern_fail;
751 
752     rc = curthread->td_retval[0];
753 
754     return (rc);
755 kern_fail:
756     ff_os_errno(rc);
757     return (-1);
758 }
759 
760 ssize_t
761 ff_sendmsg(int s, const struct msghdr *msg, int flags)
762 {
763     int rc;
764     struct sockaddr_storage freebsd_sa;
765     void *linux_sa = msg->msg_name;
766 
767     if (linux_sa != NULL) {
768         linux2freebsd_sockaddr(linux_sa,
769             sizeof(struct linux_sockaddr), (struct sockaddr *)&freebsd_sa);
770         __DECONST(struct msghdr *, msg)->msg_name = &freebsd_sa;
771     }
772 
773     rc = sendit(curthread, s, __DECONST(struct msghdr *, msg), flags);
774 
775     __DECONST(struct msghdr *, msg)->msg_name = linux_sa;
776 
777     if (rc)
778         goto kern_fail;
779 
780     rc = curthread->td_retval[0];
781 
782     return (rc);
783 kern_fail:
784     ff_os_errno(rc);
785     return (-1);
786 }
787 
788 
789 ssize_t
790 ff_recv(int s, void *buf, size_t len, int flags)
791 {
792     return (ff_recvfrom(s, buf, len, flags, NULL, 0));
793 }
794 
795 ssize_t
796 ff_recvfrom(int s, void *buf, size_t len, int flags,
797     struct linux_sockaddr *from, socklen_t *fromlen)
798 {
799     struct msghdr msg;
800     struct iovec aiov;
801     int rc;
802     struct sockaddr_storage bsdaddr;
803 
804     if (fromlen != NULL)
805         msg.msg_namelen = *fromlen;
806     else
807         msg.msg_namelen = 0;
808 
809     msg.msg_name = &bsdaddr;
810     msg.msg_iov = &aiov;
811     msg.msg_iovlen = 1;
812     aiov.iov_base = buf;
813     aiov.iov_len = len;
814     msg.msg_control = 0;
815     msg.msg_flags = flags;
816     if ((rc = kern_recvit(curthread, s, &msg, UIO_SYSSPACE, NULL)))
817         goto kern_fail;
818     rc = curthread->td_retval[0];
819     if (fromlen != NULL)
820         *fromlen = msg.msg_namelen;
821 
822     if (from)
823         freebsd2linux_sockaddr(from, (struct sockaddr *)&bsdaddr);
824 
825     return (rc);
826 kern_fail:
827     ff_os_errno(rc);
828     return (-1);
829 }
830 
831 /*
832  * It is considered here that the upper 4 bytes of
833  * msg->iovlen and msg->msg_controllen in linux_msghdr are 0.
834  */
835 ssize_t
836 ff_recvmsg(int s, struct msghdr *msg, int flags)
837 {
838     int rc;
839     struct linux_msghdr *linux_msg = (struct linux_msghdr *)msg;
840 
841     msg->msg_flags = flags;
842 
843     if ((rc = kern_recvit(curthread, s, msg, UIO_SYSSPACE, NULL))) {
844         msg->msg_flags = 0;
845         goto kern_fail;
846     }
847     rc = curthread->td_retval[0];
848 
849     freebsd2linux_sockaddr(linux_msg->msg_name, msg->msg_name);
850     linux_msg->msg_flags = msg->msg_flags;
851     msg->msg_flags = 0;
852 
853     return (rc);
854 kern_fail:
855     ff_os_errno(rc);
856     return (-1);
857 }
858 
859 int
860 ff_fcntl(int fd, int cmd, ...)
861 {
862     int rc;
863     va_list ap;
864     uintptr_t argp;
865 
866     va_start(ap, cmd);
867 
868     argp = va_arg(ap, uintptr_t);
869     va_end(ap);
870 
871     if ((rc = kern_fcntl(curthread, fd, cmd, argp)))
872         goto kern_fail;
873     rc = curthread->td_retval[0];
874     return (rc);
875 kern_fail:
876     ff_os_errno(rc);
877     return (-1);
878 }
879 
880 int
881 ff_accept(int s, struct linux_sockaddr * addr,
882     socklen_t * addrlen)
883 {
884     int rc;
885     struct file *fp;
886     struct sockaddr *pf = NULL;
887     socklen_t socklen = sizeof(struct sockaddr_storage);
888 
889     if ((rc = kern_accept(curthread, s, &pf, &socklen, &fp)))
890         goto kern_fail;
891 
892     rc = curthread->td_retval[0];
893     fdrop(fp, curthread);
894 
895     if (addr && pf)
896         freebsd2linux_sockaddr(addr, pf);
897 
898     if (addrlen)
899         *addrlen = pf->sa_len;
900 
901     if(pf != NULL)
902         free(pf, M_SONAME);
903     return (rc);
904 
905 kern_fail:
906     if(pf != NULL)
907         free(pf, M_SONAME);
908     ff_os_errno(rc);
909     return (-1);
910 }
911 
912 int
913 ff_listen(int s, int backlog)
914 {
915     int rc;
916     struct listen_args la = {
917         .s = s,
918         .backlog = backlog,
919     };
920     if ((rc = sys_listen(curthread, &la)))
921         goto kern_fail;
922 
923     return (rc);
924 kern_fail:
925     ff_os_errno(rc);
926     return (-1);
927 }
928 
929 int
930 ff_bind(int s, const struct linux_sockaddr *addr, socklen_t addrlen)
931 {
932     int rc;
933     struct sockaddr_storage bsdaddr;
934     linux2freebsd_sockaddr(addr, addrlen, (struct sockaddr *)&bsdaddr);
935 
936     if ((rc = kern_bindat(curthread, AT_FDCWD, s, (struct sockaddr *)&bsdaddr)))
937         goto kern_fail;
938 
939     return (rc);
940 kern_fail:
941     ff_os_errno(rc);
942     return (-1);
943 }
944 
945 int
946 ff_connect(int s, const struct linux_sockaddr *name, socklen_t namelen)
947 {
948     int rc;
949     struct sockaddr_storage bsdaddr;
950     linux2freebsd_sockaddr(name, namelen, (struct sockaddr *)&bsdaddr);
951 
952     if ((rc = kern_connectat(curthread, AT_FDCWD, s, (struct sockaddr *)&bsdaddr)))
953         goto kern_fail;
954 
955     return (rc);
956 kern_fail:
957     ff_os_errno(rc);
958     return (-1);
959 }
960 
961 int
962 ff_getpeername(int s, struct linux_sockaddr * name,
963     socklen_t *namelen)
964 {
965     int rc;
966     struct sockaddr *pf = NULL;
967 
968     if ((rc = kern_getpeername(curthread, s, &pf, namelen)))
969         goto kern_fail;
970 
971     if (name && pf)
972         freebsd2linux_sockaddr(name, pf);
973 
974     if(pf != NULL)
975         free(pf, M_SONAME);
976     return (rc);
977 
978 kern_fail:
979     if(pf != NULL)
980         free(pf, M_SONAME);
981     ff_os_errno(rc);
982     return (-1);
983 }
984 
985 int
986 ff_getsockname(int s, struct linux_sockaddr *name,
987     socklen_t *namelen)
988 {
989     int rc;
990     struct sockaddr *pf = NULL;
991 
992     if ((rc = kern_getsockname(curthread, s, &pf, namelen)))
993         goto kern_fail;
994 
995     if (name && pf)
996         freebsd2linux_sockaddr(name, pf);
997 
998     if(pf != NULL)
999         free(pf, M_SONAME);
1000     return (rc);
1001 
1002 kern_fail:
1003     if(pf != NULL)
1004         free(pf, M_SONAME);
1005     ff_os_errno(rc);
1006     return (-1);
1007 }
1008 
1009 int
1010 ff_shutdown(int s, int how)
1011 {
1012     int rc;
1013 
1014     struct shutdown_args sa = {
1015         .s = s,
1016         .how = how,
1017     };
1018     if ((rc = sys_shutdown(curthread, &sa)))
1019         goto kern_fail;
1020 
1021     return (rc);
1022 kern_fail:
1023     ff_os_errno(rc);
1024     return (-1);
1025 }
1026 
1027 int
1028 ff_sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
1029          const void *newp, size_t newlen)
1030 {
1031     int rc;
1032     size_t retval;
1033 
1034     rc = userland_sysctl(curthread, __DECONST(int *, name), namelen, oldp, oldlenp,
1035         1, __DECONST(void *, newp), newlen, &retval, 0);
1036     if (rc)
1037         goto kern_fail;
1038     if (oldlenp)
1039         *oldlenp = retval;
1040     return (0);
1041 kern_fail:
1042     ff_os_errno(rc);
1043     return (-1);
1044 }
1045 
1046 int
1047 ff_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
1048     struct timeval *timeout)
1049 
1050 {
1051     int rc;
1052 
1053     rc = kern_select(curthread, nfds, readfds, writefds, exceptfds, timeout, 64);
1054     if (rc)
1055         goto kern_fail;
1056     rc = curthread->td_retval[0];
1057 
1058     return (rc);
1059 kern_fail:
1060     ff_os_errno(rc);
1061     return (-1);
1062 
1063 }
1064 
1065 int
1066 ff_poll(struct pollfd fds[], nfds_t nfds, int timeout)
1067 {
1068     int rc;
1069     struct timespec ts;
1070     ts.tv_sec = 0;
1071     ts.tv_nsec = 0;
1072     if ((rc = kern_poll(curthread, fds, nfds, &ts, NULL)))
1073         goto kern_fail;
1074     rc = curthread->td_retval[0];
1075     return (rc);
1076 
1077 kern_fail:
1078     ff_os_errno(rc);
1079     return (-1);
1080 }
1081 
1082 int
1083 ff_kqueue(void)
1084 {
1085     int rc;
1086     if ((rc = kern_kqueue(curthread, 0, NULL)))
1087         goto kern_fail;
1088 
1089     rc = curthread->td_retval[0];
1090     return (rc);
1091 
1092 kern_fail:
1093     ff_os_errno(rc);
1094     return (-1);
1095 }
1096 
1097 struct sys_kevent_args {
1098     int fd;
1099     const struct kevent *changelist;
1100     int nchanges;
1101     void *eventlist;
1102     int nevents;
1103     const struct timespec *timeout;
1104     void (*do_each)(void **, struct kevent *);
1105 };
1106 
1107 static int
1108 kevent_copyout(void *arg, struct kevent *kevp, int count)
1109 {
1110     int i;
1111     struct kevent *ke;
1112     struct sys_kevent_args *uap;
1113 
1114     uap = (struct sys_kevent_args *)arg;
1115 
1116     if (!uap->do_each) {
1117         bcopy(kevp, uap->eventlist, count * sizeof *kevp);
1118         uap->eventlist = (void *)((struct kevent *)(uap->eventlist) + count);
1119 
1120     } else {
1121         for (ke = kevp, i = 0; i < count; i++, ke++) {
1122             uap->do_each(&(uap->eventlist), ke);
1123         }
1124     }
1125 
1126     return (0);
1127 }
1128 
1129 /*
1130  * Copy 'count' items from the list pointed to by uap->changelist.
1131  */
1132 static int
1133 kevent_copyin(void *arg, struct kevent *kevp, int count)
1134 {
1135     struct sys_kevent_args *uap;
1136 
1137     uap = (struct sys_kevent_args *)arg;
1138     bcopy(uap->changelist, kevp, count * sizeof *kevp);
1139 
1140     uap->changelist += count;
1141 
1142     return (0);
1143 }
1144 
1145 int
1146 ff_kevent_do_each(int kq, const struct kevent *changelist, int nchanges,
1147     void *eventlist, int nevents, const struct timespec *timeout,
1148     void (*do_each)(void **, struct kevent *))
1149 {
1150     int rc;
1151     struct timespec ts;
1152     ts.tv_sec = 0;
1153     ts.tv_nsec = 0;
1154 
1155     struct sys_kevent_args ska = {
1156         kq,
1157         changelist,
1158         nchanges,
1159         eventlist,
1160         nevents,
1161         &ts,
1162         do_each
1163     };
1164 
1165     struct kevent_copyops k_ops = {
1166         &ska,
1167         kevent_copyout,
1168         kevent_copyin
1169     };
1170 
1171     if ((rc = kern_kevent(curthread, kq, nchanges, nevents, &k_ops,
1172             &ts)))
1173         goto kern_fail;
1174 
1175     rc = curthread->td_retval[0];
1176     return (rc);
1177 kern_fail:
1178     ff_os_errno(rc);
1179     return (-1);
1180 }
1181 
1182 int
1183 ff_kevent(int kq, const struct kevent *changelist, int nchanges,
1184     struct kevent *eventlist, int nevents, const struct timespec *timeout)
1185 {
1186     return ff_kevent_do_each(kq, changelist, nchanges, eventlist, nevents, timeout, NULL);
1187 }
1188 
1189 int
1190 ff_gettimeofday(struct timeval *tv, struct timezone *tz)
1191 {
1192     long nsec;
1193     ff_get_current_time(&(tv->tv_sec), &nsec);
1194     tv->tv_usec = nsec/1000;
1195     return 0;
1196 }
1197 
1198 int
1199 ff_dup(int oldfd)
1200 {
1201     int rc;
1202     struct dup_args da = {
1203         .fd = oldfd,
1204     };
1205     if ((rc = sys_dup(curthread, &da)))
1206         goto kern_fail;
1207 
1208     rc = curthread->td_retval[0];
1209 
1210     return (rc);
1211 kern_fail:
1212     ff_os_errno(rc);
1213     return (-1);
1214 }
1215 
1216 int
1217 ff_dup2(int oldfd, int newfd)
1218 {
1219     int rc;
1220     struct dup2_args da = {
1221         .from = oldfd,
1222         .to = newfd
1223     };
1224     if ((rc = sys_dup2(curthread, &da)))
1225         goto kern_fail;
1226 
1227     rc = curthread->td_retval[0];
1228 
1229     return (rc);
1230 kern_fail:
1231     ff_os_errno(rc);
1232     return (-1);
1233 }
1234 
1235 int
1236 ff_route_ctl(enum FF_ROUTE_CTL req, enum FF_ROUTE_FLAG flag,
1237     struct linux_sockaddr *dst, struct linux_sockaddr *gw,
1238     struct linux_sockaddr *netmask)
1239 
1240 {
1241     struct sockaddr_storage sa_gw, sa_dst, sa_nm;
1242     struct sockaddr *psa_gw, *psa_dst, *psa_nm;
1243     int rtreq, rtflag;
1244     int rc;
1245 
1246     switch (req) {
1247         case FF_ROUTE_ADD:
1248             rtreq = RTM_ADD;
1249             break;
1250         case FF_ROUTE_DEL:
1251             rtreq = RTM_DELETE;
1252             break;
1253         case FF_ROUTE_CHANGE:
1254             rtreq = RTM_CHANGE;
1255             break;
1256         default:
1257             rc = EINVAL;
1258             goto kern_fail;
1259     }
1260 
1261     switch (flag) {
1262         case FF_RTF_HOST:
1263             rtflag = RTF_HOST;
1264             break;
1265         case FF_RTF_GATEWAY:
1266             rtflag = RTF_GATEWAY;
1267             break;
1268         default:
1269             rc = EINVAL;
1270             goto kern_fail;
1271     };
1272 
1273     if (gw != NULL) {
1274         psa_gw = (struct sockaddr *)&sa_gw;
1275         linux2freebsd_sockaddr(gw, sizeof(*gw), psa_gw);
1276     } else {
1277         psa_gw = NULL;
1278     }
1279 
1280     if (dst != NULL) {
1281         psa_dst = (struct sockaddr *)&sa_dst;
1282         linux2freebsd_sockaddr(dst, sizeof(*dst), psa_dst);
1283     } else {
1284         psa_dst = NULL;
1285     }
1286 
1287     if (netmask != NULL) {
1288         psa_nm = (struct sockaddr *)&sa_nm;
1289         linux2freebsd_sockaddr(netmask, sizeof(*netmask), psa_nm);
1290     } else {
1291         psa_nm = NULL;
1292     }
1293 
1294     rc = rtrequest_fib(rtreq, psa_dst, psa_gw, psa_nm, rtflag,
1295         NULL, RT_DEFAULT_FIB);
1296 
1297     if (rc != 0)
1298         goto kern_fail;
1299 
1300     return (rc);
1301 
1302 kern_fail:
1303     ff_os_errno(rc);
1304     return (-1);
1305 }
1306