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