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