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