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