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