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