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