/* * Copyright (c) 2010 Kip Macy. All rights reserved. * Copyright (C) 2017 THL A29 Limited, a Tencent company. * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 #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_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 #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 #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 /* ioctl define end */ 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; default: return -1; } } 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; 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; } } 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; default: return -1; } } 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; case LINUX_TCP_MD5SIG: return TCP_MD5SIG; default: return -1; } } 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_TCP: return tcp_opt_convert(optname); default: return -1; } } static void linux2freebsd_sockaddr(const struct linux_sockaddr *linux, socklen_t addrlen, struct sockaddr *freebsd) { if (linux == NULL) { return; } /* #linux and #freebsd may point to the same address */ freebsd->sa_family = linux->sa_family; freebsd->sa_len = addrlen; bcopy(linux->sa_data, freebsd->sa_data, sizeof(linux->sa_data)); } static void freebsd2linux_sockaddr(struct linux_sockaddr *linux, struct sockaddr *freebsd) { if (linux == NULL) { return; } linux->sa_family = freebsd->sa_family; bcopy(freebsd->sa_data, linux->sa_data, sizeof(freebsd->sa_data)); } int ff_socket(int domain, int type, int protocol) { int rc; struct socket_args sa; sa.domain = domain; 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))) 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))) 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); 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); } int ff_close(int fd) { int rc; if ((rc = kern_close(curthread, fd))) 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; 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]; 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]; 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 bsdaddr; struct sockaddr *pf = &bsdaddr; 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; struct sockaddr freebsd_sa; void *linux_sa = msg->msg_name; if (linux_sa != NULL) { linux2freebsd_sockaddr(linux_sa, sizeof(struct linux_sockaddr), &freebsd_sa); __DECONST(struct msghdr *, msg)->msg_name = &freebsd_sa; } rc = sendit(curthread, s, __DECONST(struct msghdr *, msg), flags); __DECONST(struct msghdr *, msg)->msg_name = linux_sa; if (rc) goto kern_fail; rc = curthread->td_retval[0]; 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 bsdaddr; 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) freebsd2linux_sockaddr(from, &bsdaddr); return (rc); kern_fail: ff_os_errno(rc); return (-1); } ssize_t ff_recvmsg(int s, struct msghdr *msg, int flags) { int rc, oldflags; oldflags = msg->msg_flags; msg->msg_flags = flags; if ((rc = kern_recvit(curthread, s, msg, UIO_SYSSPACE, NULL))) { msg->msg_flags = oldflags; goto kern_fail; } rc = curthread->td_retval[0]; freebsd2linux_sockaddr(msg->msg_name, msg->msg_name); 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); va_end(ap); 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; struct sockaddr *pf = NULL; socklen_t socklen = sizeof(struct sockaddr); if ((rc = kern_accept(curthread, s, &pf, &socklen, &fp))) goto kern_fail; rc = curthread->td_retval[0]; fdrop(fp, curthread); if (addr && pf) freebsd2linux_sockaddr(addr, pf); if (addrlen) *addrlen = socklen; if(pf != NULL) free(pf, M_SONAME); return (rc); kern_fail: if(pf != NULL) free(pf, M_SONAME); 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) { int rc; struct sockaddr bsdaddr; linux2freebsd_sockaddr(addr, addrlen, &bsdaddr); if ((rc = kern_bindat(curthread, AT_FDCWD, s, &bsdaddr))) 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 bsdaddr; linux2freebsd_sockaddr(name, namelen, &bsdaddr); if ((rc = kern_connectat(curthread, AT_FDCWD, s, &bsdaddr))) goto kern_fail; return (rc); kern_fail: ff_os_errno(rc); return (-1); } int ff_getpeername(int s, struct linux_sockaddr * name, socklen_t *namelen) { int rc; struct sockaddr *pf = NULL; if ((rc = kern_getpeername(curthread, s, &pf, namelen))) goto kern_fail; if (name && pf) freebsd2linux_sockaddr(name, pf); if(pf != NULL) free(pf, M_SONAME); return (rc); kern_fail: if(pf != NULL) free(pf, M_SONAME); ff_os_errno(rc); return (-1); } int ff_getsockname(int s, struct linux_sockaddr *name, socklen_t *namelen) { int rc; struct sockaddr *pf = NULL; if ((rc = kern_getsockname(curthread, s, &pf, namelen))) goto kern_fail; if (name && pf) freebsd2linux_sockaddr(name, pf); if(pf != NULL) free(pf, M_SONAME); return (rc); kern_fail: if(pf != NULL) free(pf, M_SONAME); ff_os_errno(rc); return (-1); } int 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; rc = userland_sysctl(curthread, __DECONST(int *, name), namelen, oldp, oldlenp, 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; int nevents; const struct timespec *timeout; void (*do_each)(void **, struct kevent *); }; static int kevent_copyout(void *arg, struct kevent *kevp, int count) { int i; struct kevent *ke; struct sys_kevent_args *uap; uap = (struct sys_kevent_args *)arg; if (!uap->do_each) { bcopy(kevp, uap->eventlist, count * sizeof *kevp); uap->eventlist = (void *)((struct kevent *)(uap->eventlist) + count); } else { for (ke = kevp, i = 0; i < count; i++, ke++) { uap->do_each(&(uap->eventlist), ke); } } 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 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 *)) { int rc; struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 0; struct sys_kevent_args ska = { kq, changelist, nchanges, eventlist, nevents, &ts, do_each }; struct kevent_copyops k_ops = { &ska, kevent_copyout, kevent_copyin }; if ((rc = kern_kevent(curthread, kq, nchanges, nevents, &k_ops, &ts))) goto kern_fail; rc = curthread->td_retval[0]; return (rc); kern_fail: ff_os_errno(rc); return (-1); } int 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 ff_gettimeofday(struct timeval *tv, struct timezone *tz) { 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 sa_gw, sa_dst, sa_nm; struct sockaddr *psa_gw, *psa_dst, *psa_nm; int rtreq, rtflag; int rc; 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; }; if (gw != NULL) { psa_gw = &sa_gw; linux2freebsd_sockaddr(gw, sizeof(*gw), psa_gw); } else { psa_gw = NULL; } if (dst != NULL) { psa_dst = &sa_dst; linux2freebsd_sockaddr(dst, sizeof(*dst), psa_dst); } else { psa_dst = NULL; } if (netmask != NULL) { psa_nm = &sa_nm; linux2freebsd_sockaddr(netmask, sizeof(*netmask), psa_nm); } else { psa_nm = NULL; } rc = rtrequest_fib(rtreq, psa_dst, psa_gw, psa_nm, rtflag, NULL, RT_DEFAULT_FIB); if (rc != 0) goto kern_fail; return (rc); kern_fail: ff_os_errno(rc); return (-1); }