f-stack/lib/ff_syscall_wrapper.c

1599 lines
40 KiB
C
Raw Normal View History

2017-04-21 10:43:26 +00:00
/*
* Copyright (c) 2010 Kip Macy. All rights reserved.
2021-09-18 08:05:45 +00:00
* Copyright (C) 2017-2021 THL A29 Limited, a Tencent company.
2017-04-21 10:43:26 +00:00
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Derived in part from libplebnet's pn_syscall_wrapper.c.
*/
#include <sys/param.h>
#include <sys/limits.h>
#include <sys/uio.h>
#include <sys/proc.h>
#include <sys/syscallsubr.h>
#include <sys/module.h>
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/socketvar.h>
#include <sys/event.h>
#include <sys/kernel.h>
#include <sys/refcount.h>
#include <sys/sysctl.h>
#include <sys/pcpu.h>
#include <sys/select.h>
#include <sys/poll.h>
#include <sys/event.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/ttycom.h>
#include <sys/filio.h>
#include <sys/sysproto.h>
#include <sys/fcntl.h>
#include <net/route.h>
#include <net/route/route_ctl.h>
2017-04-21 10:43:26 +00:00
#include <net/if.h>
#include <sys/sockio.h>
2017-04-21 10:43:26 +00:00
#include <machine/stdarg.h>
#include "ff_api.h"
#include "ff_host_interface.h"
/* setsockopt/getsockopt define start */
#define LINUX_SOL_SOCKET 1
#define LINUX_SO_DEBUG 1
#define LINUX_SO_REUSEADDR 2
#define LINUX_SO_ERROR 4
#define LINUX_SO_DONTROUTE 5
#define LINUX_SO_BROADCAST 6
#define LINUX_SO_SNDBUF 7
#define LINUX_SO_RCVBUF 8
#define LINUX_SO_KEEPALIVE 9
#define LINUX_SO_OOBINLINE 10
#define LINUX_SO_LINGER 13
2019-11-04 02:44:07 +00:00
#define LINUX_SO_REUSEPORT 15
2017-04-21 10:43:26 +00:00
#define LINUX_SO_RCVLOWAT 18
#define LINUX_SO_SNDLOWAT 19
#define LINUX_SO_RCVTIMEO 20
#define LINUX_SO_SNDTIMEO 21
#define LINUX_SO_ACCEPTCONN 30
#define LINUX_SO_PROTOCOL 38
#define LINUX_IP_TOS 1
#define LINUX_IP_TTL 2
#define LINUX_IP_HDRINCL 3
#define LINUX_IP_OPTIONS 4
#define LINUX_IP_RECVTTL 12
#define LINUX_IP_RECVTOS 13
#define LINUX_IP_TRANSPARENT 19
#define LINUX_IP_MINTTL 21
2017-04-21 10:43:26 +00:00
#define LINUX_IP_MULTICAST_IF 32
#define LINUX_IP_MULTICAST_TTL 33
#define LINUX_IP_MULTICAST_LOOP 34
#define LINUX_IP_ADD_MEMBERSHIP 35
#define LINUX_IP_DROP_MEMBERSHIP 36
2021-02-07 08:06:14 +00:00
#define LINUX_IPV6_V6ONLY 26
2022-09-02 08:51:22 +00:00
#define LINUX_IPV6_RECVPKTINFO 49
#define LINUX_IPV6_TRANSPARENT 75
2017-04-21 10:43:26 +00:00
#define LINUX_TCP_NODELAY 1
#define LINUX_TCP_MAXSEG 2
#define LINUX_TCP_KEEPIDLE 4
#define LINUX_TCP_KEEPINTVL 5
#define LINUX_TCP_KEEPCNT 6
2019-02-24 08:51:25 +00:00
#define LINUX_TCP_INFO 11
2017-04-21 10:43:26 +00:00
#define LINUX_TCP_MD5SIG 14
/* setsockopt/getsockopt define end */
/* ioctl define start */
#define LINUX_TIOCEXCL 0x540C
#define LINUX_TIOCNXCL 0x540D
#define LINUX_TIOCSCTTY 0x540E
#define LINUX_TIOCGPGRP 0x540F
#define LINUX_TIOCSPGRP 0x5410
#define LINUX_TIOCOUTQ 0x5411
#define LINUX_TIOCSTI 0x5412
#define LINUX_TIOCGWINSZ 0x5413
#define LINUX_TIOCSWINSZ 0x5414
#define LINUX_TIOCMGET 0x5415
#define LINUX_TIOCMBIS 0x5416
#define LINUX_TIOCMBIC 0x5417
#define LINUX_TIOCMSET 0x5418
#define LINUX_FIONREAD 0x541B
#define LINUX_TIOCCONS 0x541D
#define LINUX_TIOCPKT 0x5420
#define LINUX_FIONBIO 0x5421
#define LINUX_TIOCNOTTY 0x5422
#define LINUX_TIOCSETD 0x5423
#define LINUX_TIOCGETD 0x5424
#define LINUX_TIOCSBRK 0x5427
#define LINUX_TIOCCBRK 0x5428
#define LINUX_TIOCGSID 0x5429
#define LINUX_FIONCLEX 0x5450
#define LINUX_FIOCLEX 0x5451
#define LINUX_FIOASYNC 0x5452
#define LINUX_TIOCPKT_DATA 0
#define LINUX_TIOCPKT_FLUSHREAD 1
#define LINUX_TIOCPKT_FLUSHWRITE 2
#define LINUX_TIOCPKT_STOP 4
#define LINUX_TIOCPKT_START 8
#define LINUX_TIOCPKT_NOSTOP 16
#define LINUX_TIOCPKT_DOSTOP 32
#define LINUX_TIOCPKT_IOCTL 64
#define LINUX_SIOCGIFCONF 0x8912
#define LINUX_SIOCGIFFLAGS 0x8913
#define LINUX_SIOCSIFFLAGS 0x8914
#define LINUX_SIOCGIFADDR 0x8915
#define LINUX_SIOCSIFADDR 0x8916
#define LINUX_SIOCGIFDSTADDR 0x8917
#define LINUX_SIOCSIFDSTADDR 0x8918
#define LINUX_SIOCGIFBRDADDR 0x8919
#define LINUX_SIOCSIFBRDADDR 0x891a
#define LINUX_SIOCGIFNETMASK 0x891b
#define LINUX_SIOCSIFNETMASK 0x891c
#define LINUX_SIOCGIFMETRIC 0x891d
#define LINUX_SIOCSIFMETRIC 0x891e
#define LINUX_SIOCGIFMTU 0x8921
#define LINUX_SIOCSIFMTU 0x8922
#define LINUX_SIOCSIFNAME 0x8923
#define LINUX_SIOCADDMULTI 0x8931
#define LINUX_SIOCDELMULTI 0x8932
#define LINUX_SIOCGIFINDEX 0x8933
#define LINUX_SIOCDIFADDR 0x8936
2017-04-21 10:43:26 +00:00
/* ioctl define end */
/* af define start */
#define LINUX_AF_INET6 10
/* af define end */
2017-04-21 10:43:26 +00:00
/* msghdr define start */
static /*__thread*/ struct iovec msg_iov_tmp[UIO_MAXIOV];
static /*__thread*/ size_t msg_iovlen_tmp;
struct linux_msghdr {
void *msg_name; /* Address to send to/receive from. */
socklen_t msg_namelen; /* Length of address data. */
struct iovec *msg_iov; /* Vector of data to send/receive into. */
size_t msg_iovlen; /* Number of elements in the vector. */
void *msg_control; /* Ancillary data (eg BSD filedesc passing). */
size_t msg_controllen; /* Ancillary data buffer length.
!! The type should be socklen_t but the
definition of the kernel is incompatible
with this. */
int msg_flags; /* Flags on received message. */
};
/* msghdr define end */
/* cmsghdr define start */
struct linux_cmsghdr
{
size_t cmsg_len; /* Length of data in cmsg_data plus length
of cmsghdr structure.
!! The type should be socklen_t but the
definition of the kernel is incompatible
with this. */
int cmsg_level; /* Originating protocol. */
int cmsg_type; /* Protocol specific type. */
};
/*
* LINUX_CMSG_XXXX has the same effect as FreeBSD's CMSG_XXXX,
* because aligned to 8 bytes, but still redefine them.
*/
#define LINUX_CMSG_DATA(cmsg) ((unsigned char *)(cmsg) + \
_ALIGN(sizeof(struct linux_cmsghdr)))
#define LINUX_CMSG_SPACE(l) (_ALIGN(sizeof(struct linux_cmsghdr)) + _ALIGN(l))
#define LINUX_CMSG_LEN(l) (_ALIGN(sizeof(struct linux_cmsghdr)) + (l))
#define LINUX_CMSG_FIRSTHDR(mhdr) \
((mhdr)->msg_controllen >= sizeof(struct linux_cmsghdr) ? \
(struct linux_cmsghdr *)(mhdr)->msg_control : \
(struct linux_cmsghdr *)0)
#define LINUX_CMSG_NXTHDR(mhdr, cmsg) \
((char *)(cmsg) == (char *)0 ? LINUX_CMSG_FIRSTHDR(mhdr) : \
((char *)(cmsg) + _ALIGN(((struct linux_cmsghdr *)(cmsg))->cmsg_len) + \
_ALIGN(sizeof(struct linux_cmsghdr)) > \
(char *)(mhdr)->msg_control + (mhdr)->msg_controllen) ? \
(struct linux_cmsghdr *)0 : \
(struct linux_cmsghdr *)(void *)((char *)(cmsg) + \
_ALIGN(((struct linux_cmsghdr *)(cmsg))->cmsg_len)))
/* cmsghdr define end */
2017-04-21 10:43:26 +00:00
extern int sendit(struct thread *td, int s, struct msghdr *mp, int flags);
static long
linux2freebsd_ioctl(unsigned long request)
{
switch(request) {
case LINUX_TIOCEXCL:
return TIOCEXCL;
case LINUX_TIOCNXCL:
return TIOCNXCL;
case LINUX_TIOCSCTTY:
return TIOCSCTTY;
case LINUX_TIOCGPGRP:
return TIOCGPGRP;
case LINUX_TIOCSPGRP:
return TIOCSPGRP;
case LINUX_TIOCOUTQ:
return TIOCOUTQ;
case LINUX_TIOCSTI:
return TIOCSTI;
case LINUX_TIOCGWINSZ:
return TIOCGWINSZ;
case LINUX_TIOCSWINSZ:
return TIOCSWINSZ;
case LINUX_TIOCMGET:
return TIOCMGET;
case LINUX_TIOCMBIS:
return TIOCMBIS;
case LINUX_TIOCMBIC:
return TIOCMBIC;
case LINUX_TIOCMSET:
return TIOCMSET;
case LINUX_FIONREAD:
return FIONREAD;
case LINUX_TIOCCONS:
return TIOCCONS;
case LINUX_TIOCPKT:
return TIOCPKT;
case LINUX_FIONBIO:
return FIONBIO;
case LINUX_TIOCNOTTY:
return TIOCNOTTY;
case LINUX_TIOCSETD:
return TIOCSETD;
case LINUX_TIOCGETD:
return TIOCGETD;
case LINUX_TIOCSBRK:
return TIOCSBRK;
case LINUX_TIOCCBRK:
return TIOCCBRK;
case LINUX_TIOCGSID:
return TIOCGSID;
case LINUX_FIONCLEX:
return FIONCLEX;
case LINUX_FIOCLEX:
return FIOCLEX;
case LINUX_FIOASYNC:
return FIOASYNC;
case LINUX_TIOCPKT_DATA:
return TIOCPKT_DATA;
case LINUX_TIOCPKT_FLUSHREAD:
return TIOCPKT_FLUSHREAD;
case LINUX_TIOCPKT_FLUSHWRITE:
return TIOCPKT_FLUSHWRITE;
case LINUX_TIOCPKT_STOP:
return TIOCPKT_STOP;
case LINUX_TIOCPKT_START:
return TIOCPKT_START;
case LINUX_TIOCPKT_NOSTOP:
return TIOCPKT_NOSTOP;
case LINUX_TIOCPKT_DOSTOP:
return TIOCPKT_DOSTOP;
case LINUX_TIOCPKT_IOCTL:
return TIOCPKT_IOCTL;
case LINUX_SIOCGIFCONF:
return SIOCGIFCONF;
case LINUX_SIOCGIFFLAGS:
return SIOCGIFFLAGS;
case LINUX_SIOCSIFFLAGS:
return SIOCSIFFLAGS;
case LINUX_SIOCGIFADDR:
return SIOCGIFADDR;
case LINUX_SIOCSIFADDR:
return SIOCSIFADDR;
case LINUX_SIOCGIFDSTADDR:
return SIOCGIFDSTADDR;
case LINUX_SIOCSIFDSTADDR:
return SIOCSIFDSTADDR;
case LINUX_SIOCGIFBRDADDR:
return SIOCGIFBRDADDR;
case LINUX_SIOCSIFBRDADDR:
return SIOCSIFBRDADDR;
case LINUX_SIOCGIFNETMASK:
return SIOCGIFNETMASK;
case LINUX_SIOCSIFNETMASK:
return SIOCSIFNETMASK;
case LINUX_SIOCGIFMETRIC:
return SIOCGIFMETRIC;
case LINUX_SIOCSIFMETRIC:
return SIOCSIFMETRIC;
case LINUX_SIOCGIFMTU:
return SIOCGIFMTU;
case LINUX_SIOCSIFMTU:
return SIOCSIFMTU;
case LINUX_SIOCSIFNAME:
return SIOCSIFNAME;
case LINUX_SIOCADDMULTI:
return SIOCADDMULTI;
case LINUX_SIOCDELMULTI:
return SIOCDELMULTI;
case LINUX_SIOCGIFINDEX:
return SIOCGIFINDEX;
case LINUX_SIOCDIFADDR:
return SIOCDIFADDR;
2017-04-21 10:43:26 +00:00
default:
return -1;
2017-04-21 10:43:26 +00:00
}
}
static int
so_opt_convert(int optname)
{
switch(optname) {
case LINUX_SO_DEBUG:
return SO_DEBUG;
case LINUX_SO_REUSEADDR:
return SO_REUSEADDR;
case LINUX_SO_ERROR:
return SO_ERROR;
case LINUX_SO_DONTROUTE:
return SO_DONTROUTE;
case LINUX_SO_BROADCAST:
return SO_BROADCAST;
case LINUX_SO_SNDBUF:
return SO_SNDBUF;
case LINUX_SO_RCVBUF:
return SO_RCVBUF;
case LINUX_SO_KEEPALIVE:
return SO_KEEPALIVE;
case LINUX_SO_OOBINLINE:
return SO_OOBINLINE;
case LINUX_SO_LINGER:
return SO_LINGER;
2019-11-04 02:44:07 +00:00
case LINUX_SO_REUSEPORT:
return SO_REUSEPORT;
2017-04-21 10:43:26 +00:00
case LINUX_SO_RCVLOWAT:
return SO_RCVLOWAT;
case LINUX_SO_SNDLOWAT:
return SO_SNDLOWAT;
case LINUX_SO_RCVTIMEO:
return SO_RCVTIMEO;
case LINUX_SO_SNDTIMEO:
return SO_SNDTIMEO;
case LINUX_SO_ACCEPTCONN:
return SO_ACCEPTCONN;
case LINUX_SO_PROTOCOL:
return SO_PROTOCOL;
default:
return -1;
2017-04-21 10:43:26 +00:00
}
}
static int
ip_opt_convert(int optname)
{
switch(optname) {
case LINUX_IP_TOS:
return IP_TOS;
case LINUX_IP_TTL:
return IP_TTL;
case LINUX_IP_HDRINCL:
return IP_HDRINCL;
case LINUX_IP_OPTIONS:
return IP_OPTIONS;
case LINUX_IP_MULTICAST_IF:
return IP_MULTICAST_IF;
case LINUX_IP_MULTICAST_TTL:
return IP_MULTICAST_TTL;
case LINUX_IP_MULTICAST_LOOP:
return IP_MULTICAST_LOOP;
case LINUX_IP_ADD_MEMBERSHIP:
return IP_ADD_MEMBERSHIP;
case LINUX_IP_DROP_MEMBERSHIP:
return IP_DROP_MEMBERSHIP;
case LINUX_IP_RECVTTL:
return IP_RECVTTL;
case LINUX_IP_RECVTOS:
return IP_RECVTOS;
case LINUX_IP_TRANSPARENT:
return IP_BINDANY;
case LINUX_IP_MINTTL:
return IP_MINTTL;
2017-04-21 10:43:26 +00:00
default:
return optname;
2017-04-21 10:43:26 +00:00
}
}
static int
ip6_opt_convert(int optname)
{
switch(optname) {
case LINUX_IPV6_V6ONLY:
return IPV6_V6ONLY;
2021-02-07 08:06:14 +00:00
case LINUX_IPV6_RECVPKTINFO:
2022-09-02 08:51:22 +00:00
return IPV6_RECVPKTINFO;
case LINUX_IPV6_TRANSPARENT:
return IPV6_BINDANY;
2017-04-21 10:43:26 +00:00
default:
return optname;
2017-04-21 10:43:26 +00:00
}
}
static int
tcp_opt_convert(int optname)
{
switch(optname) {
case LINUX_TCP_NODELAY:
return TCP_NODELAY;
case LINUX_TCP_MAXSEG:
return TCP_MAXSEG;
case LINUX_TCP_KEEPIDLE:
return TCP_KEEPIDLE;
case LINUX_TCP_KEEPINTVL:
return TCP_KEEPINTVL;
case LINUX_TCP_KEEPCNT:
return TCP_KEEPCNT;
2019-02-24 08:51:25 +00:00
case LINUX_TCP_INFO:
return TCP_INFO;
2017-04-21 10:43:26 +00:00
case LINUX_TCP_MD5SIG:
return TCP_MD5SIG;
default:
return -1;
2017-04-21 10:43:26 +00:00
}
}
static int
linux2freebsd_opt(int level, int optname)
{
switch(level) {
case SOL_SOCKET:
return so_opt_convert(optname);
case IPPROTO_IP:
return ip_opt_convert(optname);
case IPPROTO_IPV6:
2022-09-02 08:51:22 +00:00
return ip6_opt_convert(optname);
2017-04-21 10:43:26 +00:00
case IPPROTO_TCP:
return tcp_opt_convert(optname);
default:
return -1;
2017-04-21 10:43:26 +00:00
}
}
static void
linux2freebsd_sockaddr(const struct linux_sockaddr *linux,
socklen_t addrlen, struct sockaddr *freebsd)
{
if (linux == NULL || freebsd == NULL) {
2017-04-21 10:43:26 +00:00
return;
}
/* #linux and #freebsd may point to the same address */
freebsd->sa_family = linux->sa_family == LINUX_AF_INET6 ? AF_INET6 : linux->sa_family;
freebsd->sa_len = addrlen;
if (linux->sa_data != freebsd->sa_data) {
bcopy(linux->sa_data, freebsd->sa_data, addrlen - sizeof(linux->sa_family));
}
2017-04-21 10:43:26 +00:00
}
static void
freebsd2linux_sockaddr(struct linux_sockaddr *linux,
struct sockaddr *freebsd)
{
if (linux == NULL || freebsd == NULL) {
2017-04-21 10:43:26 +00:00
return;
}
/* #linux and #freebsd may point to the same address */
if (linux->sa_data != freebsd->sa_data) {
bcopy(freebsd->sa_data, linux->sa_data, freebsd->sa_len - sizeof(linux->sa_family));
}
linux->sa_family = freebsd->sa_family == AF_INET6 ? LINUX_AF_INET6 : freebsd->sa_family;
}
static inline int
freebsd2linux_cmsghdr(struct linux_msghdr *linux_msg, const struct msghdr *freebsd_msg)
{
struct cmsghdr *freebsd_cmsg = CMSG_FIRSTHDR(freebsd_msg);
struct linux_cmsghdr *linux_cmsg = LINUX_CMSG_FIRSTHDR(linux_msg);
while (freebsd_cmsg && linux_cmsg) {
unsigned char *freebsd_optval = CMSG_DATA(freebsd_cmsg);
unsigned char *linux_optval = LINUX_CMSG_DATA(linux_cmsg);
/*
* The address of linux_cmsg and freebsd_cmsg coincides while recvmsg,
* but the position of the variable pointer is different,
* and the assignment must be reversed.
*
* Although sizeof(struct linux_msghdr) and sizeof(struct msghdr) have different lengths,
* but cmsg_data both skip the same 16 bytesboth aligned to 8 bytes.
*/
linux_cmsg->cmsg_type = freebsd_cmsg->cmsg_type;
linux_cmsg->cmsg_level = freebsd_cmsg->cmsg_level;
linux_cmsg->cmsg_len = LINUX_CMSG_LEN(freebsd_cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)));
/*
* The freebsd_msg's cmsg_level and cmsg_type has been moddied while recvmsg,
* must use linux_cmsg to judge and calculate data length.
* And don't copy other the bytes that used aligned.
*/
switch (linux_cmsg->cmsg_level) {
case IPPROTO_IP:
switch (linux_cmsg->cmsg_type) {
case IP_RECVTOS:
linux_cmsg->cmsg_type = LINUX_IP_TOS;
*linux_optval = *freebsd_optval;
break;
case IP_RECVTTL:
2023-09-13 05:12:13 +00:00
linux_cmsg->cmsg_len = LINUX_CMSG_LEN(sizeof(int));
linux_cmsg->cmsg_type = LINUX_IP_TTL;
*(int *)linux_optval = *freebsd_optval;
break;
/*case XXXX:
break;*/
default:
memcpy(linux_optval, freebsd_optval, linux_cmsg->cmsg_len - sizeof(struct linux_cmsghdr));
break;
}
break;
default:
memcpy(linux_optval, freebsd_optval, linux_cmsg->cmsg_len - sizeof(struct linux_cmsghdr));
break;
}
linux_cmsg = LINUX_CMSG_NXTHDR(linux_msg, linux_cmsg);
freebsd_cmsg = CMSG_NXTHDR(freebsd_msg, freebsd_cmsg);
}
return 0;
}
static inline int
linux2freebsd_cmsg(const struct linux_msghdr *linux_msg, struct msghdr *freebsd_msg)
{
struct cmsghdr *freebsd_cmsg = CMSG_FIRSTHDR(freebsd_msg);
struct linux_cmsghdr *linux_cmsg = LINUX_CMSG_FIRSTHDR(linux_msg);
while (freebsd_cmsg && linux_cmsg) {
unsigned char *freebsd_optval = CMSG_DATA(freebsd_cmsg);
unsigned char *linux_optval = LINUX_CMSG_DATA(linux_cmsg);
freebsd_cmsg->cmsg_type = linux_cmsg->cmsg_type;
freebsd_cmsg->cmsg_level = linux_cmsg->cmsg_level;
freebsd_cmsg->cmsg_len = CMSG_LEN(linux_cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct linux_cmsghdr)));
switch (linux_cmsg->cmsg_level) {
case IPPROTO_IP:
switch (linux_cmsg->cmsg_type) {
case LINUX_IP_TOS:
freebsd_cmsg->cmsg_type = IP_TOS;
freebsd_cmsg->cmsg_len = CMSG_LEN(sizeof(char));
if (linux_cmsg->cmsg_len == LINUX_CMSG_LEN(sizeof(int))) {
*freebsd_optval = *(int *)linux_optval;
} else if (linux_cmsg->cmsg_len == LINUX_CMSG_LEN(sizeof(char))) {
*freebsd_optval = *linux_optval;
}
break;
case LINUX_IP_TTL:
freebsd_cmsg->cmsg_type = IP_TTL;
freebsd_cmsg->cmsg_len = CMSG_LEN(sizeof(char));
*freebsd_optval = *(int *)linux_optval;
break;
/*case XXXX:
break;*/
default:
memcpy(freebsd_optval, linux_optval, linux_cmsg->cmsg_len - sizeof(struct linux_cmsghdr));
break;
}
break;
default:
memcpy(freebsd_optval, linux_optval, linux_cmsg->cmsg_len - sizeof(struct linux_cmsghdr));
break;
}
linux_cmsg = LINUX_CMSG_NXTHDR(linux_msg, linux_cmsg);
freebsd_cmsg = CMSG_NXTHDR(freebsd_msg, freebsd_cmsg);
}
return 0;
}
/*
* While sendmsg, need convert msg_name and msg_control from Linux to FreeBSD.
* While recvmsg, need convert msg_name and msg_control from FreeBSD to Linux.
* Note: linux2freebsd_msghdr and freebsd2linux_msghdr must be called in sequence and in pairs.
*/
static int
freebsd2linux_msghdr(struct linux_msghdr *linux_msg, struct msghdr *freebsd_msg, int send_flag)
{
if (linux_msg == NULL || freebsd_msg == NULL) {
return -1;
}
if (linux_msg->msg_name && freebsd_msg->msg_name && !send_flag) {
linux_msg->msg_name = freebsd_msg->msg_name;
freebsd2linux_sockaddr(linux_msg->msg_name, freebsd_msg->msg_name);
linux_msg->msg_namelen = freebsd_msg->msg_namelen;
}
linux_msg->msg_iov = freebsd_msg->msg_iov;
linux_msg->msg_iovlen = freebsd_msg->msg_iovlen;
/* Restore the old iov pointer, compatible with the Linux interface */
memcpy(linux_msg->msg_iov, msg_iov_tmp, msg_iovlen_tmp * sizeof(struct iovec));
if(freebsd_msg->msg_control && linux_msg->msg_control && !send_flag) {
freebsd2linux_cmsghdr(linux_msg, freebsd_msg);
linux_msg->msg_controllen = freebsd_msg->msg_controllen;
}
linux_msg->msg_flags = freebsd_msg->msg_flags;
return 0;
}
static int
linux2freebsd_msghdr(const struct linux_msghdr *linux_msg, struct msghdr *freebsd_msg, int send_flag)
{
int ret = 0;
if (linux_msg == NULL || freebsd_msg == NULL) {
return -1;;
}
if (linux_msg->msg_name && freebsd_msg->msg_name && send_flag) {
linux2freebsd_sockaddr(linux_msg->msg_name, linux_msg->msg_namelen, freebsd_msg->msg_name);
} else {
freebsd_msg->msg_name = linux_msg->msg_name;
}
freebsd_msg->msg_namelen = linux_msg->msg_namelen;
/* Save the old iov pointer, compatible with the Linux interface */
msg_iovlen_tmp = linux_msg->msg_iovlen;
if (msg_iovlen_tmp > UIO_MAXIOV) {
return -1; // EMSGSIZE;
}
memcpy(msg_iov_tmp, linux_msg->msg_iov, msg_iovlen_tmp * sizeof(struct iovec));
freebsd_msg->msg_iov = linux_msg->msg_iov;
freebsd_msg->msg_iovlen = linux_msg->msg_iovlen;
freebsd_msg->msg_controllen = linux_msg->msg_controllen;
if (linux_msg->msg_control && send_flag) {
ret = linux2freebsd_cmsg(linux_msg, freebsd_msg);
if(ret < 0) {
return ret;
}
} else {
freebsd_msg->msg_control = linux_msg->msg_control;
}
freebsd_msg->msg_flags = linux_msg->msg_flags;
return 0;
2017-04-21 10:43:26 +00:00
}
int
ff_socket(int domain, int type, int protocol)
{
int rc;
struct socket_args sa;
sa.domain = domain == LINUX_AF_INET6 ? AF_INET6 : domain;
2017-04-21 10:43:26 +00:00
sa.type = type;
sa.protocol = protocol;
if ((rc = sys_socket(curthread, &sa)))
goto kern_fail;
return curthread->td_retval[0];
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_getsockopt(int s, int level, int optname, void *optval,
socklen_t *optlen)
{
int rc;
if (level == LINUX_SOL_SOCKET)
level = SOL_SOCKET;
optname = linux2freebsd_opt(level, optname);
if (optname < 0) {
rc = EINVAL;
goto kern_fail;
}
if ((rc = kern_getsockopt(curthread, s, level, optname,
optval, UIO_USERSPACE, optlen)))
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_getsockopt_freebsd(int s, int level, int optname,
void *optval, socklen_t *optlen)
{
int rc;
if ((rc = kern_getsockopt(curthread, s, level, optname,
optval, UIO_USERSPACE, optlen)))
2017-04-21 10:43:26 +00:00
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_setsockopt(int s, int level, int optname, const void *optval,
socklen_t optlen)
{
int rc;
if (level == LINUX_SOL_SOCKET)
level = SOL_SOCKET;
optname = linux2freebsd_opt(level, optname);
if (optname < 0) {
rc = EINVAL;
goto kern_fail;
}
if ((rc = kern_setsockopt(curthread, s, level, optname,
__DECONST(void *, optval), UIO_USERSPACE, optlen)))
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_setsockopt_freebsd(int s, int level, int optname,
const void *optval, socklen_t optlen)
{
int rc;
if ((rc = kern_setsockopt(curthread, s, level, optname,
__DECONST(void *, optval), UIO_USERSPACE, optlen)))
2017-04-21 10:43:26 +00:00
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_ioctl(int fd, unsigned long request, ...)
{
int rc;
va_list ap;
caddr_t argp;
long req = linux2freebsd_ioctl(request);
if (req < 0) {
rc = EINVAL;
goto kern_fail;
}
va_start(ap, request);
argp = va_arg(ap, caddr_t);
va_end(ap);
2017-04-21 10:43:26 +00:00
if ((rc = kern_ioctl(curthread, fd, req, argp)))
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_ioctl_freebsd(int fd, unsigned long request, ...)
{
int rc;
va_list ap;
caddr_t argp;
va_start(ap, request);
argp = va_arg(ap, caddr_t);
va_end(ap);
if ((rc = kern_ioctl(curthread, fd, request, argp)))
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
2017-04-21 10:43:26 +00:00
int
ff_close(int fd)
{
int rc;
2022-09-02 08:51:22 +00:00
if ((rc = kern_close(curthread, fd)))
2017-04-21 10:43:26 +00:00
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
ssize_t
ff_read(int fd, void *buf, size_t nbytes)
{
struct uio auio;
struct iovec aiov;
int rc;
2022-09-02 08:51:22 +00:00
2017-04-21 10:43:26 +00:00
if (nbytes > INT_MAX) {
rc = EINVAL;
goto kern_fail;
}
aiov.iov_base = buf;
aiov.iov_len = nbytes;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_resid = nbytes;
auio.uio_segflg = UIO_SYSSPACE;
if ((rc = kern_readv(curthread, fd, &auio)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
ssize_t
ff_readv(int fd, const struct iovec *iov, int iovcnt)
{
struct uio auio;
int rc, len, i;
len = 0;
for (i = 0; i < iovcnt; i++)
len += iov[i].iov_len;
auio.uio_iov = __DECONST(struct iovec *, iov);
auio.uio_iovcnt = iovcnt;
auio.uio_resid = len;
auio.uio_segflg = UIO_SYSSPACE;
if ((rc = kern_readv(curthread, fd, &auio)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
ssize_t
ff_write(int fd, const void *buf, size_t nbytes)
{
struct uio auio;
struct iovec aiov;
int rc;
if (nbytes > INT_MAX) {
rc = EINVAL;
goto kern_fail;
}
aiov.iov_base = (void *)(uintptr_t)buf;
aiov.iov_len = nbytes;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_resid = nbytes;
auio.uio_segflg = UIO_SYSSPACE;
if ((rc = kern_writev(curthread, fd, &auio)))
goto kern_fail;
rc = curthread->td_retval[0];
2022-09-02 08:51:22 +00:00
2017-04-21 10:43:26 +00:00
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
ssize_t
ff_writev(int fd, const struct iovec *iov, int iovcnt)
{
struct uio auio;
int i, rc, len;
len = 0;
for (i = 0; i < iovcnt; i++)
len += iov[i].iov_len;
auio.uio_iov = __DECONST(struct iovec *, iov);
auio.uio_iovcnt = iovcnt;
auio.uio_resid = len;
auio.uio_segflg = UIO_SYSSPACE;
if ((rc = kern_writev(curthread, fd, &auio)))
goto kern_fail;
rc = curthread->td_retval[0];
2022-09-02 08:51:22 +00:00
2017-04-21 10:43:26 +00:00
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
ssize_t
ff_send(int s, const void *buf, size_t len, int flags)
{
return (ff_sendto(s, buf, len, flags, NULL, 0));
}
ssize_t
ff_sendto(int s, const void *buf, size_t len, int flags,
const struct linux_sockaddr *to, socklen_t tolen)
{
struct msghdr msg;
struct iovec aiov;
int rc;
struct sockaddr_storage bsdaddr;
struct sockaddr *pf = (struct sockaddr *)&bsdaddr;
2017-04-21 10:43:26 +00:00
if (to) {
linux2freebsd_sockaddr(to, tolen, pf);
} else {
pf = NULL;
}
msg.msg_name = pf;
msg.msg_namelen = tolen;
msg.msg_iov = &aiov;
msg.msg_iovlen = 1;
msg.msg_control = 0;
aiov.iov_base = __DECONST(void *, buf);
aiov.iov_len = len;
if ((rc = sendit(curthread, s, &msg, flags)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
ssize_t
ff_sendmsg(int s, const struct msghdr *msg, int flags)
{
int rc, ret;
struct sockaddr_storage freebsd_sa;
struct msghdr freebsd_msg;
struct cmsghdr *freebsd_cmsg = NULL;
freebsd_msg.msg_name = &freebsd_sa;
if ((__DECONST(struct linux_msghdr *, msg))->msg_control) {
freebsd_cmsg = malloc((__DECONST(struct linux_msghdr *, msg))->msg_controllen, NULL, 0);
if (freebsd_cmsg == NULL) {
rc = ENOMEM;
goto kern_fail;
}
}
freebsd_msg.msg_control = freebsd_cmsg;
2017-04-21 10:43:26 +00:00
ret = linux2freebsd_msghdr((const struct linux_msghdr *)msg, &freebsd_msg, 1);
if (ret < 0) {
rc = EINVAL;
goto kern_fail;
}
rc = sendit(curthread, s, &freebsd_msg, flags);
if (rc)
2017-04-21 10:43:26 +00:00
goto kern_fail;
rc = curthread->td_retval[0];
freebsd2linux_msghdr(__DECONST(struct linux_msghdr *, msg), &freebsd_msg, 1);
if (freebsd_cmsg) {
free(freebsd_cmsg, NULL);
}
2017-04-21 10:43:26 +00:00
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
ssize_t
ff_recv(int s, void *buf, size_t len, int flags)
{
return (ff_recvfrom(s, buf, len, flags, NULL, 0));
}
ssize_t
ff_recvfrom(int s, void *buf, size_t len, int flags,
struct linux_sockaddr *from, socklen_t *fromlen)
{
struct msghdr msg;
struct iovec aiov;
int rc;
struct sockaddr_storage bsdaddr;
2017-04-21 10:43:26 +00:00
if (fromlen != NULL)
msg.msg_namelen = *fromlen;
else
msg.msg_namelen = 0;
msg.msg_name = &bsdaddr;
msg.msg_iov = &aiov;
msg.msg_iovlen = 1;
aiov.iov_base = buf;
aiov.iov_len = len;
msg.msg_control = 0;
msg.msg_flags = flags;
if ((rc = kern_recvit(curthread, s, &msg, UIO_SYSSPACE, NULL)))
goto kern_fail;
rc = curthread->td_retval[0];
if (fromlen != NULL)
*fromlen = msg.msg_namelen;
if (from && msg.msg_namelen != 0)
freebsd2linux_sockaddr(from, (struct sockaddr *)&bsdaddr);
2017-04-21 10:43:26 +00:00
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
/*
* It is considered here that the upper 4 bytes of
* msg->iovlen and msg->msg_controllen in linux_msghdr are 0.
*/
2017-04-21 10:43:26 +00:00
ssize_t
ff_recvmsg(int s, struct msghdr *msg, int flags)
{
int rc, ret;
struct msghdr freebsd_msg;
2017-04-21 10:43:26 +00:00
ret = linux2freebsd_msghdr((struct linux_msghdr *)msg, &freebsd_msg, 0);
if (ret < 0) {
rc = EINVAL;
goto kern_fail;
}
freebsd_msg.msg_flags = flags;
2017-04-21 10:43:26 +00:00
if ((rc = kern_recvit(curthread, s, &freebsd_msg, UIO_SYSSPACE, NULL))) {
2017-04-21 10:43:26 +00:00
goto kern_fail;
}
rc = curthread->td_retval[0];
freebsd2linux_msghdr((struct linux_msghdr *)msg, &freebsd_msg, 0);
2017-04-21 10:43:26 +00:00
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_fcntl(int fd, int cmd, ...)
{
int rc;
va_list ap;
uintptr_t argp;
va_start(ap, cmd);
argp = va_arg(ap, uintptr_t);
2022-09-02 08:51:22 +00:00
va_end(ap);
2017-04-21 10:43:26 +00:00
if ((rc = kern_fcntl(curthread, fd, cmd, argp)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_accept(int s, struct linux_sockaddr * addr,
socklen_t * addrlen)
{
int rc;
struct file *fp;
2017-06-07 05:18:11 +00:00
struct sockaddr *pf = NULL;
socklen_t socklen = sizeof(struct sockaddr_storage);
2017-04-21 10:43:26 +00:00
if ((rc = kern_accept(curthread, s, &pf, &socklen, &fp)))
goto kern_fail;
rc = curthread->td_retval[0];
fdrop(fp, curthread);
2017-06-07 05:18:11 +00:00
if (addr && pf)
2017-04-21 10:43:26 +00:00
freebsd2linux_sockaddr(addr, pf);
if (addrlen)
*addrlen = pf->sa_len;
2022-09-02 08:51:22 +00:00
2017-06-07 05:18:11 +00:00
if(pf != NULL)
free(pf, M_SONAME);
2017-04-21 10:43:26 +00:00
return (rc);
2022-09-02 08:51:22 +00:00
2017-04-21 10:43:26 +00:00
kern_fail:
2017-06-07 05:18:11 +00:00
if(pf != NULL)
free(pf, M_SONAME);
2017-04-21 10:43:26 +00:00
ff_os_errno(rc);
return (-1);
}
int
ff_listen(int s, int backlog)
{
int rc;
struct listen_args la = {
.s = s,
.backlog = backlog,
};
if ((rc = sys_listen(curthread, &la)))
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_bind(int s, const struct linux_sockaddr *addr, socklen_t addrlen)
{
2022-09-02 08:51:22 +00:00
int rc;
struct sockaddr_storage bsdaddr;
linux2freebsd_sockaddr(addr, addrlen, (struct sockaddr *)&bsdaddr);
2017-04-21 10:43:26 +00:00
if ((rc = kern_bindat(curthread, AT_FDCWD, s, (struct sockaddr *)&bsdaddr)))
2017-04-21 10:43:26 +00:00
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_connect(int s, const struct linux_sockaddr *name, socklen_t namelen)
{
int rc;
struct sockaddr_storage bsdaddr;
linux2freebsd_sockaddr(name, namelen, (struct sockaddr *)&bsdaddr);
2017-04-21 10:43:26 +00:00
if ((rc = kern_connectat(curthread, AT_FDCWD, s, (struct sockaddr *)&bsdaddr)))
2017-04-21 10:43:26 +00:00
goto kern_fail;
2017-04-21 10:43:26 +00:00
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_getpeername(int s, struct linux_sockaddr * name,
socklen_t *namelen)
{
int rc;
2017-06-07 05:18:11 +00:00
struct sockaddr *pf = NULL;
2017-04-21 10:43:26 +00:00
if ((rc = kern_getpeername(curthread, s, &pf, namelen)))
goto kern_fail;
2017-06-07 05:18:11 +00:00
if (name && pf)
2017-04-21 10:43:26 +00:00
freebsd2linux_sockaddr(name, pf);
2017-06-07 05:18:11 +00:00
if(pf != NULL)
free(pf, M_SONAME);
2017-04-21 10:43:26 +00:00
return (rc);
2022-09-02 08:51:22 +00:00
2017-04-21 10:43:26 +00:00
kern_fail:
2017-06-07 05:18:11 +00:00
if(pf != NULL)
free(pf, M_SONAME);
2017-04-21 10:43:26 +00:00
ff_os_errno(rc);
return (-1);
}
int
ff_getsockname(int s, struct linux_sockaddr *name,
socklen_t *namelen)
{
int rc;
2017-06-07 05:18:11 +00:00
struct sockaddr *pf = NULL;
2017-04-21 10:43:26 +00:00
if ((rc = kern_getsockname(curthread, s, &pf, namelen)))
goto kern_fail;
2017-06-07 05:18:11 +00:00
if (name && pf)
2017-04-21 10:43:26 +00:00
freebsd2linux_sockaddr(name, pf);
2017-06-07 05:18:11 +00:00
if(pf != NULL)
free(pf, M_SONAME);
2017-04-21 10:43:26 +00:00
return (rc);
kern_fail:
2017-06-07 05:18:11 +00:00
if(pf != NULL)
free(pf, M_SONAME);
2017-04-21 10:43:26 +00:00
ff_os_errno(rc);
return (-1);
}
2022-09-02 08:51:22 +00:00
int
2017-04-21 10:43:26 +00:00
ff_shutdown(int s, int how)
{
int rc;
struct shutdown_args sa = {
.s = s,
.how = how,
};
if ((rc = sys_shutdown(curthread, &sa)))
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp,
const void *newp, size_t newlen)
{
int rc;
size_t retval;
2022-09-02 08:51:22 +00:00
rc = userland_sysctl(curthread, __DECONST(int *, name), namelen, oldp, oldlenp,
2017-04-21 10:43:26 +00:00
1, __DECONST(void *, newp), newlen, &retval, 0);
if (rc)
goto kern_fail;
if (oldlenp)
*oldlenp = retval;
return (0);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout)
{
int rc;
rc = kern_select(curthread, nfds, readfds, writefds, exceptfds, timeout, 64);
if (rc)
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_poll(struct pollfd fds[], nfds_t nfds, int timeout)
{
int rc;
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
if ((rc = kern_poll(curthread, fds, nfds, &ts, NULL)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_kqueue(void)
{
int rc;
if ((rc = kern_kqueue(curthread, 0, NULL)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
struct sys_kevent_args {
int fd;
const struct kevent *changelist;
int nchanges;
void *eventlist;
2017-04-21 10:43:26 +00:00
int nevents;
const struct timespec *timeout;
void (*do_each)(void **, struct kevent *);
2017-04-21 10:43:26 +00:00
};
static int
kevent_copyout(void *arg, struct kevent *kevp, int count)
{
int i;
2017-06-13 11:26:38 +00:00
struct kevent *ke;
2017-04-21 10:43:26 +00:00
struct sys_kevent_args *uap;
uap = (struct sys_kevent_args *)arg;
2017-06-13 11:26:38 +00:00
if (!uap->do_each) {
bcopy(kevp, uap->eventlist, count * sizeof *kevp);
uap->eventlist = (void *)((struct kevent *)(uap->eventlist) + count);
2017-06-13 11:26:38 +00:00
} else {
for (ke = kevp, i = 0; i < count; i++, ke++) {
uap->do_each(&(uap->eventlist), ke);
}
}
2017-04-21 10:43:26 +00:00
return (0);
}
/*
* Copy 'count' items from the list pointed to by uap->changelist.
*/
static int
kevent_copyin(void *arg, struct kevent *kevp, int count)
{
struct sys_kevent_args *uap;
uap = (struct sys_kevent_args *)arg;
bcopy(uap->changelist, kevp, count * sizeof *kevp);
uap->changelist += count;
return (0);
}
int
2022-09-02 08:51:22 +00:00
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 *))
2017-04-21 10:43:26 +00:00
{
int rc;
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
2017-04-21 10:43:26 +00:00
struct sys_kevent_args ska = {
kq,
changelist,
nchanges,
eventlist,
nevents,
&ts,
do_each
2017-04-21 10:43:26 +00:00
};
2017-04-21 10:43:26 +00:00
struct kevent_copyops k_ops = {
&ska,
kevent_copyout,
kevent_copyin
};
2022-09-02 08:51:22 +00:00
if ((rc = kern_kevent(curthread, kq, nchanges, nevents, &k_ops,
2017-04-21 10:43:26 +00:00
&ts)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
2022-09-02 08:51:22 +00:00
ff_kevent(int kq, const struct kevent *changelist, int nchanges,
struct kevent *eventlist, int nevents, const struct timespec *timeout)
{
return ff_kevent_do_each(kq, changelist, nchanges, eventlist, nevents, timeout, NULL);
}
int
#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 31)
ff_gettimeofday(struct timeval *tv, void *tz)
#else
ff_gettimeofday(struct timeval *tv, struct timezone *tz)
#endif
{
long nsec;
ff_get_current_time(&(tv->tv_sec), &nsec);
tv->tv_usec = nsec/1000;
return 0;
}
int
ff_dup(int oldfd)
{
int rc;
struct dup_args da = {
.fd = oldfd,
};
if ((rc = sys_dup(curthread, &da)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
int
ff_dup2(int oldfd, int newfd)
{
int rc;
struct dup2_args da = {
.from = oldfd,
.to = newfd
};
if ((rc = sys_dup2(curthread, &da)))
goto kern_fail;
rc = curthread->td_retval[0];
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}
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)
{
struct sockaddr_storage sa_gw, sa_dst, sa_nm;
struct sockaddr *psa_gw, *psa_dst, *psa_nm;
int rtreq, rtflag;
int rc;
struct rt_addrinfo info;
struct rib_cmd_info rci;
switch (req) {
case FF_ROUTE_ADD:
rtreq = RTM_ADD;
break;
case FF_ROUTE_DEL:
rtreq = RTM_DELETE;
break;
case FF_ROUTE_CHANGE:
rtreq = RTM_CHANGE;
break;
default:
rc = EINVAL;
goto kern_fail;
}
switch (flag) {
case FF_RTF_HOST:
rtflag = RTF_HOST;
break;
case FF_RTF_GATEWAY:
rtflag = RTF_GATEWAY;
break;
default:
rc = EINVAL;
goto kern_fail;
};
bzero((caddr_t)&info, sizeof(info));
info.rti_flags = rtflag;
if (gw != NULL) {
psa_gw = (struct sockaddr *)&sa_gw;
linux2freebsd_sockaddr(gw, sizeof(*gw), psa_gw);
info.rti_info[RTAX_GATEWAY] = psa_gw;
} else {
psa_gw = NULL;
}
if (dst != NULL) {
psa_dst = (struct sockaddr *)&sa_dst;
linux2freebsd_sockaddr(dst, sizeof(*dst), psa_dst);
info.rti_info[RTAX_DST] = psa_dst;
} else {
psa_dst = NULL;
}
if (netmask != NULL) {
psa_nm = (struct sockaddr *)&sa_nm;
linux2freebsd_sockaddr(netmask, sizeof(*netmask), psa_nm);
info.rti_info[RTAX_NETMASK] = psa_nm;
} else {
psa_nm = NULL;
}
rc = rib_action(RT_DEFAULT_FIB, rtreq, &info, &rci);
if (rc != 0)
goto kern_fail;
return (rc);
kern_fail:
ff_os_errno(rc);
return (-1);
}