1279 lines
30 KiB
C
1279 lines
30 KiB
C
/**
|
|
* Copyright (c) 2018 Linaro Limited.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include "simplelink_log.h"
|
|
LOG_MODULE_DECLARE(LOG_MODULE_NAME);
|
|
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <zephyr.h>
|
|
/* Define sockaddr, etc, before simplelink.h */
|
|
#include <net/socket_offload.h>
|
|
|
|
#include <errno.h>
|
|
#include <ti/drivers/net/wifi/simplelink.h>
|
|
#include <ti/drivers/net/wifi/source/driver.h>
|
|
#include <ti/net/slnetutils.h>
|
|
#include <ti/net/slnetif.h>
|
|
#include "simplelink_support.h"
|
|
|
|
#include "sockets_internal.h"
|
|
#include "tls_internal.h"
|
|
|
|
#define FAILED (-1)
|
|
|
|
/* Increment by 1 to make sure we do not store the value of 0, which has
|
|
* a special meaning in the fdtable subsys.
|
|
*/
|
|
#define SD_TO_OBJ(sd) ((void *)(sd + 1))
|
|
#define OBJ_TO_SD(obj) (((int)obj) - 1)
|
|
|
|
static int simplelink_socket_accept(void *obj, struct sockaddr *addr,
|
|
socklen_t *addrlen);
|
|
|
|
/*
|
|
* Convert SL error codes into BSD errno values
|
|
* note that we are handling the same set of values as in TI SlNetSock
|
|
* minus the ones that are not defined in ti/drivers/net/wifi/errors.h.
|
|
*/
|
|
static int getErrno(_i32 error)
|
|
{
|
|
if (error >= 0) {
|
|
return error;
|
|
}
|
|
/* This switch case block is necessary for translating the NWP error
|
|
* code to BSD ones. The #ifdef in each case are made in order to
|
|
* reduce code footprint: These cases are compiled if and only if
|
|
* there's a discrepancy between the BSD error number and the error
|
|
* code returned by the NWP.
|
|
*/
|
|
switch (error) {
|
|
#if EBADF != SL_ERROR_BSD_EBADF
|
|
case SL_ERROR_BSD_EBADF:
|
|
error = EBADF;
|
|
break;
|
|
#endif
|
|
#if ENSOCK != SL_ERROR_BSD_ENSOCK
|
|
case SL_ERROR_BSD_ENSOCK:
|
|
/* The limit on total # of open sockets has been reached */
|
|
error = ENSOCK;
|
|
break;
|
|
#endif
|
|
#if EAGAIN != SL_ERROR_BSD_EAGAIN
|
|
case SL_ERROR_BSD_EAGAIN:
|
|
error = EAGAIN;
|
|
break;
|
|
#endif
|
|
#if ENOMEM != SL_ERROR_BSD_ENOMEM
|
|
case SL_ERROR_BSD_ENOMEM:
|
|
error = ENOMEM;
|
|
break;
|
|
#endif
|
|
#if EACCES != SL_ERROR_BSD_EACCES
|
|
case SL_ERROR_BSD_EACCES:
|
|
error = EACCES;
|
|
break;
|
|
#endif
|
|
#if EFAULT != SL_ERROR_BSD_EFAULT
|
|
case SL_ERROR_BSD_EFAULT:
|
|
error = EFAULT;
|
|
break;
|
|
#endif
|
|
#if EINVAL != SL_ERROR_BSD_EINVAL
|
|
case SL_ERROR_BSD_EINVAL:
|
|
error = EINVAL;
|
|
break;
|
|
#endif
|
|
#if EDESTADDRREQ != SL_ERROR_BSD_EDESTADDRREQ
|
|
case SL_ERROR_BSD_EDESTADDRREQ:
|
|
error = EDESTADDRREQ;
|
|
break;
|
|
#endif
|
|
#if EPROTOTYPE != SL_ERROR_BSD_EPROTOTYPE
|
|
case SL_ERROR_BSD_EPROTOTYPE:
|
|
error = EPROTOTYPE;
|
|
break;
|
|
#endif
|
|
#if ENOPROTOOPT != SL_ERROR_BSD_ENOPROTOOPT
|
|
case SL_ERROR_BSD_ENOPROTOOPT:
|
|
error = ENOPROTOOPT;
|
|
break;
|
|
#endif
|
|
#if EPROTONOSUPPORT != SL_ERROR_BSD_EPROTONOSUPPORT
|
|
case SL_ERROR_BSD_EPROTONOSUPPORT:
|
|
error = EPROTONOSUPPORT;
|
|
break;
|
|
#endif
|
|
#if EOPNOTSUPP != SL_ERROR_BSD_EOPNOTSUPP
|
|
case SL_ERROR_BSD_EOPNOTSUPP:
|
|
error = EOPNOTSUPP;
|
|
break;
|
|
#endif
|
|
#if EAFNOSUPPORT != SL_ERROR_BSD_EAFNOSUPPORT
|
|
case SL_ERROR_BSD_EAFNOSUPPORT:
|
|
error = EAFNOSUPPORT;
|
|
break;
|
|
#endif
|
|
#if EADDRINUSE != SL_ERROR_BSD_EADDRINUSE
|
|
case SL_ERROR_BSD_EADDRINUSE:
|
|
error = EADDRINUSE;
|
|
break;
|
|
#endif
|
|
#if EADDRNOTAVAIL != SL_ERROR_BSD_EADDRNOTAVAIL
|
|
case SL_ERROR_BSD_EADDRNOTAVAIL:
|
|
error = EADDRNOTAVAIL;
|
|
break;
|
|
#endif
|
|
#if ENETUNREACH != SL_ERROR_BSD_ENETUNREACH
|
|
case SL_ERROR_BSD_ENETUNREACH:
|
|
error = ENETUNREACH;
|
|
break;
|
|
#endif
|
|
#if ENOBUFS != SL_ERROR_BSD_ENOBUFS
|
|
case SL_ERROR_BSD_ENOBUFS:
|
|
error = ENOBUFS;
|
|
break;
|
|
#endif
|
|
#if EISCONN != SL_ERROR_BSD_EISCONN
|
|
case SL_ERROR_BSD_EISCONN:
|
|
error = EISCONN;
|
|
break;
|
|
#endif
|
|
#if ENOTCONN != SL_ERROR_BSD_ENOTCONN
|
|
case SL_ERROR_BSD_ENOTCONN:
|
|
error = ENOTCONN;
|
|
break;
|
|
#endif
|
|
#if ETIMEDOUT != SL_ERROR_BSD_ETIMEDOUT
|
|
case SL_ERROR_BSD_ETIMEDOUT:
|
|
error = ETIMEDOUT;
|
|
break;
|
|
#endif
|
|
#if ECONNREFUSED != SL_ERROR_BSD_ECONNREFUSED
|
|
case SL_ERROR_BSD_ECONNREFUSED:
|
|
error = ECONNREFUSED;
|
|
break;
|
|
#endif
|
|
/* The cases below are proprietary driver errors, which can
|
|
* be returned by the SimpleLink Driver, in various cases of failure.
|
|
* Each is mapped to the corresponding BSD error.
|
|
*/
|
|
case SL_POOL_IS_EMPTY:
|
|
case SL_RET_CODE_NO_FREE_ASYNC_BUFFERS_ERROR:
|
|
case SL_RET_CODE_MALLOC_ERROR:
|
|
error = ENOMEM;
|
|
break;
|
|
case SL_RET_CODE_INVALID_INPUT:
|
|
case SL_EZEROLEN:
|
|
case SL_ESMALLBUF:
|
|
case SL_INVALPARAM:
|
|
error = EINVAL;
|
|
break;
|
|
default:
|
|
/* Do nothing ..
|
|
* If no case is true, that means that the BSD error
|
|
* code and the code returned by the NWP are either identical,
|
|
* or no proprietary error has occurred.
|
|
*/
|
|
break;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
static int simplelink_socket(int family, int type, int proto)
|
|
{
|
|
uint8_t sec_method = SL_SO_SEC_METHOD_SSLv3_TLSV1_2;
|
|
int sd;
|
|
int retval = 0;
|
|
int sl_proto = proto;
|
|
|
|
/* Map Zephyr socket.h family to SimpleLink's: */
|
|
switch (family) {
|
|
case AF_INET:
|
|
family = SL_AF_INET;
|
|
break;
|
|
case AF_INET6:
|
|
family = SL_AF_INET6;
|
|
break;
|
|
default:
|
|
LOG_ERR("unsupported family: %d", family);
|
|
retval = slcb_SetErrno(EAFNOSUPPORT);
|
|
goto exit;
|
|
}
|
|
|
|
/* Map Zephyr socket.h type to SimpleLink's: */
|
|
switch (type) {
|
|
case SOCK_STREAM:
|
|
type = SL_SOCK_STREAM;
|
|
break;
|
|
case SOCK_DGRAM:
|
|
type = SL_SOCK_DGRAM;
|
|
break;
|
|
case SOCK_RAW:
|
|
type = SL_SOCK_RAW;
|
|
break;
|
|
default:
|
|
LOG_ERR("unrecognized type: %d", type);
|
|
retval = slcb_SetErrno(ESOCKTNOSUPPORT);
|
|
goto exit;
|
|
}
|
|
|
|
/* Map Zephyr protocols to TI's values: */
|
|
if (proto >= IPPROTO_TLS_1_0 && proto <= IPPROTO_TLS_1_2) {
|
|
sl_proto = SL_SEC_SOCKET;
|
|
} else if (proto >= IPPROTO_DTLS_1_0 && proto <= IPPROTO_DTLS_1_2) {
|
|
/* SimpleLink doesn't handle DTLS yet! */
|
|
retval = slcb_SetErrno(EPROTONOSUPPORT);
|
|
goto exit;
|
|
} else {
|
|
switch (proto) {
|
|
case IPPROTO_TCP:
|
|
sl_proto = SL_IPPROTO_TCP;
|
|
break;
|
|
case IPPROTO_UDP:
|
|
sl_proto = SL_IPPROTO_UDP;
|
|
break;
|
|
default:
|
|
LOG_ERR("unrecognized proto: %d", sl_proto);
|
|
retval = slcb_SetErrno(EPROTONOSUPPORT);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
sd = sl_Socket(family, type, sl_proto);
|
|
if (sd >= 0) {
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS)
|
|
&& sl_proto == SL_SEC_SOCKET) {
|
|
/* Now, set specific TLS version via setsockopt(): */
|
|
sec_method = (proto - IPPROTO_TLS_1_0) +
|
|
SL_SO_SEC_METHOD_TLSV1;
|
|
retval = sl_SetSockOpt(sd, SL_SOL_SOCKET,
|
|
SL_SO_SECMETHOD,
|
|
&sec_method, sizeof(sec_method));
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(EPROTONOSUPPORT);
|
|
(void)sl_Close(sd);
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
retval = sd;
|
|
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
exit:
|
|
return retval;
|
|
}
|
|
|
|
static int simplelink_close(void *obj)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
int retval;
|
|
|
|
retval = sl_Close(sd);
|
|
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static SlSockAddr_t *translate_z_to_sl_addrlen(socklen_t addrlen,
|
|
SlSockAddrIn_t *sl_addr_in,
|
|
SlSockAddrIn6_t *sl_addr_in6,
|
|
SlSocklen_t *sl_addrlen)
|
|
{
|
|
SlSockAddr_t *sl_addr = NULL;
|
|
|
|
if (addrlen == sizeof(struct sockaddr_in)) {
|
|
*sl_addrlen = sizeof(SlSockAddrIn_t);
|
|
sl_addr = (SlSockAddr_t *)sl_addr_in;
|
|
} else if (addrlen == sizeof(struct sockaddr_in6)) {
|
|
*sl_addrlen = sizeof(SlSockAddrIn6_t);
|
|
sl_addr = (SlSockAddr_t *)sl_addr_in6;
|
|
}
|
|
|
|
return sl_addr;
|
|
}
|
|
|
|
static SlSockAddr_t *translate_z_to_sl_addrs(const struct sockaddr *addr,
|
|
socklen_t addrlen,
|
|
SlSockAddrIn_t *sl_addr_in,
|
|
SlSockAddrIn6_t *sl_addr_in6,
|
|
SlSocklen_t *sl_addrlen)
|
|
{
|
|
SlSockAddr_t *sl_addr = NULL;
|
|
|
|
if (addrlen == sizeof(struct sockaddr_in)) {
|
|
struct sockaddr_in *z_sockaddr_in = (struct sockaddr_in *)addr;
|
|
|
|
*sl_addrlen = sizeof(SlSockAddrIn_t);
|
|
sl_addr_in->sin_family = SL_AF_INET;
|
|
sl_addr_in->sin_port = z_sockaddr_in->sin_port;
|
|
sl_addr_in->sin_addr.s_addr =
|
|
z_sockaddr_in->sin_addr.s_addr;
|
|
|
|
sl_addr = (SlSockAddr_t *)sl_addr_in;
|
|
} else if (addrlen == sizeof(struct sockaddr_in6)) {
|
|
struct sockaddr_in6 *z_sockaddr_in6 =
|
|
(struct sockaddr_in6 *)addr;
|
|
|
|
*sl_addrlen = sizeof(SlSockAddrIn6_t);
|
|
sl_addr_in6->sin6_family = SL_AF_INET6;
|
|
sl_addr_in6->sin6_port = z_sockaddr_in6->sin6_port;
|
|
memcpy(sl_addr_in6->sin6_addr._S6_un._S6_u32,
|
|
z_sockaddr_in6->sin6_addr.s6_addr,
|
|
sizeof(sl_addr_in6->sin6_addr._S6_un._S6_u32));
|
|
|
|
sl_addr = (SlSockAddr_t *)sl_addr_in6;
|
|
}
|
|
|
|
return sl_addr;
|
|
}
|
|
|
|
static void translate_sl_to_z_addr(SlSockAddr_t *sl_addr,
|
|
SlSocklen_t sl_addrlen,
|
|
struct sockaddr *addr,
|
|
socklen_t *addrlen)
|
|
{
|
|
SlSockAddrIn_t *sl_addr_in;
|
|
SlSockAddrIn6_t *sl_addr_in6;
|
|
|
|
if (sl_addr->sa_family == SL_AF_INET) {
|
|
if (sl_addrlen == (SlSocklen_t)sizeof(SlSockAddrIn_t)) {
|
|
struct sockaddr_in *z_sockaddr_in =
|
|
(struct sockaddr_in *)addr;
|
|
|
|
sl_addr_in = (SlSockAddrIn_t *)sl_addr;
|
|
z_sockaddr_in->sin_family = AF_INET;
|
|
z_sockaddr_in->sin_port = sl_addr_in->sin_port;
|
|
z_sockaddr_in->sin_addr.s_addr =
|
|
sl_addr_in->sin_addr.s_addr;
|
|
*addrlen = sizeof(struct sockaddr_in);
|
|
} else {
|
|
*addrlen = sl_addrlen;
|
|
}
|
|
} else if (sl_addr->sa_family == SL_AF_INET6) {
|
|
if (sl_addrlen == sizeof(SlSockAddrIn6_t)) {
|
|
struct sockaddr_in6 *z_sockaddr_in6 =
|
|
(struct sockaddr_in6 *)addr;
|
|
sl_addr_in6 = (SlSockAddrIn6_t *)sl_addr;
|
|
|
|
z_sockaddr_in6->sin6_family = AF_INET6;
|
|
z_sockaddr_in6->sin6_port = sl_addr_in6->sin6_port;
|
|
z_sockaddr_in6->sin6_scope_id =
|
|
(uint8_t)sl_addr_in6->sin6_scope_id;
|
|
memcpy(z_sockaddr_in6->sin6_addr.s6_addr,
|
|
sl_addr_in6->sin6_addr._S6_un._S6_u32,
|
|
sizeof(z_sockaddr_in6->sin6_addr.s6_addr));
|
|
*addrlen = sizeof(struct sockaddr_in6);
|
|
} else {
|
|
*addrlen = sl_addrlen;
|
|
}
|
|
}
|
|
}
|
|
|
|
static int simplelink_accept(void *obj, struct sockaddr *addr,
|
|
socklen_t *addrlen)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
int retval;
|
|
SlSockAddr_t *sl_addr;
|
|
SlSockAddrIn_t sl_addr_in;
|
|
SlSockAddrIn6_t sl_addr_in6;
|
|
SlSocklen_t sl_addrlen;
|
|
|
|
if ((addrlen == NULL) || (addr == NULL)) {
|
|
retval = SL_RET_CODE_INVALID_INPUT;
|
|
goto exit;
|
|
}
|
|
|
|
/* Translate between Zephyr's and SimpleLink's sockaddr's: */
|
|
sl_addr = translate_z_to_sl_addrlen(*addrlen, &sl_addr_in, &sl_addr_in6,
|
|
&sl_addrlen);
|
|
if (sl_addr == NULL) {
|
|
retval = SL_RET_CODE_INVALID_INPUT;
|
|
goto exit;
|
|
}
|
|
|
|
retval = sl_Accept(sd, sl_addr, &sl_addrlen);
|
|
if (retval < 0) {
|
|
goto exit;
|
|
}
|
|
|
|
/* Translate returned sl_addr into *addr and set *addrlen: */
|
|
translate_sl_to_z_addr(sl_addr, sl_addrlen, addr, addrlen);
|
|
|
|
exit:
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int simplelink_bind(void *obj, const struct sockaddr *addr,
|
|
socklen_t addrlen)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
int retval;
|
|
SlSockAddr_t *sl_addr;
|
|
SlSockAddrIn_t sl_addr_in;
|
|
SlSockAddrIn6_t sl_addr_in6;
|
|
SlSocklen_t sl_addrlen;
|
|
|
|
if (addr == NULL) {
|
|
retval = slcb_SetErrno(EISDIR);
|
|
return retval;
|
|
}
|
|
|
|
/* Translate to sl_Bind() parameters: */
|
|
sl_addr = translate_z_to_sl_addrs(addr, addrlen, &sl_addr_in,
|
|
&sl_addr_in6, &sl_addrlen);
|
|
|
|
if (sl_addr == NULL) {
|
|
retval = SL_RET_CODE_INVALID_INPUT;
|
|
goto exit;
|
|
}
|
|
|
|
retval = sl_Bind(sd, sl_addr, sl_addrlen);
|
|
|
|
exit:
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int simplelink_listen(void *obj, int backlog)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
int retval;
|
|
|
|
retval = (int)sl_Listen(sd, backlog);
|
|
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int simplelink_connect(void *obj, const struct sockaddr *addr,
|
|
socklen_t addrlen)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
int retval;
|
|
SlSockAddr_t *sl_addr;
|
|
SlSockAddrIn_t sl_addr_in;
|
|
SlSockAddrIn6_t sl_addr_in6;
|
|
SlSocklen_t sl_addrlen;
|
|
|
|
__ASSERT_NO_MSG(addr);
|
|
|
|
/* Translate to sl_Connect() parameters: */
|
|
sl_addr = translate_z_to_sl_addrs(addr, addrlen, &sl_addr_in,
|
|
&sl_addr_in6, &sl_addrlen);
|
|
|
|
if (sl_addr == NULL) {
|
|
retval = SL_RET_CODE_INVALID_INPUT;
|
|
goto exit;
|
|
}
|
|
|
|
retval = sl_Connect(sd, sl_addr, sl_addrlen);
|
|
|
|
/* TBD: Until we have a good way to get correct date from Zephyr,
|
|
* log a date validation error as a warning, but continue connection:
|
|
*/
|
|
if (retval == SL_ERROR_BSD_ESECDATEERROR) {
|
|
LOG_WRN("Failed certificate date validation: %d", retval);
|
|
retval = 0;
|
|
}
|
|
|
|
/* Warn users when root CA is not in the certificate catalog.
|
|
* For enhanced security, users should update the catalog with the
|
|
* certificates for sites the device is expected to connect to. Note
|
|
* the connection is established successfully even when the root CA
|
|
* is not part of the catalog.
|
|
*/
|
|
if (retval == SL_ERROR_BSD_ESECUNKNOWNROOTCA) {
|
|
LOG_WRN("Unknown root CA used. For proper security, please "
|
|
"use a root CA that is part of the certificate "
|
|
"catalog in production systems.");
|
|
retval = 0;
|
|
}
|
|
|
|
exit:
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
#define ONE_THOUSAND 1000
|
|
|
|
static const struct socket_op_vtable simplelink_socket_fd_op_vtable;
|
|
|
|
static int simplelink_poll(struct zsock_pollfd *fds, int nfds, int msecs)
|
|
{
|
|
int max_sd = 0;
|
|
struct SlTimeval_t tv, *ptv;
|
|
SlFdSet_t rfds; /* Set of read file descriptors */
|
|
SlFdSet_t wfds; /* Set of write file descriptors */
|
|
int i, retval, sd;
|
|
void *obj;
|
|
|
|
if (nfds > SL_FD_SETSIZE) {
|
|
retval = slcb_SetErrno(EINVAL);
|
|
goto exit;
|
|
}
|
|
|
|
/* Convert time to SlTimeval struct values: */
|
|
if (msecs == SYS_FOREVER_MS) {
|
|
ptv = NULL;
|
|
} else {
|
|
tv.tv_sec = msecs / ONE_THOUSAND;
|
|
tv.tv_usec = (msecs % ONE_THOUSAND) * ONE_THOUSAND;
|
|
ptv = &tv;
|
|
}
|
|
|
|
/* Setup read and write fds for select, based on pollfd fields: */
|
|
SL_SOCKET_FD_ZERO(&rfds);
|
|
SL_SOCKET_FD_ZERO(&wfds);
|
|
|
|
for (i = 0; i < nfds; i++) {
|
|
fds[i].revents = 0;
|
|
if (fds[i].fd < 0) {
|
|
continue;
|
|
} else {
|
|
obj = z_get_fd_obj(fds[i].fd,
|
|
(const struct fd_op_vtable *)
|
|
&simplelink_socket_fd_op_vtable,
|
|
ENOTSUP);
|
|
if (obj != NULL) {
|
|
/* Offloaded socket found. */
|
|
sd = OBJ_TO_SD(obj);
|
|
} else {
|
|
/* Non-offloaded socket, return an error. */
|
|
retval = slcb_SetErrno(EINVAL);
|
|
goto exit;
|
|
}
|
|
}
|
|
if (fds[i].events & ZSOCK_POLLIN) {
|
|
SL_SOCKET_FD_SET(sd, &rfds);
|
|
}
|
|
if (fds[i].events & ZSOCK_POLLOUT) {
|
|
SL_SOCKET_FD_SET(sd, &wfds);
|
|
}
|
|
if (sd > max_sd) {
|
|
max_sd = sd;
|
|
}
|
|
}
|
|
|
|
/* Wait for requested read and write fds to be ready: */
|
|
retval = sl_Select(max_sd + 1, &rfds, &wfds, NULL, ptv);
|
|
if (retval > 0) {
|
|
for (i = 0; i < nfds; i++) {
|
|
if (fds[i].fd >= 0) {
|
|
obj = z_get_fd_obj(
|
|
fds[i].fd,
|
|
(const struct fd_op_vtable *)
|
|
&simplelink_socket_fd_op_vtable,
|
|
ENOTSUP);
|
|
sd = OBJ_TO_SD(obj);
|
|
if (SL_SOCKET_FD_ISSET(sd, &rfds)) {
|
|
fds[i].revents |= ZSOCK_POLLIN;
|
|
}
|
|
if (SL_SOCKET_FD_ISSET(sd, &wfds)) {
|
|
fds[i].revents |= ZSOCK_POLLOUT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
exit:
|
|
return retval;
|
|
}
|
|
|
|
#ifdef CONFIG_NET_SOCKETS_SOCKOPT_TLS
|
|
|
|
/* Iterate through the list of Zephyr's credential types, and
|
|
* map to SimpleLink values, then set stored filenames
|
|
* via SimpleLink's sl_SetSockOpt()
|
|
*/
|
|
static int map_credentials(int sd, const void *optval, socklen_t optlen)
|
|
{
|
|
sec_tag_t *sec_tags = (sec_tag_t *)optval;
|
|
int retval = 0;
|
|
int sec_tags_len;
|
|
sec_tag_t tag;
|
|
int opt;
|
|
int i;
|
|
struct tls_credential *cert;
|
|
|
|
if ((optlen % sizeof(sec_tag_t)) != 0 || (optlen == 0)) {
|
|
retval = EINVAL;
|
|
goto exit;
|
|
} else {
|
|
sec_tags_len = optlen / sizeof(sec_tag_t);
|
|
}
|
|
|
|
/* For each tag, retrieve the credentials value and type: */
|
|
for (i = 0; i < sec_tags_len; i++) {
|
|
tag = sec_tags[i];
|
|
cert = credential_next_get(tag, NULL);
|
|
while (cert != NULL) {
|
|
/* Map Zephyr cert types to Simplelink cert options: */
|
|
switch (cert->type) {
|
|
case TLS_CREDENTIAL_CA_CERTIFICATE:
|
|
opt = SL_SO_SECURE_FILES_CA_FILE_NAME;
|
|
break;
|
|
case TLS_CREDENTIAL_SERVER_CERTIFICATE:
|
|
opt = SL_SO_SECURE_FILES_CERTIFICATE_FILE_NAME;
|
|
break;
|
|
case TLS_CREDENTIAL_PRIVATE_KEY:
|
|
opt = SL_SO_SECURE_FILES_PRIVATE_KEY_FILE_NAME;
|
|
break;
|
|
case TLS_CREDENTIAL_NONE:
|
|
case TLS_CREDENTIAL_PSK:
|
|
case TLS_CREDENTIAL_PSK_ID:
|
|
default:
|
|
/* Not handled by SimpleLink: */
|
|
retval = EINVAL;
|
|
goto exit;
|
|
}
|
|
retval = sl_SetSockOpt(sd, SL_SOL_SOCKET, opt,
|
|
cert->buf,
|
|
(SlSocklen_t)cert->len);
|
|
if (retval < 0) {
|
|
retval = getErrno(retval);
|
|
break;
|
|
}
|
|
cert = credential_next_get(tag, cert);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return retval;
|
|
}
|
|
#else
|
|
static int map_credentials(int sd, const void *optval, socklen_t optlen)
|
|
{
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_NET_SOCKETS_SOCKOPT_TLS */
|
|
|
|
/* Excerpted from SimpleLink's socket.h:
|
|
* "Unsupported: these are only placeholders to not break BSD code."
|
|
* Remove once Zephyr has POSIX socket options defined.
|
|
*/
|
|
#define SO_BROADCAST (200)
|
|
#define SO_SNDBUF (202)
|
|
|
|
/* Needed to keep line lengths < 80: */
|
|
#define _SEC_DOMAIN_VERIF SL_SO_SECURE_DOMAIN_NAME_VERIFICATION
|
|
|
|
static int simplelink_setsockopt(void *obj, int level, int optname,
|
|
const void *optval, socklen_t optlen)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
int retval;
|
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS) && level == SOL_TLS) {
|
|
/* Handle Zephyr's SOL_TLS secure socket options: */
|
|
switch (optname) {
|
|
case TLS_SEC_TAG_LIST:
|
|
/* Bind credential filenames to this socket: */
|
|
retval = map_credentials(sd, optval, optlen);
|
|
if (retval != 0) {
|
|
retval = slcb_SetErrno(retval);
|
|
goto exit;
|
|
}
|
|
break;
|
|
case TLS_HOSTNAME:
|
|
retval = sl_SetSockOpt(sd, SL_SOL_SOCKET,
|
|
_SEC_DOMAIN_VERIF,
|
|
(const char *)optval, optlen);
|
|
break;
|
|
case TLS_PEER_VERIFY:
|
|
if (optval) {
|
|
/*
|
|
* Not currently supported. Verification
|
|
* is automatically performed if a CA
|
|
* certificate is set. We are returning
|
|
* success here to allow
|
|
* mqtt_client_tls_connect()
|
|
* to proceed, given it requires
|
|
* verification and it is indeed
|
|
* performed when the cert is set.
|
|
*/
|
|
if (*(uint32_t *)optval != 2U) {
|
|
retval = slcb_SetErrno(ENOTSUP);
|
|
goto exit;
|
|
} else {
|
|
retval = 0;
|
|
}
|
|
} else {
|
|
retval = slcb_SetErrno(EINVAL);
|
|
goto exit;
|
|
}
|
|
break;
|
|
case TLS_CIPHERSUITE_LIST:
|
|
case TLS_DTLS_ROLE:
|
|
/* Not yet supported: */
|
|
retval = slcb_SetErrno(ENOTSUP);
|
|
goto exit;
|
|
default:
|
|
retval = slcb_SetErrno(EINVAL);
|
|
goto exit;
|
|
}
|
|
} else {
|
|
/* Can be SOL_SOCKET or TI specific: */
|
|
|
|
/* Note: this logic should match SimpleLink SDK's socket.c: */
|
|
switch (optname) {
|
|
case TCP_NODELAY:
|
|
if (optval) {
|
|
/* if user wishes to have TCP_NODELAY = FALSE,
|
|
* we return EINVAL and fail in the cases below.
|
|
*/
|
|
if (*(uint32_t *)optval) {
|
|
retval = 0;
|
|
goto exit;
|
|
}
|
|
}
|
|
/* These sock opts aren't supported by the cc32xx
|
|
* network stack, so we ignore them and set errno to
|
|
* EINVAL in order to not break "off-the-shelf" BSD
|
|
* code.
|
|
*/
|
|
case SO_BROADCAST:
|
|
case SO_REUSEADDR:
|
|
case SO_SNDBUF:
|
|
retval = slcb_SetErrno(EINVAL);
|
|
goto exit;
|
|
default:
|
|
break;
|
|
}
|
|
retval = sl_SetSockOpt(sd, SL_SOL_SOCKET, optname, optval,
|
|
(SlSocklen_t)optlen);
|
|
}
|
|
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
exit:
|
|
return retval;
|
|
}
|
|
|
|
static int simplelink_getsockopt(void *obj, int level, int optname,
|
|
void *optval, socklen_t *optlen)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
int retval;
|
|
|
|
if (IS_ENABLED(CONFIG_NET_SOCKETS_SOCKOPT_TLS) && level == SOL_TLS) {
|
|
/* Handle Zephyr's SOL_TLS secure socket options: */
|
|
switch (optname) {
|
|
case TLS_SEC_TAG_LIST:
|
|
case TLS_CIPHERSUITE_LIST:
|
|
case TLS_CIPHERSUITE_USED:
|
|
/* Not yet supported: */
|
|
retval = slcb_SetErrno(ENOTSUP);
|
|
goto exit;
|
|
default:
|
|
retval = slcb_SetErrno(EINVAL);
|
|
goto exit;
|
|
}
|
|
} else {
|
|
/* Can be SOL_SOCKET or TI specific: */
|
|
|
|
/* Note: this logic should match SimpleLink SDK's socket.c: */
|
|
switch (optname) {
|
|
/* TCP_NODELAY always set by the NWP, so return True */
|
|
case TCP_NODELAY:
|
|
if (optval) {
|
|
(*(_u32 *)optval) = TRUE;
|
|
retval = 0;
|
|
goto exit;
|
|
}
|
|
/* These sock opts aren't supported by the cc32xx
|
|
* network stack, so we silently ignore them and set
|
|
* errno to EINVAL in order to not break "off-the-shelf"
|
|
* BSD code.
|
|
*/
|
|
case SO_BROADCAST:
|
|
case SO_REUSEADDR:
|
|
case SO_SNDBUF:
|
|
retval = slcb_SetErrno(EINVAL);
|
|
goto exit;
|
|
default:
|
|
break;
|
|
}
|
|
retval = sl_GetSockOpt(sd, SL_SOL_SOCKET, optname, optval,
|
|
(SlSocklen_t *)optlen);
|
|
}
|
|
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
exit:
|
|
return retval;
|
|
}
|
|
|
|
/* SimpleLink does not support flags in recv.
|
|
* However, to enable more Zephyr apps to use this socket_offload, rather than
|
|
* failing with ENOTSUP, we can closely emulate the MSG_DONTWAIT feature using
|
|
* SimpleLink socket options.
|
|
*/
|
|
static int handle_recv_flags(int sd, int flags, bool set, int *nb_enabled)
|
|
{
|
|
ssize_t retval = 0;
|
|
SlSocklen_t optlen = sizeof(SlSockNonblocking_t);
|
|
SlSockNonblocking_t enableOption;
|
|
|
|
if (flags & ZSOCK_MSG_PEEK) {
|
|
retval = ENOTSUP;
|
|
} else if (flags & ZSOCK_MSG_DONTWAIT) {
|
|
if (set) {
|
|
/* Get previous state, to restore later: */
|
|
sl_GetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING,
|
|
(_u8 *)&enableOption, &optlen);
|
|
*nb_enabled = enableOption.NonBlockingEnabled;
|
|
|
|
/* Now, set to non_blocking if not already set: */
|
|
if (!*nb_enabled) {
|
|
enableOption.NonBlockingEnabled = 1;
|
|
sl_SetSockOpt(sd, SL_SOL_SOCKET,
|
|
SL_SO_NONBLOCKING,
|
|
(_u8 *)&enableOption,
|
|
sizeof(enableOption));
|
|
}
|
|
} else {
|
|
/* Restore socket to previous state: */
|
|
enableOption.NonBlockingEnabled = *nb_enabled;
|
|
sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING,
|
|
(_u8 *)&enableOption,
|
|
sizeof(enableOption));
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static ssize_t simplelink_recvfrom(void *obj, void *buf, size_t len, int flags,
|
|
struct sockaddr *from, socklen_t *fromlen)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
ssize_t retval;
|
|
SlSockAddr_t *sl_addr;
|
|
SlSockAddrIn_t sl_addr_in;
|
|
SlSockAddrIn6_t sl_addr_in6;
|
|
SlSocklen_t sl_addrlen;
|
|
int nb_enabled;
|
|
|
|
retval = handle_recv_flags(sd, flags, TRUE, &nb_enabled);
|
|
|
|
if (!retval) {
|
|
/* Translate to sl_RecvFrom() parameters: */
|
|
if (fromlen != NULL) {
|
|
sl_addr = translate_z_to_sl_addrlen(*fromlen,
|
|
&sl_addr_in,
|
|
&sl_addr_in6,
|
|
&sl_addrlen);
|
|
retval = (ssize_t)sl_RecvFrom(sd, buf, len, 0, sl_addr,
|
|
&sl_addrlen);
|
|
} else {
|
|
retval = (ssize_t)sl_Recv(sd, buf, len, 0);
|
|
}
|
|
|
|
handle_recv_flags(sd, flags, FALSE, &nb_enabled);
|
|
if (retval >= 0) {
|
|
if (fromlen != NULL) {
|
|
/*
|
|
* Translate sl_addr into *addr and set
|
|
* *addrlen
|
|
*/
|
|
translate_sl_to_z_addr(sl_addr, sl_addrlen,
|
|
from, fromlen);
|
|
}
|
|
} else {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
} else {
|
|
retval = slcb_SetErrno(retval);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static ssize_t simplelink_sendto(void *obj, const void *buf, size_t len,
|
|
int flags, const struct sockaddr *to,
|
|
socklen_t tolen)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
ssize_t retval;
|
|
SlSockAddr_t *sl_addr;
|
|
SlSockAddrIn_t sl_addr_in;
|
|
SlSockAddrIn6_t sl_addr_in6;
|
|
SlSocklen_t sl_addrlen;
|
|
|
|
if (to != NULL) {
|
|
/* Translate to sl_SendTo() parameters: */
|
|
sl_addr = translate_z_to_sl_addrs(to, tolen, &sl_addr_in,
|
|
&sl_addr_in6, &sl_addrlen);
|
|
|
|
if (sl_addr == NULL) {
|
|
retval = SL_RET_CODE_INVALID_INPUT;
|
|
goto exit;
|
|
}
|
|
|
|
retval = sl_SendTo(sd, buf, (uint16_t)len, flags,
|
|
sl_addr, sl_addrlen);
|
|
} else {
|
|
retval = (ssize_t)sl_Send(sd, buf, len, flags);
|
|
}
|
|
|
|
exit:
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static ssize_t simplelink_sendmsg(void *obj, const struct msghdr *msg,
|
|
int flags)
|
|
{
|
|
errno = -ENOTSUP;
|
|
return -1;
|
|
}
|
|
|
|
/* Adds address info entry to a list */
|
|
static int set_addr_info(const struct SlNetUtil_addrInfo_t *sl_ai,
|
|
struct zsock_addrinfo **res)
|
|
{
|
|
struct zsock_addrinfo *ai;
|
|
struct sockaddr *ai_addr;
|
|
int retval = 0;
|
|
|
|
ai = calloc(1, sizeof(struct zsock_addrinfo));
|
|
if (!ai) {
|
|
retval = DNS_EAI_MEMORY;
|
|
goto exit;
|
|
} else {
|
|
/* Now, alloc the embedded sockaddr struct: */
|
|
ai_addr = calloc(1, sizeof(struct sockaddr));
|
|
if (!ai_addr) {
|
|
retval = DNS_EAI_MEMORY;
|
|
free(ai);
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
/* Now, fill in the fields of res (addrinfo struct): */
|
|
ai->ai_family = (sl_ai->ai_family == SL_AF_INET6 ? AF_INET6 : AF_INET);
|
|
ai->ai_socktype = (sl_ai->ai_socktype == SLNETSOCK_SOCK_DGRAM ?
|
|
SOCK_DGRAM : SOCK_STREAM);
|
|
ai->ai_protocol = (sl_ai->ai_protocol == SLNETSOCK_PROTO_UDP ?
|
|
IPPROTO_UDP : IPPROTO_TCP);
|
|
|
|
/* Fill sockaddr struct fields based on family: */
|
|
if (ai->ai_family == AF_INET) {
|
|
SlNetSock_AddrIn_t *sl_addr =
|
|
(SlNetSock_AddrIn_t *)sl_ai->ai_addr;
|
|
|
|
net_sin(ai_addr)->sin_family = ai->ai_family;
|
|
net_sin(ai_addr)->sin_addr.s_addr = sl_addr->sin_addr.s_addr;
|
|
net_sin(ai_addr)->sin_port = sl_addr->sin_port;
|
|
ai->ai_addrlen = sizeof(struct sockaddr_in);
|
|
} else {
|
|
SlNetSock_AddrIn6_t *sl_addr =
|
|
(SlNetSock_AddrIn6_t *)sl_ai->ai_addr;
|
|
|
|
net_sin6(ai_addr)->sin6_family = ai->ai_family;
|
|
net_sin6(ai_addr)->sin6_addr.s6_addr32[0] =
|
|
sl_addr->sin6_addr._S6_un._S6_u32[0];
|
|
net_sin6(ai_addr)->sin6_addr.s6_addr32[1] =
|
|
sl_addr->sin6_addr._S6_un._S6_u32[1];
|
|
net_sin6(ai_addr)->sin6_addr.s6_addr32[2] =
|
|
sl_addr->sin6_addr._S6_un._S6_u32[2];
|
|
net_sin6(ai_addr)->sin6_addr.s6_addr32[3] =
|
|
sl_addr->sin6_addr._S6_un._S6_u32[3];
|
|
net_sin6(ai_addr)->sin6_port = sl_addr->sin6_port;
|
|
ai->ai_addrlen = sizeof(struct sockaddr_in6);
|
|
}
|
|
ai->ai_addr = ai_addr;
|
|
ai->ai_next = *res;
|
|
*res = ai;
|
|
|
|
exit:
|
|
return retval;
|
|
}
|
|
|
|
static int simplelink_getaddrinfo(const char *node, const char *service,
|
|
const struct zsock_addrinfo *hints,
|
|
struct zsock_addrinfo **res)
|
|
{
|
|
int32_t retval;
|
|
struct SlNetUtil_addrInfo_t sl_hints;
|
|
struct SlNetUtil_addrInfo_t *sl_res, *sl_ai;
|
|
|
|
/* Initialize sl_hints to the defaults */
|
|
memset(&sl_hints, 0, sizeof(sl_hints));
|
|
|
|
/* Check args: */
|
|
if (!res) {
|
|
retval = DNS_EAI_NONAME;
|
|
goto exit;
|
|
}
|
|
|
|
if (hints) {
|
|
/*
|
|
* SlNetUtil only supports AI_NUMERICHOST and AI_PASSIVE, so
|
|
* the rest are ignored.
|
|
*/
|
|
sl_hints.ai_flags |= ((hints->ai_flags & AI_PASSIVE) ?
|
|
SLNETUTIL_AI_PASSIVE : 0);
|
|
sl_hints.ai_flags |= ((hints->ai_flags & AI_NUMERICHOST) ?
|
|
SLNETUTIL_AI_NUMERICHOST : 0);
|
|
if (hints->ai_family == AF_UNSPEC) {
|
|
sl_hints.ai_family = SLNETSOCK_AF_UNSPEC;
|
|
} else {
|
|
sl_hints.ai_family = (hints->ai_family == AF_INET6 ?
|
|
SLNETSOCK_AF_INET6 : SLNETSOCK_AF_INET);
|
|
}
|
|
if (hints->ai_socktype == 0) {
|
|
sl_hints.ai_socktype = 0;
|
|
} else {
|
|
sl_hints.ai_socktype =
|
|
(hints->ai_socktype == SOCK_DGRAM ?
|
|
SLNETSOCK_SOCK_DGRAM : SLNETSOCK_SOCK_STREAM);
|
|
}
|
|
if (hints->ai_protocol == 0) {
|
|
sl_hints.ai_protocol = 0;
|
|
} else {
|
|
sl_hints.ai_protocol =
|
|
(hints->ai_protocol == IPPROTO_UDP ?
|
|
SLNETSOCK_PROTO_UDP : SLNETSOCK_PROTO_TCP);
|
|
}
|
|
|
|
}
|
|
|
|
/* Now, try to resolve host name: */
|
|
retval = SlNetUtil_getAddrInfo(SLNETIF_ID_1, node,
|
|
service, &sl_hints, &sl_res);
|
|
|
|
if (retval < 0) {
|
|
LOG_ERR("Could not resolve name: %s, retval: %d",
|
|
node, retval);
|
|
retval = DNS_EAI_NONAME;
|
|
goto exit;
|
|
}
|
|
|
|
sl_ai = sl_res;
|
|
*res = NULL;
|
|
while (sl_ai != NULL) {
|
|
retval = set_addr_info(sl_ai, res);
|
|
if (retval < 0) {
|
|
LOG_ERR("Unable to set address info, retval: %d",
|
|
retval);
|
|
goto exit;
|
|
}
|
|
sl_ai = sl_ai->ai_next;
|
|
}
|
|
SlNetUtil_freeAddrInfo(sl_res);
|
|
exit:
|
|
return retval;
|
|
}
|
|
|
|
static void simplelink_freeaddrinfo(struct zsock_addrinfo *res)
|
|
{
|
|
__ASSERT_NO_MSG(res);
|
|
|
|
free(res->ai_addr);
|
|
free(res);
|
|
}
|
|
|
|
static int simplelink_fcntl(int sd, int cmd, va_list args)
|
|
{
|
|
int retval = 0;
|
|
SlSockNonblocking_t enableOption;
|
|
SlSocklen_t optlen = sizeof(SlSockNonblocking_t);
|
|
|
|
switch (cmd) {
|
|
case F_GETFL:
|
|
retval = sl_GetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING,
|
|
(_u8 *)&enableOption, &optlen);
|
|
if (retval == 0) {
|
|
if (enableOption.NonBlockingEnabled) {
|
|
retval |= O_NONBLOCK;
|
|
}
|
|
}
|
|
break;
|
|
case F_SETFL:
|
|
if ((va_arg(args, int) & O_NONBLOCK) != 0) {
|
|
enableOption.NonBlockingEnabled = 1;
|
|
} else {
|
|
enableOption.NonBlockingEnabled = 0;
|
|
}
|
|
retval = sl_SetSockOpt(sd, SL_SOL_SOCKET, SL_SO_NONBLOCKING,
|
|
&enableOption, optlen);
|
|
break;
|
|
default:
|
|
LOG_ERR("Invalid command: %d", cmd);
|
|
retval = slcb_SetErrno(EINVAL);
|
|
goto exit;
|
|
}
|
|
|
|
if (retval < 0) {
|
|
retval = slcb_SetErrno(getErrno(retval));
|
|
}
|
|
|
|
exit:
|
|
return retval;
|
|
}
|
|
|
|
static int simplelink_ioctl(void *obj, unsigned int request, va_list args)
|
|
{
|
|
int sd = OBJ_TO_SD(obj);
|
|
|
|
switch (request) {
|
|
case ZFD_IOCTL_POLL_PREPARE:
|
|
return -EXDEV;
|
|
|
|
case ZFD_IOCTL_POLL_UPDATE:
|
|
return -EOPNOTSUPP;
|
|
|
|
case ZFD_IOCTL_POLL_OFFLOAD: {
|
|
struct zsock_pollfd *fds;
|
|
int nfds;
|
|
int timeout;
|
|
|
|
fds = va_arg(args, struct zsock_pollfd *);
|
|
nfds = va_arg(args, int);
|
|
timeout = va_arg(args, int);
|
|
|
|
return simplelink_poll(fds, nfds, timeout);
|
|
}
|
|
|
|
/* Otherwise, just forward to offloaded fcntl()
|
|
* In Zephyr, fcntl() is just an alias of ioctl().
|
|
*/
|
|
default:
|
|
return simplelink_fcntl(sd, request, args);
|
|
}
|
|
}
|
|
|
|
static ssize_t simplelink_read(void *obj, void *buffer, size_t count)
|
|
{
|
|
return simplelink_recvfrom(obj, buffer, count, 0, NULL, 0);
|
|
}
|
|
|
|
static ssize_t simplelink_write(void *obj, const void *buffer,
|
|
size_t count)
|
|
{
|
|
return simplelink_sendto(obj, buffer, count, 0, NULL, 0);
|
|
}
|
|
|
|
static const struct socket_op_vtable simplelink_socket_fd_op_vtable = {
|
|
.fd_vtable = {
|
|
.read = simplelink_read,
|
|
.write = simplelink_write,
|
|
.close = simplelink_close,
|
|
.ioctl = simplelink_ioctl,
|
|
},
|
|
.bind = simplelink_bind,
|
|
.connect = simplelink_connect,
|
|
.listen = simplelink_listen,
|
|
.accept = simplelink_socket_accept,
|
|
.sendto = simplelink_sendto,
|
|
.sendmsg = simplelink_sendmsg,
|
|
.recvfrom = simplelink_recvfrom,
|
|
.getsockopt = simplelink_getsockopt,
|
|
.setsockopt = simplelink_setsockopt,
|
|
};
|
|
|
|
static bool simplelink_is_supported(int family, int type, int proto)
|
|
{
|
|
/* TODO offloading always enabled for now. */
|
|
return true;
|
|
}
|
|
|
|
static int simplelink_socket_create(int family, int type, int proto)
|
|
{
|
|
int fd = z_reserve_fd();
|
|
int sock;
|
|
|
|
if (fd < 0) {
|
|
return -1;
|
|
}
|
|
|
|
sock = simplelink_socket(family, type, proto);
|
|
if (sock < 0) {
|
|
z_free_fd(fd);
|
|
return -1;
|
|
}
|
|
|
|
z_finalize_fd(fd, SD_TO_OBJ(sock),
|
|
(const struct fd_op_vtable *)
|
|
&simplelink_socket_fd_op_vtable);
|
|
|
|
return fd;
|
|
}
|
|
|
|
static int simplelink_socket_accept(void *obj, struct sockaddr *addr,
|
|
socklen_t *addrlen)
|
|
{
|
|
int fd = z_reserve_fd();
|
|
int sock;
|
|
|
|
if (fd < 0) {
|
|
return -1;
|
|
}
|
|
|
|
sock = simplelink_accept(obj, addr, addrlen);
|
|
if (sock < 0) {
|
|
z_free_fd(fd);
|
|
return -1;
|
|
}
|
|
|
|
z_finalize_fd(fd, SD_TO_OBJ(sock),
|
|
(const struct fd_op_vtable *)
|
|
&simplelink_socket_fd_op_vtable);
|
|
|
|
return fd;
|
|
}
|
|
|
|
#ifdef CONFIG_NET_SOCKETS_OFFLOAD
|
|
NET_SOCKET_REGISTER(simplelink, NET_SOCKET_DEFAULT_PRIO, AF_UNSPEC,
|
|
simplelink_is_supported, simplelink_socket_create);
|
|
#endif
|
|
|
|
void simplelink_sockets_init(void)
|
|
{
|
|
}
|
|
|
|
const struct socket_dns_offload simplelink_dns_ops = {
|
|
.getaddrinfo = simplelink_getaddrinfo,
|
|
.freeaddrinfo = simplelink_freeaddrinfo,
|
|
};
|