diff options
Diffstat (limited to 'rtemslwip/common/rtems_lwip_io.c')
-rw-r--r-- | rtemslwip/common/rtems_lwip_io.c | 1323 |
1 files changed, 1323 insertions, 0 deletions
diff --git a/rtemslwip/common/rtems_lwip_io.c b/rtemslwip/common/rtems_lwip_io.c new file mode 100644 index 0000000..8aa28b5 --- /dev/null +++ b/rtemslwip/common/rtems_lwip_io.c @@ -0,0 +1,1323 @@ +/* + * + * RTEMS Project (https://www.rtems.org/) + * + * Copyright (c) 2021 Vijay Kumar Banerjee <vijay@rtems.org>. + * 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. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#define LWIP_COMPAT_SOCKETS 0 + +#include <string.h> +#include <stdarg.h> +/* #include <stdlib.h> */ +#include <stdio.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/libio_.h> +#include <rtems/error.h> + +#include <errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/filio.h> +#include <sys/sysctl.h> + +#include <rtems/thread.h> + +#include <lwip/tcpip.h> +#include <lwip/api.h> +#include <lwip/netbuf.h> +#include <lwip/netdb.h> +#include <lwip/netifapi.h> +#include <lwip/sockets.h> +#include <lwip/sys.h> +#include <sys/errno.h> + +#include <lwip/init.h> +#include "lwip/err.h" +#include "lwip/tcp.h" +#include <netif/etharp.h> + +#include <string.h> + +#include "lwip/tcpip.h" +//#include "arch/eth_lwip.h" +#include "lwip/api.h" +#include "lwip/netbuf.h" +#include "lwip/netdb.h" +#include "lwip/netifapi.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" + +#include "rtems_lwip_int.h" + +static const rtems_filesystem_file_handlers_r rtems_lwip_socket_handlers; + +static rtems_recursive_mutex rtems_lwip_mutex = + RTEMS_RECURSIVE_MUTEX_INITIALIZER( "_LWIP" ); + +void rtems_lwip_semaphore_obtain( void ) +{ + rtems_recursive_mutex_lock( &rtems_lwip_mutex ); +} + +/* + * Release network mutex + */ +void rtems_lwip_semaphore_release( void ) +{ + rtems_recursive_mutex_unlock( &rtems_lwip_mutex ); +} + +static inline int rtems_lwip_iop_to_lwipfd( rtems_libio_t *iop ) +{ + if ( iop == NULL ) { + errno = EBADF; + + return -1; + } + +/* + if ((rtems_libio_iop_flags(iop) & LIBIO_FLAGS_OPEN) == 0) { + errno = EBADF; + return -1; + } + */ + + if ( iop->pathinfo.handlers != &rtems_lwip_socket_handlers ) { + errno = ENOTSOCK; + + return -1; + } + + return iop->data0; +} + +/* + * Convert an RTEMS file descriptor to a LWIP socket pointer. + */ +int rtems_lwip_sysfd_to_lwipfd( int fd ) +{ + if ( (uint32_t) fd >= rtems_libio_number_iops ) { + errno = EBADF; + + return -1; + } + + return rtems_lwip_iop_to_lwipfd( rtems_libio_iop( fd ) ); +} + +/* + * Create an RTEMS file descriptor for a socket + */ +static int rtems_lwip_make_sysfd_from_lwipfd( int lfwipfd ) +{ + rtems_libio_t *iop; + int fd; + + iop = rtems_libio_allocate(); + + if ( iop == 0 ) + rtems_set_errno_and_return_minus_one( ENFILE ); + + fd = rtems_libio_iop_to_descriptor( iop ); + iop->data0 = lfwipfd; + iop->data1 = NULL; + iop->pathinfo.handlers = &rtems_lwip_socket_handlers; + iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry; + rtems_filesystem_location_add_to_mt_entry( &iop->pathinfo ); + rtems_libio_iop_flags_set( iop, LIBIO_FLAGS_READ_WRITE | LIBIO_FLAGS_OPEN ); + + return fd; +} + +/* + ********************************************************************* + * BSD-style entry points * + ********************************************************************* + */ +int socket( + int domain, + int type, + int protocol +) +{ + int fd; + int lwipfd; + + if ( domain == rtems_lwip_sysdefs_PF_UNSPEC ) { + domain = PF_UNSPEC; + } else if ( domain == rtems_lwip_sysdefs_PF_INET ) { + domain = PF_INET; + } else if ( domain == rtems_lwip_sysdefs_PF_INET6 ) { + domain = PF_INET6; + } else { + errno = EINVAL; + + return -1; + } + + if ( type == rtems_lwip_sysdefs_SOCK_STREAM ) { + type = SOCK_STREAM; + } else if ( type == rtems_lwip_sysdefs_SOCK_DGRAM ) { + type = SOCK_DGRAM; + } else { + errno = EINVAL; + + return -1; + } + + rtems_lwip_semaphore_obtain(); + + lwipfd = lwip_socket( domain, type, 0 ); + + if ( lwipfd < 0 ) { + fd = -1; + } else { + fd = rtems_lwip_make_sysfd_from_lwipfd( lwipfd ); + + if ( fd < 0 ) { + lwip_close( lwipfd ); + } + } + + rtems_lwip_semaphore_release(); + + return fd; +} + +int bind( + int s, + const struct sockaddr *name, + socklen_t namelen +) +{ + int ret = -1; + int lwipfd; + int family; + struct sockaddr *lwipname; + socklen_t lwipnamelen; + struct sockaddr_in so_in; + + #if LWIP_IPV6 + struct sockaddr_in6 so_in6; + #endif + + family = rtems_lwip_sysdefs_sockaddr_get_family( name ); + + if ( ( family == rtems_lwip_sysdefs_AF_INET ) && + ( namelen >= rtems_lwip_sysdefs_sockaddr_in_size ) ) { + so_in.sin_len = sizeof( so_in ); + so_in.sin_family = PF_INET; + so_in.sin_port = rtems_lwip_sysdefs_sockaddr_in_get_sin_port( name ); + so_in.sin_addr.s_addr = + rtems_lwip_sysdefs_sockaddr_in_get_sin_addr( name ); + lwipname = (struct sockaddr *) &so_in; + lwipnamelen = so_in.sin_len; + #if LWIP_IPV6 + } else if ( ( family == rtems_lwip_sysdefs_AF_INET6 ) && + ( namelen >= rtems_lwip_sysdefs_sockaddr_in6_size ) ) { + so_in6.sin6_len = sizeof( so_in6 ); + so_in6.sin6_family = PF_INET6; + so_in6.sin6_port = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_port( name ); + memcpy( &so_in6.sin6_addr, + rtems_lwip_sysdefs_sockaddr_in6_get_sin6_addr_ptr_const( name ), + sizeof( so_in6.sin6_addr ) ); + so_in6.sin6_flowinfo = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_flowinfo( + name ); + so_in6.sin6_scope_id = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_scope_id( + name ); + lwipname = (struct sockaddr *) &so_in6; + lwipnamelen = so_in6.sin6_len; + #endif + } else { + errno = EINVAL; + + return -1; + } + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + ret = lwip_bind( lwipfd, lwipname, lwipnamelen ); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +int connect( + int s, + const struct sockaddr *name, + socklen_t namelen +) +{ + int ret = -1; + int lwipfd; + int family; + struct sockaddr *lwipname; + socklen_t lwipnamelen; + struct sockaddr_in so_in; + + #if LWIP_IPV6 + struct sockaddr_in6 so_in6; + #endif + + family = rtems_lwip_sysdefs_sockaddr_get_family( name ); + + if ( ( family == rtems_lwip_sysdefs_AF_INET ) && + ( namelen >= rtems_lwip_sysdefs_sockaddr_in_size ) ) { + so_in.sin_len = sizeof( so_in ); + so_in.sin_family = AF_INET; + so_in.sin_port = rtems_lwip_sysdefs_sockaddr_in_get_sin_port( name ); + so_in.sin_addr.s_addr = + rtems_lwip_sysdefs_sockaddr_in_get_sin_addr( name ); + lwipname = (struct sockaddr *) &so_in; + lwipnamelen = so_in.sin_len; + #if LWIP_IPV6 + } else if ( ( family == rtems_lwip_sysdefs_AF_INET6 ) && + ( namelen >= rtems_lwip_sysdefs_sockaddr_in6_size ) ) { + so_in6.sin6_len = sizeof( so_in6 ); + so_in6.sin6_family = AF_INET6; + so_in6.sin6_port = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_port( name ); + memcpy( &so_in6.sin6_addr, + rtems_lwip_sysdefs_sockaddr_in6_get_sin6_addr_ptr_const( name ), + sizeof( so_in6.sin6_addr ) ); + so_in6.sin6_flowinfo = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_flowinfo( + name ); + so_in6.sin6_scope_id = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_scope_id( + name ); + lwipname = (struct sockaddr *) &so_in6; + lwipnamelen = so_in6.sin6_len; + #endif + } else { + errno = EINVAL; + + return -1; + } + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + ret = lwip_connect( lwipfd, lwipname, lwipnamelen ); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +int listen( + int s, + int backlog +) +{ + int ret = -1; + int lwipfd; + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + ret = lwip_listen( lwipfd, backlog ); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +int accept( + int s, + struct sockaddr *name, + socklen_t *namelen +) +{ + int ret = -1; + int lwipfd; + struct sockaddr *lwipname = name; + socklen_t lwipnamelen = *namelen; + struct sockaddr_in so_in; + + #if LWIP_IPV6 + struct sockaddr_in6 so_in6; + #endif + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + + rtems_lwip_semaphore_release(); + lwipfd = lwip_accept( lwipfd, lwipname, &lwipnamelen ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + if ( lwipfd < 0 ) + return lwipfd; + + if ( lwipname->sa_family == AF_INET ) { + memcpy( &so_in, lwipname, sizeof( so_in ) ); + rtems_lwip_sysdefs_sockaddr_set_len( name, + rtems_lwip_sysdefs_sockaddr_in_size ); + rtems_lwip_sysdefs_sockaddr_set_family( name, rtems_lwip_sysdefs_AF_INET ); + rtems_lwip_sysdefs_sockaddr_in_set_sin_port( name, so_in.sin_port ); + rtems_lwip_sysdefs_sockaddr_in_set_sin_addr( name, so_in.sin_addr.s_addr ); + #if LWIP_IPV6 + } else if ( lwipname->sa_family == AF_INET6 ) { + memcpy( &so_in6, lwipname, sizeof( so_in6 ) ); + rtems_lwip_sysdefs_sockaddr_set_len( name, + rtems_lwip_sysdefs_sockaddr_in6_size ); + rtems_lwip_sysdefs_sockaddr_set_family( name, + rtems_lwip_sysdefs_AF_INET6 ); + + rtems_lwip_sysdefs_sockaddr_in6_set_sin6_port( name, so_in6.sin6_port ); + memcpy( rtems_lwip_sysdefs_sockaddr_in6_get_sin6_addr_ptr( name ), + &so_in6.sin6_addr, + sizeof( so_in6.sin6_addr ) ); + rtems_lwip_sysdefs_sockaddr_in6_set_sin6_flowinfo( name, + so_in6.sin6_flowinfo ); + rtems_lwip_sysdefs_sockaddr_in6_set_sin6_scope_id( name, + so_in6.sin6_scope_id ); + #endif + } else { + lwip_close( lwipfd ); + errno = EINVAL; + + return -1; + } + + rtems_lwip_semaphore_obtain(); + ret = rtems_lwip_make_sysfd_from_lwipfd( lwipfd ); + + if ( ret < 0 ) { + rtems_lwip_semaphore_release(); + lwip_close( lwipfd ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + *namelen = rtems_lwip_sysdefs_sockaddr_get_len( name ); + + return ret; +} + +/* + * Shutdown routine + */ + +int shutdown( + int s, + int how +) +{ + int ret = -1; + int lwipfd; + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + rtems_lwip_semaphore_release(); + ret = lwip_shutdown( lwipfd, how ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +ssize_t recv( + int s, + void *buf, + size_t len, + int flags +) +{ + int ret = -1; + int lwipfd; + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + rtems_lwip_semaphore_release(); + ret = lwip_recv( lwipfd, buf, len, flags ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +ssize_t send( + int s, + const void *buf, + size_t len, + int flags +) +{ + int ret = -1; + int lwipfd; + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + rtems_lwip_semaphore_release(); + ret = lwip_send( lwipfd, buf, len, flags ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +ssize_t recvfrom( + int s, + void *buf, + size_t len, + int flags, + struct sockaddr *name, + socklen_t *namelen +) +{ + int ret = -1; + int lwipfd; + struct sockaddr *lwipname = name; + socklen_t lwipnamelen = *namelen; + struct sockaddr_in so_in; + + #if LWIP_IPV6 + struct sockaddr_in6 so_in6; + #endif + + if ( name == NULL ) + return recv( s, buf, len, flags ); + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + rtems_lwip_semaphore_release(); + lwipfd = lwip_recvfrom( lwipfd, buf, len, flags, lwipname, &lwipnamelen ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + if ( lwipfd < 0 ) + return lwipfd; + + if ( lwipname->sa_family == AF_INET ) { + memcpy( &so_in, lwipname, sizeof( so_in ) ); + rtems_lwip_sysdefs_sockaddr_set_len( name, + rtems_lwip_sysdefs_sockaddr_in_size ); + rtems_lwip_sysdefs_sockaddr_set_family( name, rtems_lwip_sysdefs_AF_INET ); + rtems_lwip_sysdefs_sockaddr_in_set_sin_port( name, so_in.sin_port ); + rtems_lwip_sysdefs_sockaddr_in_set_sin_addr( name, so_in.sin_addr.s_addr ); + #if LWIP_IPV6 + } else if ( lwipname->sa_family == AF_INET6 ) { + memcpy( &so_in6, lwipname, sizeof( so_in6 ) ); + rtems_lwip_sysdefs_sockaddr_set_len( name, + rtems_lwip_sysdefs_sockaddr_in6_size ); + rtems_lwip_sysdefs_sockaddr_set_family( name, + rtems_lwip_sysdefs_AF_INET6 ); + + rtems_lwip_sysdefs_sockaddr_in6_set_sin6_port( name, so_in6.sin6_port ); + memcpy( rtems_lwip_sysdefs_sockaddr_in6_get_sin6_addr_ptr( name ), + &so_in6.sin6_addr, + sizeof( so_in6.sin6_addr ) ); + rtems_lwip_sysdefs_sockaddr_in6_set_sin6_flowinfo( name, + so_in6.sin6_flowinfo ); + rtems_lwip_sysdefs_sockaddr_in6_set_sin6_scope_id( name, + so_in6.sin6_scope_id ); + #endif + } else { + lwip_close( lwipfd ); + errno = EINVAL; + + return -1; + } + + rtems_lwip_semaphore_obtain(); + ret = rtems_lwip_make_sysfd_from_lwipfd( lwipfd ); + + if ( ret < 0 ) { + lwip_close( lwipfd ); + } + + rtems_lwip_semaphore_release(); + + *namelen = rtems_lwip_sysdefs_sockaddr_get_len( name ); + + return ret; +} + +ssize_t sendto( + int s, + const void *buf, + size_t len, + int flags, + const struct sockaddr *name, + socklen_t namelen +) +{ + int ret = -1; + int lwipfd; + int family; + struct sockaddr *lwipname; + socklen_t lwipnamelen; + struct sockaddr_in so_in; + + #if LWIP_IPV6 + struct sockaddr_in6 so_in6; + #endif + + if ( name == NULL ) + return send( s, buf, len, flags ); + + family = rtems_lwip_sysdefs_sockaddr_get_family( name ); + + if ( ( family == rtems_lwip_sysdefs_AF_INET ) && + ( namelen >= rtems_lwip_sysdefs_sockaddr_in_size ) ) { + so_in.sin_len = sizeof( so_in ); + so_in.sin_family = AF_INET; + so_in.sin_port = rtems_lwip_sysdefs_sockaddr_in_get_sin_port( name ); + so_in.sin_addr.s_addr = + rtems_lwip_sysdefs_sockaddr_in_get_sin_addr( name ); + lwipname = (struct sockaddr *) &so_in; + lwipnamelen = so_in.sin_len; + #if LWIP_IPV6 + } else if ( ( family == rtems_lwip_sysdefs_AF_INET6 ) && + ( namelen >= rtems_lwip_sysdefs_sockaddr_in6_size ) ) { + so_in6.sin6_len = sizeof( so_in6 ); + so_in6.sin6_family = AF_INET6; + so_in6.sin6_port = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_port( name ); + memcpy( &so_in6.sin6_addr, + rtems_lwip_sysdefs_sockaddr_in6_get_sin6_addr_ptr_const( name ), + sizeof( so_in6.sin6_addr ) ); + so_in6.sin6_flowinfo = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_flowinfo( + name ); + so_in6.sin6_scope_id = rtems_lwip_sysdefs_sockaddr_in6_get_sin6_scope_id( + name ); + lwipname = (struct sockaddr *) &so_in6; + lwipnamelen = so_in6.sin6_len; + #endif + } else { + errno = EINVAL; + + return -1; + } + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) >= 0 ) { + rtems_lwip_semaphore_release(); + ret = lwip_sendto( lwipfd, buf, len, flags, lwipname, lwipnamelen ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +#if 0 + +/* + * All `transmit' operations end up calling this routine. + */ +ssize_t sendmsg( + int s, + const struct msghdr *mp, + int flags +) +{ + int ret = -1; + int error; + struct uio auio; + struct iovec *iov; + int lwipfd; + struct mbuf *to; + struct mbuf *control = NULL; + int i; + int len; + + rtems_lwip_semaphore_obtain(); + + if ( ( so = rtems_lwip_sysfd_to_lwipfd( s ) ) == NULL ) { + rtems_lwip_semaphore_release(); + + return -1; + } + + auio.uio_iov = mp->msg_iov; + auio.uio_iovcnt = mp->msg_iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_offset = 0; + auio.uio_resid = 0; + iov = mp->msg_iov; + + for ( i = 0; i < mp->msg_iovlen; i++, iov++ ) { + if ( ( auio.uio_resid += iov->iov_len ) < 0 ) { + errno = EINVAL; + rtems_lwip_semaphore_release(); + + return -1; + } + } + + if ( mp->msg_name ) { + error = sockargstombuf( &to, mp->msg_name, mp->msg_namelen, MT_SONAME ); + + if ( error ) { + errno = error; + rtems_lwip_semaphore_release(); + + return -1; + } + } else { + to = NULL; + } + + if ( mp->msg_control ) { + if ( mp->msg_controllen < sizeof( struct cmsghdr ) ) { + errno = EINVAL; + + if ( to ) + m_freem( to ); + + rtems_lwip_semaphore_release(); + + return -1; + } + + sockargstombuf( &control, mp->msg_control, mp->msg_controllen, + MT_CONTROL ); + } else { + control = NULL; + } + + len = auio.uio_resid; + error = sosend( so, to, &auio, (struct mbuf *) 0, control, flags ); + + if ( error ) { + if ( auio.uio_resid != len && ( error == EINTR || error == EWOULDBLOCK ) ) + error = 0; + } + + if ( error ) + errno = error; + else + ret = len - auio.uio_resid; + + if ( to ) + m_freem( to ); + + rtems_lwip_semaphore_release(); + + return ( ret ); +} + +/* + * All `receive' operations end up calling this routine. + */ +ssize_t recvmsg( + int s, + struct msghdr *mp, + int flags +) +{ + int ret = -1; + int error; + struct uio auio; + struct iovec *iov; + int lwipfd; + struct mbuf *from = NULL, *control = NULL; + int i; + int len; + + rtems_lwip_semaphore_obtain(); + + if ( ( so = rtems_lwip_sysfd_to_lwipfd( s ) ) == NULL ) { + rtems_lwip_semaphore_release(); + + return -1; + } + + auio.uio_iov = mp->msg_iov; + auio.uio_iovcnt = mp->msg_iovlen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_READ; + auio.uio_offset = 0; + auio.uio_resid = 0; + iov = mp->msg_iov; + + for ( i = 0; i < mp->msg_iovlen; i++, iov++ ) { + if ( ( auio.uio_resid += iov->iov_len ) < 0 ) { + errno = EINVAL; + rtems_lwip_semaphore_release(); + + return -1; + } + } + + len = auio.uio_resid; + mp->msg_flags = flags; + error = soreceive( so, &from, &auio, (struct mbuf **) NULL, + mp->msg_control ? &control : (struct mbuf **) NULL, + &mp->msg_flags ); + + if ( error ) { + if ( auio.uio_resid != len && ( error == EINTR || error == EWOULDBLOCK ) ) + error = 0; + } + + if ( error ) { + errno = error; + } else { + ret = len - auio.uio_resid; + + if ( mp->msg_name ) { + len = mp->msg_namelen; + + if ( ( len <= 0 ) || ( from == NULL ) ) { + len = 0; + } else { + if ( len > from->m_len ) + len = from->m_len; + + memcpy( mp->msg_name, mtod( from, caddr_t ), len ); + } + + mp->msg_namelen = len; + } + + if ( mp->msg_control ) { + struct mbuf *m; + void *ctlbuf; + + len = mp->msg_controllen; + m = control; + mp->msg_controllen = 0; + ctlbuf = mp->msg_control; + + while ( m && ( len > 0 ) ) { + unsigned int tocopy; + + if ( len >= m->m_len ) + tocopy = m->m_len; + else { + mp->msg_flags |= MSG_CTRUNC; + tocopy = len; + } + + memcpy( ctlbuf, mtod( m, caddr_t ), tocopy ); + ctlbuf += tocopy; + len -= tocopy; + m = m->m_next; + } + + mp->msg_controllen = ctlbuf - mp->msg_control; + } + } + + if ( from ) + m_freem( from ); + + if ( control ) + m_freem( control ); + + rtems_lwip_semaphore_release(); + + return ( ret ); +} + +#endif + +int setsockopt( + int s, + int level, + int name, + const void *val, + socklen_t len +) +{ + +#if 0 + int lwipfd; + struct mbuf *m = NULL; + int error; + + rtems_lwip_semaphore_obtain(); + + if ( ( so = rtems_lwip_sysfd_to_lwipfd( s ) ) == NULL ) { + rtems_lwip_semaphore_release(); + + return -1; + } + + if ( len > MLEN ) { + errno = EINVAL; + rtems_lwip_semaphore_release(); + + return -1; + } + + if ( val ) { + error = sockargstombuf( &m, val, len, MT_SOOPTS ); + + if ( error ) { + errno = error; + rtems_lwip_semaphore_release(); + + return -1; + } + } + + error = sosetopt( so, level, name, m ); + + if ( error ) { + errno = error; + rtems_lwip_semaphore_release(); + + return -1; + } + + rtems_lwip_semaphore_release(); +#endif + return 0; +} + +#if 0 + +int getsockopt( + int s, + int level, + int name, + void *aval, + socklen_t *avalsize +) +{ + int lwipfd; + struct mbuf *m = NULL, *m0; + char *val = aval; + int i, op, valsize; + int error; + + rtems_lwip_semaphore_obtain(); + + if ( ( so = rtems_lwip_sysfd_to_lwipfd( s ) ) == NULL ) { + rtems_lwip_semaphore_release(); + + return -1; + } + + if ( val ) + valsize = *avalsize; + else + valsize = 0; + + if ( ( ( error = + sogetopt( so, level, name, + &m ) ) == 0 ) && val && valsize && m ) { + op = 0; + + while ( m && op < valsize ) { + i = valsize - op; + + if ( i > m->m_len ) + i = m->m_len; + + memcpy( val, mtod( m, caddr_t ), i ); + op += i; + val += i; + m0 = m; + MFREE( m0, m ); + } + + *avalsize = op; + } + + if ( m != NULL ) + (void) m_free( m ); + + if ( error ) { + errno = error; + rtems_lwip_semaphore_release(); + + return -1; + } + + rtems_lwip_semaphore_release(); + + return 0; +} + +static int getpeersockname( + int s, + struct sockaddr *name, + socklen_t *namelen, + int pflag +) +{ + int lwipfd; + struct mbuf *m; + int len = *namelen; + int error; + + rtems_lwip_semaphore_obtain(); + + if ( ( so = rtems_lwip_sysfd_to_lwipfd( s ) ) == NULL ) { + rtems_lwip_semaphore_release(); + + return -1; + } + + m = m_getclr( M_WAIT, MT_SONAME ); + + if ( m == NULL ) { + errno = ENOBUFS; + rtems_lwip_semaphore_release(); + + return -1; + } + + if ( pflag ) + error = ( *so->so_proto->pr_usrreqs->pru_peeraddr )( so, m ); + else + error = ( *so->so_proto->pr_usrreqs->pru_sockaddr )( so, m ); + + if ( error ) { + m_freem( m ); + errno = error; + rtems_lwip_semaphore_release(); + + return -1; + } + + if ( len > m->m_len ) { + len = m->m_len; + *namelen = len; + } + + memcpy( name, mtod( m, caddr_t ), len ); + m_freem( m ); + rtems_lwip_semaphore_release(); + + return 0; +} + +#endif + +int getpeername( + int s, + struct sockaddr *name, + socklen_t *namelen +) +{ + int lwipfd; + int error; + + rtems_lwip_semaphore_obtain(); + + if ( ( lwipfd = rtems_lwip_sysfd_to_lwipfd( s ) ) < 0 ) { + rtems_lwip_semaphore_release(); + + return -1; + } + + error = lwip_getpeername(lwipfd, name, namelen); + + rtems_lwip_semaphore_release(); + + return error; +} + +#if 0 + +int getsockname( + int s, + struct sockaddr *name, + socklen_t *namelen +) +{ + return getpeersockname( s, name, namelen, 0 ); +} + +int sysctl( + const int *name, + u_int namelen, + void *oldp, + size_t *oldlenp, + const void *newp, + size_t newlen +) +{ + int error; + size_t j; + + rtems_lwip_semaphore_obtain(); + error = + userland_sysctl( 0, name, namelen, oldp, oldlenp, 1, newp, newlen, &j ); + rtems_lwip_semaphore_release(); + + if ( oldlenp ) + *oldlenp = j; + + if ( error ) { + errno = error; + + return -1; + } + + return 0; +} + +#endif + +/* + ************************************************************************ + * RTEMS I/O HANDLER ROUTINES * + ************************************************************************ + */ +static int rtems_lwip_close( rtems_libio_t *iop ) +{ + int lwipfd; + int ret; + + rtems_lwip_semaphore_obtain(); + lwipfd = rtems_lwip_iop_to_lwipfd( iop ); + + if ( lwipfd < 0 ) { + ret = -1; + } else { + rtems_lwip_semaphore_release(); + ret = lwip_close( lwipfd ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +static ssize_t rtems_lwip_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + int lwipfd; + int ret; + + rtems_lwip_semaphore_obtain(); + lwipfd = rtems_lwip_iop_to_lwipfd( iop ); + + if ( lwipfd < 0 ) { + ret = -1; + } else { + rtems_lwip_semaphore_release(); + ret = lwip_read( lwipfd, buffer, count ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +static ssize_t rtems_lwip_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + int lwipfd; + int ret; + + rtems_lwip_semaphore_obtain(); + lwipfd = rtems_lwip_iop_to_lwipfd( iop ); + + if ( lwipfd < 0 ) { + ret = -1; + } else { + rtems_lwip_semaphore_release(); + ret = lwip_write( lwipfd, buffer, count ); + rtems_lwip_semaphore_obtain(); + } + + rtems_lwip_semaphore_release(); + + return ret; +} + +int so_ioctl( + rtems_libio_t *iop, + int lwipfd, + uint32_t command, + void *buffer +) +{ +#if 0 + + switch ( command ) { + case FIONBIO: + + if ( *(int *) buffer ) { + iop->flags |= O_NONBLOCK; + so->so_state |= SS_NBIO; + } else { + iop->flags &= ~O_NONBLOCK; + so->so_state &= ~SS_NBIO; + } + + return 0; + + case FIONREAD: + *(int *) buffer = so->so_rcv.sb_cc; + + return 0; + } + + if ( IOCGROUP( command ) == 'i' ) + return ifioctl( so, command, buffer, NULL ); + + if ( IOCGROUP( command ) == 'r' ) + return rtioctl( command, buffer, NULL ); + + return ( *so->so_proto->pr_usrreqs->pru_control )( so, command, buffer, 0 ); +#endif + + return -1; +} + +static int rtems_lwip_ioctl( + rtems_libio_t *iop, + ioctl_command_t command, + void *buffer +) +{ +#if 0 + int lwipfd; + int error; + + rtems_lwip_semaphore_obtain(); + + if ( ( so = iop->data1 ) == NULL ) { + errno = EBADF; + rtems_lwip_semaphore_release(); + + return -1; + } + + error = so_ioctl( iop, so, command, buffer ); + rtems_lwip_semaphore_release(); + + if ( error ) { + errno = error; + + return -1; + } + + return 0; +#endif + + return -1; +} + +static int rtems_lwip_fcntl( + rtems_libio_t *iop, + int cmd +) +{ +#if 0 + int lwipfd; + + if ( cmd == F_SETFL ) { + rtems_lwip_semaphore_obtain(); + + if ( ( so = iop->data1 ) == NULL ) { + rtems_lwip_semaphore_release(); + + return EBADF; + } + + if ( rtems_libio_iop_is_no_delay( iop ) ) + so->so_state |= SS_NBIO; + else + so->so_state &= ~SS_NBIO; + + rtems_lwip_semaphore_release(); + } + + return 0; +#endif + + return -1; +} + +static int rtems_lwip_fstat( + const rtems_filesystem_location_info_t *loc, + struct stat *sp +) +{ + sp->st_mode = S_IFSOCK; + + return 0; +} + +static const rtems_filesystem_file_handlers_r rtems_lwip_socket_handlers = { + .open_h = rtems_filesystem_default_open, + .close_h = rtems_lwip_close, + .read_h = rtems_lwip_read, + .write_h = rtems_lwip_write, + .ioctl_h = rtems_lwip_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_lwip_fstat, + .ftruncate_h = rtems_filesystem_default_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_lwip_fcntl, + .kqfilter_h = rtems_filesystem_default_kqfilter, + .mmap_h = rtems_filesystem_default_mmap, + .poll_h = rtems_filesystem_default_poll, + .readv_h = rtems_filesystem_default_readv, + .writev_h = rtems_filesystem_default_writev +}; + +const char * +inet_ntop(int af, const void *src, char *dst, socklen_t size){ + return lwip_inet_ntop(af, src, dst, size); +} |