xref: /f-stack/lib/ff_syscall_wrapper.c (revision 4557d19a)
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
linux2freebsd_ioctl(unsigned long request)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
so_opt_convert(int optname)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
ip_opt_convert(int optname)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
ip6_opt_convert(int optname)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
tcp_opt_convert(int optname)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
ip_opt_convert2linux(int optname)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
freebsd2linux_cmsghdr(struct linux_msghdr * linux_msg)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     switch (cmsg->cmsg_level) {
468         case IPPROTO_IP:
469             linux_cmsg->cmsg_type = ip_opt_convert2linux(cmsg->cmsg_type);
470             break;
471         default:
472             linux_cmsg->cmsg_type = cmsg->cmsg_type;
473             break;
474     }
475 
476     linux_cmsg->cmsg_level = cmsg->cmsg_level;
477     linux_cmsg->cmsg_len = cmsg->cmsg_len + sizeof(struct linux_cmsghdr) - sizeof(struct cmsghdr);
478 
479 }
480 
481 static int
linux2freebsd_opt(int level,int optname)482 linux2freebsd_opt(int level, int optname)
483 {
484     switch(level) {
485         case SOL_SOCKET:
486             return so_opt_convert(optname);
487         case IPPROTO_IP:
488             return ip_opt_convert(optname);
489         case IPPROTO_IPV6:
490             return ip6_opt_convert(optname);
491         case IPPROTO_TCP:
492             return tcp_opt_convert(optname);
493         default:
494             return -1;
495     }
496 }
497 
498 static void
linux2freebsd_sockaddr(const struct linux_sockaddr * linux,socklen_t addrlen,struct sockaddr * freebsd)499 linux2freebsd_sockaddr(const struct linux_sockaddr *linux,
500     socklen_t addrlen, struct sockaddr *freebsd)
501 {
502     if (linux == NULL) {
503         return;
504     }
505 
506     /* #linux and #freebsd may point to the same address */
507     freebsd->sa_family = linux->sa_family == LINUX_AF_INET6 ? AF_INET6 : linux->sa_family;
508     freebsd->sa_len = addrlen;
509 
510     bcopy(linux->sa_data, freebsd->sa_data, addrlen - sizeof(linux->sa_family));
511 }
512 
513 static void
freebsd2linux_sockaddr(struct linux_sockaddr * linux,struct sockaddr * freebsd)514 freebsd2linux_sockaddr(struct linux_sockaddr *linux,
515     struct sockaddr *freebsd)
516 {
517     if (linux == NULL) {
518         return;
519     }
520 
521     linux->sa_family = freebsd->sa_family == AF_INET6 ? LINUX_AF_INET6 : freebsd->sa_family;
522 
523     bcopy(freebsd->sa_data, linux->sa_data, freebsd->sa_len - sizeof(linux->sa_family));
524 }
525 
526 int
ff_socket(int domain,int type,int protocol)527 ff_socket(int domain, int type, int protocol)
528 {
529     int rc;
530     struct socket_args sa;
531     sa.domain = domain == LINUX_AF_INET6 ? AF_INET6 : domain;
532     sa.type = type;
533     sa.protocol = protocol;
534     if ((rc = sys_socket(curthread, &sa)))
535         goto kern_fail;
536 
537     return curthread->td_retval[0];
538 kern_fail:
539     ff_os_errno(rc);
540     return (-1);
541 }
542 
543 int
ff_getsockopt(int s,int level,int optname,void * optval,socklen_t * optlen)544 ff_getsockopt(int s, int level, int optname, void *optval,
545     socklen_t *optlen)
546 {
547     int rc;
548     if (level == LINUX_SOL_SOCKET)
549         level = SOL_SOCKET;
550 
551     optname = linux2freebsd_opt(level, optname);
552     if (optname < 0) {
553         rc = EINVAL;
554         goto kern_fail;
555     }
556 
557     if ((rc = kern_getsockopt(curthread, s, level, optname,
558             optval, UIO_USERSPACE, optlen)))
559         goto kern_fail;
560 
561     return (rc);
562 
563 kern_fail:
564     ff_os_errno(rc);
565     return (-1);
566 }
567 
568 int
ff_getsockopt_freebsd(int s,int level,int optname,void * optval,socklen_t * optlen)569 ff_getsockopt_freebsd(int s, int level, int optname,
570     void *optval, socklen_t *optlen)
571 {
572     int rc;
573 
574     if ((rc = kern_getsockopt(curthread, s, level, optname,
575             optval, UIO_USERSPACE, optlen)))
576         goto kern_fail;
577 
578     return (rc);
579 
580 kern_fail:
581     ff_os_errno(rc);
582     return (-1);
583 }
584 
585 int
ff_setsockopt(int s,int level,int optname,const void * optval,socklen_t optlen)586 ff_setsockopt(int s, int level, int optname, const void *optval,
587     socklen_t optlen)
588 {
589     int rc;
590 
591     if (level == LINUX_SOL_SOCKET)
592         level = SOL_SOCKET;
593 
594     optname = linux2freebsd_opt(level, optname);
595     if (optname < 0) {
596         rc = EINVAL;
597         goto kern_fail;
598     }
599 
600     if ((rc = kern_setsockopt(curthread, s, level, optname,
601             __DECONST(void *, optval), UIO_USERSPACE, optlen)))
602         goto kern_fail;
603 
604     return (rc);
605 
606 kern_fail:
607     ff_os_errno(rc);
608     return (-1);
609 }
610 
611 int
ff_setsockopt_freebsd(int s,int level,int optname,const void * optval,socklen_t optlen)612 ff_setsockopt_freebsd(int s, int level, int optname,
613     const void *optval, socklen_t optlen)
614 {
615     int rc;
616 
617     if ((rc = kern_setsockopt(curthread, s, level, optname,
618             __DECONST(void *, optval), UIO_USERSPACE, optlen)))
619         goto kern_fail;
620 
621     return (rc);
622 
623 kern_fail:
624     ff_os_errno(rc);
625     return (-1);
626 }
627 
628 int
ff_ioctl(int fd,unsigned long request,...)629 ff_ioctl(int fd, unsigned long request, ...)
630 {
631     int rc;
632     va_list ap;
633     caddr_t argp;
634 
635     long req = linux2freebsd_ioctl(request);
636     if (req < 0) {
637         rc = EINVAL;
638         goto kern_fail;
639     }
640 
641     va_start(ap, request);
642 
643     argp = va_arg(ap, caddr_t);
644     va_end(ap);
645     if ((rc = kern_ioctl(curthread, fd, req, argp)))
646         goto kern_fail;
647 
648     return (rc);
649 
650 kern_fail:
651     ff_os_errno(rc);
652     return (-1);
653 }
654 
655 int
ff_ioctl_freebsd(int fd,unsigned long request,...)656 ff_ioctl_freebsd(int fd, unsigned long request, ...)
657 {
658     int rc;
659     va_list ap;
660     caddr_t argp;
661 
662     va_start(ap, request);
663 
664     argp = va_arg(ap, caddr_t);
665     va_end(ap);
666     if ((rc = kern_ioctl(curthread, fd, request, argp)))
667         goto kern_fail;
668 
669     return (rc);
670 
671 kern_fail:
672     ff_os_errno(rc);
673     return (-1);
674 }
675 
676 int
ff_close(int fd)677 ff_close(int fd)
678 {
679     int rc;
680 
681     if ((rc = kern_close(curthread, fd)))
682         goto kern_fail;
683 
684     return (rc);
685 kern_fail:
686     ff_os_errno(rc);
687     return (-1);
688 }
689 
690 ssize_t
ff_read(int fd,void * buf,size_t nbytes)691 ff_read(int fd, void *buf, size_t nbytes)
692 {
693     struct uio auio;
694     struct iovec aiov;
695     int rc;
696 
697     if (nbytes > INT_MAX) {
698         rc = EINVAL;
699         goto kern_fail;
700     }
701 
702     aiov.iov_base = buf;
703     aiov.iov_len = nbytes;
704     auio.uio_iov = &aiov;
705     auio.uio_iovcnt = 1;
706     auio.uio_resid = nbytes;
707     auio.uio_segflg = UIO_SYSSPACE;
708     if ((rc = kern_readv(curthread, fd, &auio)))
709         goto kern_fail;
710     rc = curthread->td_retval[0];
711 
712     return (rc);
713 kern_fail:
714     ff_os_errno(rc);
715     return (-1);
716 }
717 
718 ssize_t
ff_readv(int fd,const struct iovec * iov,int iovcnt)719 ff_readv(int fd, const struct iovec *iov, int iovcnt)
720 {
721     struct uio auio;
722     int rc, len, i;
723 
724     len = 0;
725     for (i = 0; i < iovcnt; i++)
726         len += iov[i].iov_len;
727     auio.uio_iov = __DECONST(struct iovec *, iov);
728     auio.uio_iovcnt = iovcnt;
729     auio.uio_resid = len;
730     auio.uio_segflg = UIO_SYSSPACE;
731 
732     if ((rc = kern_readv(curthread, fd, &auio)))
733         goto kern_fail;
734     rc = curthread->td_retval[0];
735 
736     return (rc);
737 kern_fail:
738     ff_os_errno(rc);
739     return (-1);
740 }
741 
742 ssize_t
ff_write(int fd,const void * buf,size_t nbytes)743 ff_write(int fd, const void *buf, size_t nbytes)
744 {
745     struct uio auio;
746     struct iovec aiov;
747     int rc;
748 
749     if (nbytes > INT_MAX) {
750         rc = EINVAL;
751         goto kern_fail;
752     }
753 
754     aiov.iov_base = (void *)(uintptr_t)buf;
755     aiov.iov_len = nbytes;
756     auio.uio_iov = &aiov;
757     auio.uio_iovcnt = 1;
758     auio.uio_resid = nbytes;
759     auio.uio_segflg = UIO_SYSSPACE;
760     if ((rc = kern_writev(curthread, fd, &auio)))
761         goto kern_fail;
762     rc = curthread->td_retval[0];
763 
764     return (rc);
765 kern_fail:
766     ff_os_errno(rc);
767     return (-1);
768 }
769 
770 ssize_t
ff_writev(int fd,const struct iovec * iov,int iovcnt)771 ff_writev(int fd, const struct iovec *iov, int iovcnt)
772 {
773     struct uio auio;
774     int i, rc, len;
775 
776     len = 0;
777     for (i = 0; i < iovcnt; i++)
778         len += iov[i].iov_len;
779     auio.uio_iov = __DECONST(struct iovec *, iov);
780     auio.uio_iovcnt = iovcnt;
781     auio.uio_resid = len;
782     auio.uio_segflg = UIO_SYSSPACE;
783     if ((rc = kern_writev(curthread, fd, &auio)))
784         goto kern_fail;
785     rc = curthread->td_retval[0];
786 
787     return (rc);
788 kern_fail:
789     ff_os_errno(rc);
790     return (-1);
791 }
792 
793 ssize_t
ff_send(int s,const void * buf,size_t len,int flags)794 ff_send(int s, const void *buf, size_t len, int flags)
795 {
796     return (ff_sendto(s, buf, len, flags, NULL, 0));
797 }
798 
799 ssize_t
ff_sendto(int s,const void * buf,size_t len,int flags,const struct linux_sockaddr * to,socklen_t tolen)800 ff_sendto(int s, const void *buf, size_t len, int flags,
801          const struct linux_sockaddr *to, socklen_t tolen)
802 {
803     struct msghdr msg;
804     struct iovec aiov;
805     int rc;
806 
807     struct sockaddr_storage bsdaddr;
808     struct sockaddr *pf = (struct sockaddr *)&bsdaddr;
809 
810     if (to) {
811         linux2freebsd_sockaddr(to, tolen, pf);
812     } else {
813         pf = NULL;
814     }
815 
816     msg.msg_name = pf;
817     msg.msg_namelen = tolen;
818     msg.msg_iov = &aiov;
819     msg.msg_iovlen = 1;
820     msg.msg_control = 0;
821     aiov.iov_base = __DECONST(void *, buf);
822     aiov.iov_len = len;
823     if ((rc = sendit(curthread, s, &msg, flags)))
824         goto kern_fail;
825 
826     rc = curthread->td_retval[0];
827 
828     return (rc);
829 kern_fail:
830     ff_os_errno(rc);
831     return (-1);
832 }
833 
834 ssize_t
ff_sendmsg(int s,const struct msghdr * msg,int flags)835 ff_sendmsg(int s, const struct msghdr *msg, int flags)
836 {
837     int rc;
838     struct sockaddr_storage freebsd_sa;
839     void *linux_sa = msg->msg_name;
840 
841     if (linux_sa != NULL) {
842         linux2freebsd_sockaddr(linux_sa,
843             sizeof(struct linux_sockaddr), (struct sockaddr *)&freebsd_sa);
844         __DECONST(struct msghdr *, msg)->msg_name = &freebsd_sa;
845     }
846 
847     rc = sendit(curthread, s, __DECONST(struct msghdr *, msg), flags);
848 
849     __DECONST(struct msghdr *, msg)->msg_name = linux_sa;
850 
851     if (rc)
852         goto kern_fail;
853 
854     rc = curthread->td_retval[0];
855 
856     return (rc);
857 kern_fail:
858     ff_os_errno(rc);
859     return (-1);
860 }
861 
862 
863 ssize_t
ff_recv(int s,void * buf,size_t len,int flags)864 ff_recv(int s, void *buf, size_t len, int flags)
865 {
866     return (ff_recvfrom(s, buf, len, flags, NULL, 0));
867 }
868 
869 ssize_t
ff_recvfrom(int s,void * buf,size_t len,int flags,struct linux_sockaddr * from,socklen_t * fromlen)870 ff_recvfrom(int s, void *buf, size_t len, int flags,
871     struct linux_sockaddr *from, socklen_t *fromlen)
872 {
873     struct msghdr msg;
874     struct iovec aiov;
875     int rc;
876     struct sockaddr_storage bsdaddr;
877 
878     if (fromlen != NULL)
879         msg.msg_namelen = *fromlen;
880     else
881         msg.msg_namelen = 0;
882 
883     msg.msg_name = &bsdaddr;
884     msg.msg_iov = &aiov;
885     msg.msg_iovlen = 1;
886     aiov.iov_base = buf;
887     aiov.iov_len = len;
888     msg.msg_control = 0;
889     msg.msg_flags = flags;
890     if ((rc = kern_recvit(curthread, s, &msg, UIO_SYSSPACE, NULL)))
891         goto kern_fail;
892     rc = curthread->td_retval[0];
893     if (fromlen != NULL)
894         *fromlen = msg.msg_namelen;
895 
896     if (from)
897         freebsd2linux_sockaddr(from, (struct sockaddr *)&bsdaddr);
898 
899     return (rc);
900 kern_fail:
901     ff_os_errno(rc);
902     return (-1);
903 }
904 
905 /*
906  * It is considered here that the upper 4 bytes of
907  * msg->iovlen and msg->msg_controllen in linux_msghdr are 0.
908  */
909 ssize_t
ff_recvmsg(int s,struct msghdr * msg,int flags)910 ff_recvmsg(int s, struct msghdr *msg, int flags)
911 {
912     int rc;
913     struct linux_msghdr *linux_msg = (struct linux_msghdr *)msg;
914 
915     msg->msg_flags = flags;
916 
917     if ((rc = kern_recvit(curthread, s, msg, UIO_SYSSPACE, NULL))) {
918         msg->msg_flags = 0;
919         goto kern_fail;
920     }
921     rc = curthread->td_retval[0];
922 
923     freebsd2linux_sockaddr(linux_msg->msg_name, msg->msg_name);
924     linux_msg->msg_flags = msg->msg_flags;
925     msg->msg_flags = 0;
926 
927     if(msg->msg_control) {
928         freebsd2linux_cmsghdr(linux_msg);
929     }
930 
931     return (rc);
932 kern_fail:
933     ff_os_errno(rc);
934     return (-1);
935 }
936 
937 int
ff_fcntl(int fd,int cmd,...)938 ff_fcntl(int fd, int cmd, ...)
939 {
940     int rc;
941     va_list ap;
942     uintptr_t argp;
943 
944     va_start(ap, cmd);
945 
946     argp = va_arg(ap, uintptr_t);
947     va_end(ap);
948 
949     if ((rc = kern_fcntl(curthread, fd, cmd, argp)))
950         goto kern_fail;
951     rc = curthread->td_retval[0];
952     return (rc);
953 kern_fail:
954     ff_os_errno(rc);
955     return (-1);
956 }
957 
958 int
ff_accept(int s,struct linux_sockaddr * addr,socklen_t * addrlen)959 ff_accept(int s, struct linux_sockaddr * addr,
960     socklen_t * addrlen)
961 {
962     int rc;
963     struct file *fp;
964     struct sockaddr *pf = NULL;
965     socklen_t socklen = sizeof(struct sockaddr_storage);
966 
967     if ((rc = kern_accept(curthread, s, &pf, &socklen, &fp)))
968         goto kern_fail;
969 
970     rc = curthread->td_retval[0];
971     fdrop(fp, curthread);
972 
973     if (addr && pf)
974         freebsd2linux_sockaddr(addr, pf);
975 
976     if (addrlen)
977         *addrlen = pf->sa_len;
978 
979     if(pf != NULL)
980         free(pf, M_SONAME);
981     return (rc);
982 
983 kern_fail:
984     if(pf != NULL)
985         free(pf, M_SONAME);
986     ff_os_errno(rc);
987     return (-1);
988 }
989 
990 int
ff_listen(int s,int backlog)991 ff_listen(int s, int backlog)
992 {
993     int rc;
994     struct listen_args la = {
995         .s = s,
996         .backlog = backlog,
997     };
998     if ((rc = sys_listen(curthread, &la)))
999         goto kern_fail;
1000 
1001     return (rc);
1002 kern_fail:
1003     ff_os_errno(rc);
1004     return (-1);
1005 }
1006 
1007 int
ff_bind(int s,const struct linux_sockaddr * addr,socklen_t addrlen)1008 ff_bind(int s, const struct linux_sockaddr *addr, socklen_t addrlen)
1009 {
1010     int rc;
1011     struct sockaddr_storage bsdaddr;
1012     linux2freebsd_sockaddr(addr, addrlen, (struct sockaddr *)&bsdaddr);
1013 
1014     if ((rc = kern_bindat(curthread, AT_FDCWD, s, (struct sockaddr *)&bsdaddr)))
1015         goto kern_fail;
1016 
1017     return (rc);
1018 kern_fail:
1019     ff_os_errno(rc);
1020     return (-1);
1021 }
1022 
1023 int
ff_connect(int s,const struct linux_sockaddr * name,socklen_t namelen)1024 ff_connect(int s, const struct linux_sockaddr *name, socklen_t namelen)
1025 {
1026     int rc;
1027     struct sockaddr_storage bsdaddr;
1028     linux2freebsd_sockaddr(name, namelen, (struct sockaddr *)&bsdaddr);
1029 
1030     if ((rc = kern_connectat(curthread, AT_FDCWD, s, (struct sockaddr *)&bsdaddr)))
1031         goto kern_fail;
1032 
1033     return (rc);
1034 kern_fail:
1035     ff_os_errno(rc);
1036     return (-1);
1037 }
1038 
1039 int
ff_getpeername(int s,struct linux_sockaddr * name,socklen_t * namelen)1040 ff_getpeername(int s, struct linux_sockaddr * name,
1041     socklen_t *namelen)
1042 {
1043     int rc;
1044     struct sockaddr *pf = NULL;
1045 
1046     if ((rc = kern_getpeername(curthread, s, &pf, namelen)))
1047         goto kern_fail;
1048 
1049     if (name && pf)
1050         freebsd2linux_sockaddr(name, pf);
1051 
1052     if(pf != NULL)
1053         free(pf, M_SONAME);
1054     return (rc);
1055 
1056 kern_fail:
1057     if(pf != NULL)
1058         free(pf, M_SONAME);
1059     ff_os_errno(rc);
1060     return (-1);
1061 }
1062 
1063 int
ff_getsockname(int s,struct linux_sockaddr * name,socklen_t * namelen)1064 ff_getsockname(int s, struct linux_sockaddr *name,
1065     socklen_t *namelen)
1066 {
1067     int rc;
1068     struct sockaddr *pf = NULL;
1069 
1070     if ((rc = kern_getsockname(curthread, s, &pf, namelen)))
1071         goto kern_fail;
1072 
1073     if (name && pf)
1074         freebsd2linux_sockaddr(name, pf);
1075 
1076     if(pf != NULL)
1077         free(pf, M_SONAME);
1078     return (rc);
1079 
1080 kern_fail:
1081     if(pf != NULL)
1082         free(pf, M_SONAME);
1083     ff_os_errno(rc);
1084     return (-1);
1085 }
1086 
1087 int
ff_shutdown(int s,int how)1088 ff_shutdown(int s, int how)
1089 {
1090     int rc;
1091 
1092     struct shutdown_args sa = {
1093         .s = s,
1094         .how = how,
1095     };
1096     if ((rc = sys_shutdown(curthread, &sa)))
1097         goto kern_fail;
1098 
1099     return (rc);
1100 kern_fail:
1101     ff_os_errno(rc);
1102     return (-1);
1103 }
1104 
1105 int
ff_sysctl(const int * name,u_int namelen,void * oldp,size_t * oldlenp,const void * newp,size_t newlen)1106 ff_sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
1107          const void *newp, size_t newlen)
1108 {
1109     int rc;
1110     size_t retval;
1111 
1112     rc = userland_sysctl(curthread, __DECONST(int *, name), namelen, oldp, oldlenp,
1113         1, __DECONST(void *, newp), newlen, &retval, 0);
1114     if (rc)
1115         goto kern_fail;
1116     if (oldlenp)
1117         *oldlenp = retval;
1118     return (0);
1119 kern_fail:
1120     ff_os_errno(rc);
1121     return (-1);
1122 }
1123 
1124 int
ff_select(int nfds,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout)1125 ff_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
1126     struct timeval *timeout)
1127 
1128 {
1129     int rc;
1130 
1131     rc = kern_select(curthread, nfds, readfds, writefds, exceptfds, timeout, 64);
1132     if (rc)
1133         goto kern_fail;
1134     rc = curthread->td_retval[0];
1135 
1136     return (rc);
1137 kern_fail:
1138     ff_os_errno(rc);
1139     return (-1);
1140 
1141 }
1142 
1143 int
ff_poll(struct pollfd fds[],nfds_t nfds,int timeout)1144 ff_poll(struct pollfd fds[], nfds_t nfds, int timeout)
1145 {
1146     int rc;
1147     struct timespec ts;
1148     ts.tv_sec = 0;
1149     ts.tv_nsec = 0;
1150     if ((rc = kern_poll(curthread, fds, nfds, &ts, NULL)))
1151         goto kern_fail;
1152     rc = curthread->td_retval[0];
1153     return (rc);
1154 
1155 kern_fail:
1156     ff_os_errno(rc);
1157     return (-1);
1158 }
1159 
1160 int
ff_kqueue(void)1161 ff_kqueue(void)
1162 {
1163     int rc;
1164     if ((rc = kern_kqueue(curthread, 0, NULL)))
1165         goto kern_fail;
1166 
1167     rc = curthread->td_retval[0];
1168     return (rc);
1169 
1170 kern_fail:
1171     ff_os_errno(rc);
1172     return (-1);
1173 }
1174 
1175 struct sys_kevent_args {
1176     int fd;
1177     const struct kevent *changelist;
1178     int nchanges;
1179     void *eventlist;
1180     int nevents;
1181     const struct timespec *timeout;
1182     void (*do_each)(void **, struct kevent *);
1183 };
1184 
1185 static int
kevent_copyout(void * arg,struct kevent * kevp,int count)1186 kevent_copyout(void *arg, struct kevent *kevp, int count)
1187 {
1188     int i;
1189     struct kevent *ke;
1190     struct sys_kevent_args *uap;
1191 
1192     uap = (struct sys_kevent_args *)arg;
1193 
1194     if (!uap->do_each) {
1195         bcopy(kevp, uap->eventlist, count * sizeof *kevp);
1196         uap->eventlist = (void *)((struct kevent *)(uap->eventlist) + count);
1197 
1198     } else {
1199         for (ke = kevp, i = 0; i < count; i++, ke++) {
1200             uap->do_each(&(uap->eventlist), ke);
1201         }
1202     }
1203 
1204     return (0);
1205 }
1206 
1207 /*
1208  * Copy 'count' items from the list pointed to by uap->changelist.
1209  */
1210 static int
kevent_copyin(void * arg,struct kevent * kevp,int count)1211 kevent_copyin(void *arg, struct kevent *kevp, int count)
1212 {
1213     struct sys_kevent_args *uap;
1214 
1215     uap = (struct sys_kevent_args *)arg;
1216     bcopy(uap->changelist, kevp, count * sizeof *kevp);
1217 
1218     uap->changelist += count;
1219 
1220     return (0);
1221 }
1222 
1223 int
ff_kevent_do_each(int kq,const struct kevent * changelist,int nchanges,void * eventlist,int nevents,const struct timespec * timeout,void (* do_each)(void **,struct kevent *))1224 ff_kevent_do_each(int kq, const struct kevent *changelist, int nchanges,
1225     void *eventlist, int nevents, const struct timespec *timeout,
1226     void (*do_each)(void **, struct kevent *))
1227 {
1228     int rc;
1229     struct timespec ts;
1230     ts.tv_sec = 0;
1231     ts.tv_nsec = 0;
1232 
1233     struct sys_kevent_args ska = {
1234         kq,
1235         changelist,
1236         nchanges,
1237         eventlist,
1238         nevents,
1239         &ts,
1240         do_each
1241     };
1242 
1243     struct kevent_copyops k_ops = {
1244         &ska,
1245         kevent_copyout,
1246         kevent_copyin
1247     };
1248 
1249     if ((rc = kern_kevent(curthread, kq, nchanges, nevents, &k_ops,
1250             &ts)))
1251         goto kern_fail;
1252 
1253     rc = curthread->td_retval[0];
1254     return (rc);
1255 kern_fail:
1256     ff_os_errno(rc);
1257     return (-1);
1258 }
1259 
1260 int
ff_kevent(int kq,const struct kevent * changelist,int nchanges,struct kevent * eventlist,int nevents,const struct timespec * timeout)1261 ff_kevent(int kq, const struct kevent *changelist, int nchanges,
1262     struct kevent *eventlist, int nevents, const struct timespec *timeout)
1263 {
1264     return ff_kevent_do_each(kq, changelist, nchanges, eventlist, nevents, timeout, NULL);
1265 }
1266 
1267 int
ff_gettimeofday(struct timeval * tv,struct timezone * tz)1268 ff_gettimeofday(struct timeval *tv, struct timezone *tz)
1269 {
1270     long nsec;
1271     ff_get_current_time(&(tv->tv_sec), &nsec);
1272     tv->tv_usec = nsec/1000;
1273     return 0;
1274 }
1275 
1276 int
ff_dup(int oldfd)1277 ff_dup(int oldfd)
1278 {
1279     int rc;
1280     struct dup_args da = {
1281         .fd = oldfd,
1282     };
1283     if ((rc = sys_dup(curthread, &da)))
1284         goto kern_fail;
1285 
1286     rc = curthread->td_retval[0];
1287 
1288     return (rc);
1289 kern_fail:
1290     ff_os_errno(rc);
1291     return (-1);
1292 }
1293 
1294 int
ff_dup2(int oldfd,int newfd)1295 ff_dup2(int oldfd, int newfd)
1296 {
1297     int rc;
1298     struct dup2_args da = {
1299         .from = oldfd,
1300         .to = newfd
1301     };
1302     if ((rc = sys_dup2(curthread, &da)))
1303         goto kern_fail;
1304 
1305     rc = curthread->td_retval[0];
1306 
1307     return (rc);
1308 kern_fail:
1309     ff_os_errno(rc);
1310     return (-1);
1311 }
1312 
1313 int
ff_route_ctl(enum FF_ROUTE_CTL req,enum FF_ROUTE_FLAG flag,struct linux_sockaddr * dst,struct linux_sockaddr * gw,struct linux_sockaddr * netmask)1314 ff_route_ctl(enum FF_ROUTE_CTL req, enum FF_ROUTE_FLAG flag,
1315     struct linux_sockaddr *dst, struct linux_sockaddr *gw,
1316     struct linux_sockaddr *netmask)
1317 
1318 {
1319     struct sockaddr_storage sa_gw, sa_dst, sa_nm;
1320     struct sockaddr *psa_gw, *psa_dst, *psa_nm;
1321     int rtreq, rtflag;
1322     int rc;
1323     struct rt_addrinfo info;
1324     struct rib_cmd_info rci;
1325 
1326     switch (req) {
1327         case FF_ROUTE_ADD:
1328             rtreq = RTM_ADD;
1329             break;
1330         case FF_ROUTE_DEL:
1331             rtreq = RTM_DELETE;
1332             break;
1333         case FF_ROUTE_CHANGE:
1334             rtreq = RTM_CHANGE;
1335             break;
1336         default:
1337             rc = EINVAL;
1338             goto kern_fail;
1339     }
1340 
1341     switch (flag) {
1342         case FF_RTF_HOST:
1343             rtflag = RTF_HOST;
1344             break;
1345         case FF_RTF_GATEWAY:
1346             rtflag = RTF_GATEWAY;
1347             break;
1348         default:
1349             rc = EINVAL;
1350             goto kern_fail;
1351     };
1352 
1353     bzero((caddr_t)&info, sizeof(info));
1354     info.rti_flags = rtflag;
1355 
1356     if (gw != NULL) {
1357         psa_gw = (struct sockaddr *)&sa_gw;
1358         linux2freebsd_sockaddr(gw, sizeof(*gw), psa_gw);
1359         info.rti_info[RTAX_GATEWAY] = psa_gw;
1360     } else {
1361         psa_gw = NULL;
1362     }
1363 
1364     if (dst != NULL) {
1365         psa_dst = (struct sockaddr *)&sa_dst;
1366         linux2freebsd_sockaddr(dst, sizeof(*dst), psa_dst);
1367         info.rti_info[RTAX_DST] = psa_dst;
1368     } else {
1369         psa_dst = NULL;
1370     }
1371 
1372     if (netmask != NULL) {
1373         psa_nm = (struct sockaddr *)&sa_nm;
1374         linux2freebsd_sockaddr(netmask, sizeof(*netmask), psa_nm);
1375         info.rti_info[RTAX_NETMASK] = psa_nm;
1376     } else {
1377         psa_nm = NULL;
1378     }
1379 
1380     rc = rib_action(RT_DEFAULT_FIB, rtreq, &info, &rci);
1381 
1382     if (rc != 0)
1383         goto kern_fail;
1384 
1385     return (rc);
1386 
1387 kern_fail:
1388     ff_os_errno(rc);
1389     return (-1);
1390 }
1391