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