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