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