/****************************************************************************
 * drivers/usrsock/usrsock_rpmsg_server.c
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>

#include <debug.h>
#include <errno.h>
#include <inttypes.h>
#include <poll.h>
#include <string.h>

#include <sys/ioctl.h>

#include <nuttx/kmalloc.h>
#include <nuttx/mutex.h>
#include <nuttx/net/dns.h>
#include <nuttx/net/net.h>
#include <nuttx/queue.h>
#include <nuttx/rptun/openamp.h>
#include <nuttx/usrsock/usrsock_rpmsg.h>
#ifdef CONFIG_NETDEV_WIRELESS_IOCTL
#include <nuttx/wireless/wireless.h>
#endif

/****************************************************************************
 * Private Types
 ****************************************************************************/

struct usrsock_rpmsg_s
{
  rmutex_t                  mutex;
  struct socket             socks[CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS];
  FAR struct rpmsg_endpoint *epts[CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS];
  struct pollfd             pfds[CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS];
};

/* Saving rpmsg requests to keep message order. */

struct usrsock_rpmsg_req_s
{
  sq_entry_t flink;
  FAR void  *data;
  size_t     len;
  uint32_t   src;
};

struct usrsock_rpmsg_ept_s
{
  struct rpmsg_endpoint ept;

  /* For sendto/recvfrom */

  struct iovec          iov[CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC];
  ssize_t               remain;

  /* For keeping msg order, normally nIOVec is the max request we can get */

  bool                       inuse;
  sq_queue_t                 req_free;
  sq_queue_t                 req_pending;
  struct usrsock_rpmsg_req_s reqs[CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC];
};

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

static bool usrsock_rpmsg_available(FAR struct socket *psock, int cmd);

static int usrsock_rpmsg_send_ack(FAR struct rpmsg_endpoint *ept,
                                  uint16_t events,
                                  uint32_t xid, int32_t result);
static int usrsock_rpmsg_send_data_ack(FAR struct rpmsg_endpoint *ept,
                              FAR struct usrsock_message_datareq_ack_s *ack,
                              uint16_t events,
                              uint32_t xid, int32_t result,
                              uint16_t valuelen,
                              uint16_t valuelen_nontrunc,
                              int32_t datalen);
static int usrsock_rpmsg_send_event(FAR struct rpmsg_endpoint *ept,
                                    int16_t usockid, uint16_t events);

static int usrsock_rpmsg_socket_handler(FAR struct rpmsg_endpoint *ept,
                                        FAR void *data, size_t len,
                                        uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_close_handler(FAR struct rpmsg_endpoint *ept,
                                       FAR void *data, size_t len,
                                       uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_connect_handler(FAR struct rpmsg_endpoint *ept,
                                         FAR void *data, size_t len,
                                         uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_sendto_handler(FAR struct rpmsg_endpoint *ept,
                                        FAR void *data, size_t len,
                                        uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_recvfrom_handler(FAR struct rpmsg_endpoint *ept,
                                          FAR void *data, size_t len,
                                          uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_setsockopt_handler(FAR struct rpmsg_endpoint *ept,
                                            FAR void *data, size_t len,
                                            uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_getsockopt_handler(FAR struct rpmsg_endpoint *ept,
                                            FAR void *data, size_t len,
                                            uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_getsockname_handler(FAR struct rpmsg_endpoint *ept,
                                             FAR void *data, size_t len,
                                             uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_getpeername_handler(FAR struct rpmsg_endpoint *ept,
                                             FAR void *data, size_t len,
                                             uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_bind_handler(FAR struct rpmsg_endpoint *ept,
                                      FAR void *data, size_t len,
                                      uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_listen_handler(FAR struct rpmsg_endpoint *ept,
                                        FAR void *data, size_t len,
                                        uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_accept_handler(FAR struct rpmsg_endpoint *ept,
                                        FAR void *data, size_t len,
                                        uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept,
                                       FAR void *data, size_t len,
                                       uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_shutdown_handler(FAR struct rpmsg_endpoint *ept,
                                          FAR void *data, size_t len,
                                          uint32_t src, FAR void *priv_);
static int usrsock_rpmsg_dns_handler(FAR struct rpmsg_endpoint *ept,
                                     FAR void *data, size_t len,
                                     uint32_t src, FAR void *priv_);

static bool usrsock_rpmsg_ns_match(FAR struct rpmsg_device *rdev,
                                   FAR void *priv_, FAR const char *name,
                                   uint32_t dest);
static void usrsock_rpmsg_ns_bind(FAR struct rpmsg_device *rdev,
                                  FAR void *priv_, FAR const char *name,
                                  uint32_t dest);
static void usrsock_rpmsg_ns_unbind(FAR struct rpmsg_endpoint *ept);
static int usrsock_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
                                FAR void *data, size_t len, uint32_t src,
                                FAR void *priv);

static void usrsock_rpmsg_poll_cb(FAR struct pollfd *pfds);
static void usrsock_rpmsg_poll_setup(FAR struct pollfd *pfds,
                                     pollevent_t events);

/****************************************************************************
 * Private Data
 ****************************************************************************/

static const rpmsg_ept_cb g_usrsock_rpmsg_handler[] =
{
  usrsock_rpmsg_socket_handler,
  usrsock_rpmsg_close_handler,
  usrsock_rpmsg_connect_handler,
  usrsock_rpmsg_sendto_handler,
  usrsock_rpmsg_recvfrom_handler,
  usrsock_rpmsg_setsockopt_handler,
  usrsock_rpmsg_getsockopt_handler,
  usrsock_rpmsg_getsockname_handler,
  usrsock_rpmsg_getpeername_handler,
  usrsock_rpmsg_bind_handler,
  usrsock_rpmsg_listen_handler,
  usrsock_rpmsg_accept_handler,
  usrsock_rpmsg_ioctl_handler,
  usrsock_rpmsg_shutdown_handler,
  usrsock_rpmsg_dns_handler,
};

/****************************************************************************
 * Private Functions
 ****************************************************************************/

static bool usrsock_rpmsg_available(FAR struct socket *psock, int cmd)
{
  int len;

  if (psock_ioctl(psock, cmd, &len, sizeof(len)) == 0)
    {
      if (len > 0)
        {
          return true;
        }
    }

  return false;
}

static int usrsock_rpmsg_send_ack(FAR struct rpmsg_endpoint *ept,
                                  uint16_t events,
                                  uint32_t xid, int32_t result)
{
  struct usrsock_message_req_ack_s ack;

  ack.head.msgid  = USRSOCK_MESSAGE_RESPONSE_ACK;
  ack.head.flags  = (result == -EINPROGRESS);
  ack.head.events = events;

  ack.xid    = xid;
  ack.result = result == -EINPROGRESS ? 0 : result;

  return rpmsg_send(ept, &ack, sizeof(ack));
}

static int usrsock_rpmsg_send_data_ack(FAR struct rpmsg_endpoint *ept,
                              FAR struct usrsock_message_datareq_ack_s *ack,
                              uint16_t events,
                              uint32_t xid, int32_t result,
                              uint16_t valuelen,
                              uint16_t valuelen_nontrunc,
                              int32_t datalen)
{
  ack->reqack.head.msgid  = USRSOCK_MESSAGE_RESPONSE_DATA_ACK;
  ack->reqack.head.flags  = 0;
  ack->reqack.head.events = events;

  ack->reqack.xid    = xid;
  ack->reqack.result = result;

  if (result < 0)
    {
      valuelen           = 0;
      valuelen_nontrunc  = 0;
      datalen            = 0;
    }
  else if (valuelen > valuelen_nontrunc)
    {
      valuelen           = valuelen_nontrunc;
    }

  ack->valuelen          = valuelen;
  ack->valuelen_nontrunc = valuelen_nontrunc;

  return rpmsg_send_nocopy(ept, ack, sizeof(*ack) + valuelen + datalen);
}

static int usrsock_rpmsg_send_frag_ack(FAR struct rpmsg_endpoint *ept,
                              FAR struct usrsock_message_frag_ack_s *ack,
                              uint16_t events,
                              uint32_t xid, int32_t result,
                              uint32_t datalen)
{
  ack->reqack.head.msgid  = USRSOCK_RPMSG_FRAG_RESPONSE;
  ack->reqack.head.flags  = 0;
  ack->reqack.head.events = events;
  ack->reqack.xid         = xid;
  ack->reqack.result      = result;
  ack->datalen            = datalen;

  return rpmsg_send_nocopy(ept, ack, sizeof(*ack) + datalen);
}

static int usrsock_rpmsg_send_event(FAR struct rpmsg_endpoint *ept,
                                    int16_t usockid, uint16_t events)
{
  struct usrsock_message_socket_event_s event;

  event.head.msgid  = USRSOCK_MESSAGE_SOCKET_EVENT;
  event.head.flags  = USRSOCK_MESSAGE_FLAG_EVENT;
  event.head.events = events;

  event.usockid = usockid;

  return rpmsg_send(ept, &event, sizeof(event));
}

static int usrsock_rpmsg_socket_handler(FAR struct rpmsg_endpoint *ept,
                                        FAR void *data, size_t len,
                                        uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_socket_s *req = data;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  uint16_t events = 0;
  int ret = -ENFILE;
  int retr;
  int i;

  nxrmutex_lock(&priv->mutex);
  for (i = 0; i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS; i++)
    {
      if (priv->epts[i] == NULL)
        {
          priv->epts[i] = ept;
          nxrmutex_unlock(&priv->mutex);
          ret = psock_socket(req->domain, req->type | SOCK_NONBLOCK,
                             req->protocol, &priv->socks[i]);
          if (ret >= 0)
            {
              ret = i; /* Return index as the usockid */
              if (req->type != SOCK_STREAM && req->type != SOCK_SEQPACKET)
                {
                  events = USRSOCK_EVENT_SENDTO_READY;
                }
            }
          else
            {
              priv->epts[i] = NULL;
            }

          break;
        }
    }

  if (i == CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      nxrmutex_unlock(&priv->mutex);
    }

  retr = usrsock_rpmsg_send_ack(ept, events, req->head.xid, ret);
  if (retr >= 0 && ret >= 0 &&
      req->type != SOCK_STREAM && req->type != SOCK_SEQPACKET)
    {
      usrsock_rpmsg_poll_setup(&priv->pfds[ret], POLLIN);
    }

  return retr;
}

static int usrsock_rpmsg_close_handler(FAR struct rpmsg_endpoint *ept,
                                       FAR void *data, size_t len,
                                       uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_close_s *req = data;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  int ret = -EBADF;

  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      usrsock_rpmsg_poll_setup(&priv->pfds[req->usockid], 0);

      /* It's safe to close sock here */

      ret = psock_close(&priv->socks[req->usockid]);
      nxrmutex_lock(&priv->mutex);
      priv->epts[req->usockid] = NULL;
      nxrmutex_unlock(&priv->mutex);
    }

  return usrsock_rpmsg_send_ack(ept, 0, req->head.xid, ret);
}

static int usrsock_rpmsg_connect_handler(FAR struct rpmsg_endpoint *ept,
                                         FAR void *data, size_t len,
                                         uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_connect_s *req = data;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  bool inprogress = false;
  int ret = -EBADF;
  int retr;

  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_connect(&priv->socks[req->usockid],
              (FAR const struct sockaddr *)(req + 1), req->addrlen);
    }

  retr = usrsock_rpmsg_send_ack(ept, 0, req->head.xid, ret);
  if (ret == -EINPROGRESS)
    {
      inprogress = true;
      ret = 0;
    }

  if (retr >= 0 && ret >= 0)
    {
      pollevent_t events = POLLIN;

      if (inprogress)
        {
          events |= POLLOUT;
        }

      usrsock_rpmsg_poll_setup(&priv->pfds[req->usockid], events);
      if (!inprogress)
        {
          retr = usrsock_rpmsg_send_event(ept, req->usockid,
                                          USRSOCK_EVENT_SENDTO_READY);
        }
    }

  return retr;
}

static int usrsock_rpmsg_sendto_handler(FAR struct rpmsg_endpoint *ept,
                                        FAR void *data, size_t len,
                                        uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_sendto_s *req;
  FAR struct usrsock_rpmsg_ept_s *uept =
    (FAR struct usrsock_rpmsg_ept_s *)ept;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  uint16_t events = 0;
  ssize_t ret = -EBADF;
  int retr;
  int i;

  if (uept->remain > 0)
    {
      size_t hlen;
      struct msghdr msg =
      {
      };

      uept->remain -= len;

      if (!uept->iov[0].iov_base)
        {
          /* Maybe error occurred previously, skip processing. */

          return 0;
        }

      req = uept->iov[0].iov_base;
      hlen = sizeof(*req) + req->addrlen;

      for (i = 0; i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC; i++)
        {
          if (!uept->iov[i].iov_base)
            {
              uept->iov[i].iov_base = data;
              uept->iov[i].iov_len = len;
              rpmsg_hold_rx_buffer(ept, data);
              break;
            }
        }

      /* Partial packet ? continue to fetch */

      if (uept->remain > 0)
        {
          /* We've used the last I/O vector, cannot continue. */

          if (i == CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC - 1)
            {
              nerr("ERROR: Request %d too large!\n", req->usockid);
              ret = -ENOMEM;
              goto out;
            }

          return 0;
        }
      else if (uept->remain < 0)
        {
          ret = -EINVAL;
          goto out;
        }

      /* Skip the sendto header from I/O vector */

      uept->iov[0].iov_base = (FAR char *)uept->iov[0].iov_base + hlen;
      uept->iov[0].iov_len -= hlen;

      msg.msg_name = req->addrlen ? (FAR void *)(req + 1) : NULL;
      msg.msg_namelen = req->addrlen;
      msg.msg_iov = uept->iov;
      msg.msg_iovlen = i + 1;

      ret = psock_sendmsg(&priv->socks[req->usockid], &msg, req->flags);

      /* Recover the I/O vector */

      uept->iov[0].iov_base = (FAR char *)uept->iov[0].iov_base - hlen;
      uept->iov[0].iov_len += hlen;
    }
  else
    {
      req = data;

      if (req->usockid >= 0 &&
          req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
        {
          uept->remain = sizeof(*req) + req->addrlen + req->buflen - len;
          if (uept->remain > 0)
            {
#if CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC >= 2
              uept->iov[0].iov_base = data;
              uept->iov[0].iov_len = len;

              rpmsg_hold_rx_buffer(ept, data);
              return 0;
#else
              ret = -ENOMEM;
#endif
            }
          else
            {
              ret = psock_sendto(&priv->socks[req->usockid],
                  (FAR const void *)(req + 1) + req->addrlen, req->buflen,
                  req->flags,
                  req->addrlen ?
                        (FAR const struct sockaddr *)(req + 1) : NULL,
                  req->addrlen);
            }
        }
    }

out:
  if (ret > 0 &&
      usrsock_rpmsg_available(&priv->socks[req->usockid], FIONSPACE))
    {
      events |= USRSOCK_EVENT_SENDTO_READY;
    }

  retr = usrsock_rpmsg_send_ack(ept, events, req->head.xid, ret);
  if (retr >= 0 && (ret > 0 || ret == -EAGAIN) && events == 0)
    {
      usrsock_rpmsg_poll_setup(&priv->pfds[req->usockid],
                               priv->pfds[req->usockid].events | POLLOUT);
    }

  if (uept->iov[0].iov_base)
    {
      for (i = 0; i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC; i++)
        {
          if (uept->iov[i].iov_base == NULL)
            {
              break;
            }

          rpmsg_release_rx_buffer(ept, uept->iov[i].iov_base);
          uept->iov[i].iov_base = NULL;
          uept->iov[i].iov_len = 0;
        }
    }

  return retr;
}

static int usrsock_rpmsg_recvfrom_handler(FAR struct rpmsg_endpoint *ept,
                                          FAR void *data, size_t len_,
                                          uint32_t src, FAR void *priv_)
{
  struct iovec iov[CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC];
  FAR struct usrsock_request_recvfrom_s *req = data;
  FAR struct usrsock_message_datareq_ack_s *ack;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  socklen_t outaddrlen = req->max_addrlen;
  socklen_t inaddrlen = req->max_addrlen;
  size_t buflen = req->max_buflen;
  size_t totlen = 0;
  ssize_t ret = -EBADF;
  uint32_t len = buflen;
  uint16_t events = 0;
  uint8_t i = 0;
  int retr;

  ack = rpmsg_get_tx_payload_buffer(ept, &len, true);
  if (sizeof(*ack) + inaddrlen + buflen < len)
    {
      len = sizeof(*ack) + inaddrlen + buflen;
    }

  memset(iov, 0, sizeof(iov));
  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_recvfrom(&priv->socks[req->usockid],
              (FAR void *)(ack + 1) + inaddrlen,
              len - sizeof(*ack) - inaddrlen,
              req->flags,
              outaddrlen ? (FAR struct sockaddr *)(ack + 1) : NULL,
              outaddrlen ? &outaddrlen : NULL);
      totlen = ret;
      if (ret > 0 && (priv->socks[req->usockid].s_type & SOCK_TYPE_MASK) ==
                      SOCK_STREAM)
        {
          if (outaddrlen < inaddrlen)
            {
              memcpy((FAR void *)(ack + 1) + outaddrlen,
                     (FAR void *)(ack + 1) + inaddrlen, ret);
            }

          /* Hold net_lock to combine get_tx_payload and recvfrom together.
           * Otherwise we may keep holding tx buffer when waiting net_lock in
           * recvfrom, which may block rpmsg and may cause dead lock if
           * another thread tries to get tx buffer with net_lock held.
           */

          net_lock();
          while (totlen < buflen &&
                 i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC)
            {
              uint32_t offset = sizeof(struct usrsock_message_frag_ack_s);

              if (!usrsock_rpmsg_available(&priv->socks[req->usockid],
                                           FIONREAD))
                {
                  break;
                }

              iov[i].iov_base = rpmsg_get_tx_payload_buffer(ept,
                                                            &len,
                                                            false);
              if (!iov[i].iov_base)
                {
                  break;
                }

              DEBUGASSERT(len > offset);
              if (buflen - totlen < len - offset)
                {
                  len = buflen - totlen + offset;
                }

              /* Should never wait */

              iov[i].iov_len =
                psock_recvfrom(&priv->socks[req->usockid],
                    (FAR char *)iov[i].iov_base + offset,
                    len - offset,
                    req->flags | MSG_DONTWAIT,
                    NULL, NULL);
              if ((ssize_t)iov[i].iov_len > 0)
                {
                  totlen += iov[i].iov_len;
                  if (iov[i].iov_len < len - offset)
                    {
                      break;
                    }
                }
              else
                {
                  iov[i].iov_len = 0;
                  break;
                }

              i++;
            }

          if (usrsock_rpmsg_available(&priv->socks[req->usockid], FIONREAD))
            {
              events |= USRSOCK_EVENT_RECVFROM_AVAIL;
            }

          net_unlock();
        }
    }

  retr = usrsock_rpmsg_send_data_ack(ept,
                                     ack, events, req->head.xid,
                                     totlen, inaddrlen, outaddrlen,
                                     ret);
  for (i = 0; i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC; i++)
    {
      if (!iov[i].iov_base)
        {
          break;
        }

      if (!iov[i].iov_len || retr <= 0)
        {
          rpmsg_release_tx_buffer(ept, iov[i].iov_base);
          iov[i].iov_base = NULL;
          continue;
        }

      usrsock_rpmsg_send_frag_ack(ept,
            (FAR struct usrsock_message_frag_ack_s *)iov[i].iov_base,
            events, req->head.xid, totlen, iov[i].iov_len);
    }

  if (retr >= 0 && (ret > 0 || ret == -EAGAIN) && events == 0)
    {
      usrsock_rpmsg_poll_setup(&priv->pfds[req->usockid],
                               priv->pfds[req->usockid].events | POLLIN);
    }

  return retr;
}

static int usrsock_rpmsg_setsockopt_handler(FAR struct rpmsg_endpoint *ept,
                                            FAR void *data, size_t len,
                                            uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_setsockopt_s *req = data;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  int ret = -EBADF;

  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_setsockopt(&priv->socks[req->usockid],
              req->level, req->option, req + 1, req->valuelen);
    }

  return usrsock_rpmsg_send_ack(ept, 0, req->head.xid, ret);
}

static int usrsock_rpmsg_getsockopt_handler(FAR struct rpmsg_endpoint *ept,
                                            FAR void *data, size_t len_,
                                            uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_getsockopt_s *req = data;
  FAR struct usrsock_message_datareq_ack_s *ack;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  socklen_t optlen = req->max_valuelen;
  int ret = -EBADF;
  uint32_t len;

  ack = rpmsg_get_tx_payload_buffer(ept, &len, true);
  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_getsockopt(&priv->socks[req->usockid],
              req->level, req->option, ack + 1, &optlen);
    }

  return usrsock_rpmsg_send_data_ack(ept,
          ack, 0, req->head.xid, ret, optlen, optlen, ret);
}

static int usrsock_rpmsg_getsockname_handler(FAR struct rpmsg_endpoint *ept,
                                             FAR void *data, size_t len_,
                                             uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_getsockname_s *req = data;
  FAR struct usrsock_message_datareq_ack_s *ack;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  socklen_t outaddrlen = req->max_addrlen;
  socklen_t inaddrlen = req->max_addrlen;
  int ret = -EBADF;
  uint32_t len;

  ack = rpmsg_get_tx_payload_buffer(ept, &len, true);
  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_getsockname(&priv->socks[req->usockid],
              (FAR struct sockaddr *)(ack + 1), &outaddrlen);
    }

  return usrsock_rpmsg_send_data_ack(ept,
          ack, 0, req->head.xid, ret, inaddrlen, outaddrlen, ret);
}

static int usrsock_rpmsg_getpeername_handler(FAR struct rpmsg_endpoint *ept,
                                             FAR void *data, size_t len_,
                                             uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_getpeername_s *req = data;
  FAR struct usrsock_message_datareq_ack_s *ack;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  socklen_t outaddrlen = req->max_addrlen;
  socklen_t inaddrlen = req->max_addrlen;
  int ret = -EBADF;
  uint32_t len;

  ack = rpmsg_get_tx_payload_buffer(ept, &len, true);
  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_getpeername(&priv->socks[req->usockid],
              (FAR struct sockaddr *)(ack + 1), &outaddrlen);
    }

  return usrsock_rpmsg_send_data_ack(ept,
          ack, 0, req->head.xid, ret, inaddrlen, outaddrlen, ret);
}

static int usrsock_rpmsg_bind_handler(FAR struct rpmsg_endpoint *ept,
                                      FAR void *data, size_t len,
                                      uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_bind_s *req = data;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  int ret = -EBADF;

  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_bind(&priv->socks[req->usockid],
              (FAR const struct sockaddr *)(req + 1), req->addrlen);
    }

  return usrsock_rpmsg_send_ack(ept, 0, req->head.xid, ret);
}

static int usrsock_rpmsg_listen_handler(FAR struct rpmsg_endpoint *ept,
                                        FAR void *data, size_t len,
                                        uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_listen_s *req = data;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  int ret = -EBADF;
  int retr;

  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_listen(&priv->socks[req->usockid], req->backlog);
    }

  retr = usrsock_rpmsg_send_ack(ept, 0, req->head.xid, ret);
  if (retr >= 0 && ret >= 0)
    {
      usrsock_rpmsg_poll_setup(&priv->pfds[req->usockid], POLLIN);
    }

  return retr;
}

static int usrsock_rpmsg_accept_handler(FAR struct rpmsg_endpoint *ept,
                                        FAR void *data, size_t len_,
                                        uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_accept_s *req = data;
  FAR struct usrsock_message_datareq_ack_s *ack;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  socklen_t outaddrlen = req->max_addrlen;
  socklen_t inaddrlen = req->max_addrlen;
  uint32_t len;
  int ret = -EBADF;
  int i = 0;
  int retr;

  ack = rpmsg_get_tx_payload_buffer(ept, &len, true);
  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = -ENFILE; /* Assume no free socket handler */
      nxrmutex_lock(&priv->mutex);
      for (i = 0; i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS; i++)
        {
          if (priv->epts[i] == NULL)
            {
              priv->epts[i] = ept;
              nxrmutex_unlock(&priv->mutex);
              ret = psock_accept(&priv->socks[req->usockid],
                      outaddrlen ? (FAR struct sockaddr *)(ack + 1) : NULL,
                      outaddrlen ? &outaddrlen : NULL, &priv->socks[i],
                      SOCK_NONBLOCK);
              if (ret >= 0)
                {
                  /* Append index as usockid to the payload */

                  if (outaddrlen <= inaddrlen)
                    {
                      *(FAR int16_t *)
                      ((FAR void *)(ack + 1) + outaddrlen) = i;
                    }
                  else
                    {
                      *(FAR int16_t *)
                      ((FAR void *)(ack + 1) + inaddrlen) = i;
                    }

                  ret = sizeof(int16_t); /* Return usockid size */
                }
              else
                {
                  priv->epts[i] = NULL;
                }

              break;
            }
        }

      if (i == CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
        {
          nxrmutex_unlock(&priv->mutex);
        }
    }

  retr = usrsock_rpmsg_send_data_ack(ept,
    ack, 0, req->head.xid, ret, inaddrlen, outaddrlen, ret);
  if (retr >= 0 && ret >= 0)
    {
      usrsock_rpmsg_poll_setup(&priv->pfds[req->usockid], POLLIN);
      usrsock_rpmsg_poll_setup(&priv->pfds[i], POLLIN);
      usrsock_rpmsg_send_event(ept, i, USRSOCK_EVENT_SENDTO_READY);
    }

  return retr;
}

static int usrsock_rpmsg_ioctl_handler(FAR struct rpmsg_endpoint *ept,
                                       FAR void *data, size_t len_,
                                       uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_ioctl_s *req = data;
  FAR struct usrsock_message_datareq_ack_s *ack;
  FAR struct usrsock_rpmsg_s *priv = priv_;
#ifdef CONFIG_NETDEV_WIRELESS_IOCTL
  FAR struct iwreq *wlreq;
  FAR struct iwreq *wlack;
#endif
  int ret = -EBADF;
  uint32_t len;

  ack = rpmsg_get_tx_payload_buffer(ept, &len, true);
  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      memcpy(ack + 1, req + 1, len_ - sizeof(*req));
#ifdef CONFIG_NETDEV_WIRELESS_IOCTL
      wlreq = (FAR struct iwreq *)(req + 1);
      wlack = (FAR struct iwreq *)(ack + 1);
      if (WL_IS80211POINTERCMD(req->cmd) && wlreq->u.data.pointer)
        {
          wlack->u.data.pointer = wlack + 1;
        }
#endif

      ret = psock_ioctl(&priv->socks[req->usockid],
              req->cmd, (unsigned long)(ack + 1));

#ifdef CONFIG_NETDEV_WIRELESS_IOCTL
      if (WL_IS80211POINTERCMD(req->cmd) && wlreq->u.data.pointer)
        {
          if (ret >= 0)
            {
              ret = wlreq->u.data.length;
            }

          wlack->u.data.pointer = wlreq->u.data.pointer;
        }
#endif
    }

  return usrsock_rpmsg_send_data_ack(ept,
           ack, 0, req->head.xid, ret, req->arglen, req->arglen, ret);
}

static int usrsock_rpmsg_shutdown_handler(FAR struct rpmsg_endpoint *ept,
                                       FAR void *data, size_t len,
                                       uint32_t src, FAR void *priv_)
{
  FAR struct usrsock_request_shutdown_s *req = data;
  FAR struct usrsock_rpmsg_s *priv = priv_;
  int ret = -EBADF;

  if (req->usockid >= 0 &&
      req->usockid < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS)
    {
      ret = psock_shutdown(&priv->socks[req->usockid], req->how);
    }

  return usrsock_rpmsg_send_ack(ept, 0, req->head.xid, ret);
}

static int usrsock_rpmsg_dns_handler(FAR struct rpmsg_endpoint *ept,
                                     FAR void *data, size_t len,
                                     uint32_t src, FAR void *priv_)
{
#ifdef CONFIG_NETDB_DNSCLIENT
  FAR struct usrsock_rpmsg_dns_request_s *dns = data;

  dns_add_nameserver((FAR struct sockaddr *)(dns + 1), dns->addrlen);
#endif

  return 0;
}

#ifdef CONFIG_NETDB_DNSCLIENT
static int usrsock_rpmsg_send_dns_event(FAR void *arg,
                                        FAR struct sockaddr *addr,
                                        socklen_t addrlen)
{
  FAR struct rpmsg_endpoint *ept = arg;
  FAR struct usrsock_rpmsg_dns_event_s *dns;
  uint32_t len;

  dns = rpmsg_get_tx_payload_buffer(ept, &len, true);
  if (dns == NULL)
    {
      return -ENOMEM;
    }

  dns->head.msgid = USRSOCK_RPMSG_DNS_EVENT;
  dns->head.flags = USRSOCK_MESSAGE_FLAG_EVENT;

  dns->addrlen = addrlen;
  memcpy(dns + 1, addr, addrlen);

  return rpmsg_send_nocopy(ept, dns, sizeof(*dns) + addrlen);
}
#endif

static bool usrsock_rpmsg_ns_match(FAR struct rpmsg_device *rdev,
                                   FAR void *priv_, FAR const char *name,
                                   uint32_t dest)
{
  return !strcmp(name, USRSOCK_RPMSG_EPT_NAME);
}

static void usrsock_rpmsg_ns_bind(FAR struct rpmsg_device *rdev,
                                  FAR void *priv_, FAR const char *name,
                                  uint32_t dest)
{
  FAR struct usrsock_rpmsg_s *priv = priv_;
  FAR struct usrsock_rpmsg_ept_s *uept;
  int ret;
  int i;

  uept = kmm_zalloc(sizeof(*uept));
  if (!uept)
    {
      return;
    }

  uept->ept.priv = priv;
  for (i = 0; i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NIOVEC; i++)
    {
      sq_addlast(&uept->reqs[i].flink, &uept->req_free);
    }

  ret = rpmsg_create_ept(&uept->ept, rdev, USRSOCK_RPMSG_EPT_NAME,
                         RPMSG_ADDR_ANY, dest,
                         usrsock_rpmsg_ept_cb, usrsock_rpmsg_ns_unbind);
  if (ret < 0)
    {
      kmm_free(uept);
      return;
    }

#ifdef CONFIG_NETDB_DNSCLIENT
  dns_register_notify(usrsock_rpmsg_send_dns_event, &uept->ept);
#endif
}

static void usrsock_rpmsg_ns_unbind(FAR struct rpmsg_endpoint *ept)
{
  FAR struct usrsock_rpmsg_s *priv = ept->priv;
  int i;

#ifdef CONFIG_NETDB_DNSCLIENT
  dns_unregister_notify(usrsock_rpmsg_send_dns_event, ept);
#endif

  /* Collect all socks belong to the dead client */

  for (i = 0; i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS; i++)
    {
      if (priv->epts[i] == ept)
        {
          usrsock_rpmsg_poll_setup(&priv->pfds[i], 0);

          /* It's safe to close socks here */

          psock_close(&priv->socks[i]);
          nxrmutex_lock(&priv->mutex);
          priv->epts[i] = NULL;
          nxrmutex_unlock(&priv->mutex);
        }
    }

  rpmsg_destroy_ept(ept);
  kmm_free(ept);
}

static int usrsock_rpmsg_ept_do_cb(FAR struct usrsock_rpmsg_ept_s *uept,
                                   FAR void *data, size_t len, uint32_t src,
                                   FAR struct usrsock_rpmsg_s *priv)
{
  FAR struct usrsock_request_common_s *common = data;

  if (uept->remain > 0)
    {
      return usrsock_rpmsg_sendto_handler(&uept->ept, data, len, src, priv);
    }
  else if (common->reqid >= 0 && common->reqid <= USRSOCK_REQUEST__MAX)
    {
      return g_usrsock_rpmsg_handler[common->reqid](&uept->ept, data, len,
                                                    src, priv);
    }

  return -EINVAL;
}

static int usrsock_rpmsg_ept_cb(FAR struct rpmsg_endpoint *ept,
                                FAR void *data, size_t len, uint32_t src,
                                FAR void *priv_)
{
  FAR struct usrsock_rpmsg_s *priv = priv_;
  FAR struct usrsock_rpmsg_ept_s *uept =
    (FAR struct usrsock_rpmsg_ept_s *)ept;
  FAR struct usrsock_rpmsg_req_s *req;
  int ret;

  /* This callback is called from only one thread per ept, so don't need any
   * lock for `inuse` state.
   */

  if (uept->inuse)
    {
      /* Avoid recursive call. */

      req = (FAR struct usrsock_rpmsg_req_s *)sq_remfirst(&uept->req_free);
      if (req == NULL)
        {
          return -ENOMEM;
        }

      req->data = data;
      req->len  = len;
      req->src  = src;
      sq_addlast(&req->flink, &uept->req_pending);

      rpmsg_hold_rx_buffer(ept, data);
      return OK;
    }

  uept->inuse = true;
  ret = usrsock_rpmsg_ept_do_cb(uept, data, len, src, priv);

  /* Pop pending requests to proceed. */

  while ((req = (FAR struct usrsock_rpmsg_req_s *)
                 sq_remfirst(&uept->req_pending)) != NULL)
    {
      data = req->data;
      len  = req->len;
      src  = req->src;
      sq_addlast(&req->flink, &uept->req_free);

      ret = usrsock_rpmsg_ept_do_cb(uept, data, len, src, priv);
      if (ret < 0)
        {
          nerr("ERROR: usrsock got error %d!", ret);
        }

      rpmsg_release_rx_buffer(ept, data);
    }

  uept->inuse = false;
  return ret;
}

static void usrsock_rpmsg_poll_setup(FAR struct pollfd *pfds,
                                     pollevent_t events)
{
  FAR struct usrsock_rpmsg_s *priv = (FAR struct usrsock_rpmsg_s *)pfds->arg;
  FAR struct socket *psock = &priv->socks[pfds->fd];
  int ret = 0;

  /* No poll for SOCK_CTRL. */

  if (psock->s_type == SOCK_CTRL)
    {
      return;
    }

  net_lock();

  if (events)
    {
      if (pfds->events)
        {
          ret = psock_poll(psock, pfds, false);
        }

      if (ret >= 0)
        {
          /* The protocol stack monitor flag is different when the events is
           * POLLIN or POLLOUT, so we have to call poll_setup again.
           */

          pfds->revents = 0;
          pfds->events = events;
          ret = psock_poll(psock, pfds, true);
        }
    }
  else
    {
      pfds->revents = 0;
      pfds->events = 0;
      ret = psock_poll(psock, pfds, false);
    }

  if (ret < 0)
    {
      nerr("psock_poll failed. ret %d domain %u type %u pfds->fd %d"
           ", pfds->events %08" PRIx32 ", pfds->revents %08" PRIx32,
           ret, psock->s_domain, psock->s_type, pfds->fd,
           pfds->events, pfds->revents);
    }

  net_unlock();
}

static void usrsock_rpmsg_poll_cb(FAR struct pollfd *pfds)
{
  FAR struct usrsock_rpmsg_s *priv = (FAR struct usrsock_rpmsg_s *)pfds->arg;
  int oldevents;
  int events = 0;

  nxrmutex_lock(&priv->mutex);

  if (!priv->epts[pfds->fd])
    {
      nxrmutex_unlock(&priv->mutex);
      return;
    }

  oldevents = pfds->events;
  if (pfds->revents & POLLIN)
    {
      events |= USRSOCK_EVENT_RECVFROM_AVAIL;

      /* Stop poll in until recv get called */

      pfds->events &= ~POLLIN;
      pfds->revents &= ~POLLIN;
    }

  if (pfds->revents & POLLOUT)
    {
      events |= USRSOCK_EVENT_SENDTO_READY;

      /* Stop poll out until send get called */

      pfds->events &= ~POLLOUT;
      pfds->revents &= ~POLLOUT;
    }

  if (pfds->revents & (POLLHUP | POLLERR))
    {
      events |= USRSOCK_EVENT_REMOTE_CLOSED;

      /* Check data that has not been recv */

      if (usrsock_rpmsg_available(&priv->socks[pfds->fd], FIONREAD))
        {
          events |= USRSOCK_EVENT_RECVFROM_AVAIL;
        }

      /* Clear revents */

      pfds->revents &= ~(POLLHUP | POLLERR);
    }

  if (oldevents != pfds->events)
    {
      usrsock_rpmsg_poll_setup(pfds, pfds->events);
    }

  if (events != 0)
    {
      usrsock_rpmsg_send_event(priv->epts[pfds->fd], pfds->fd, events);
    }

  nxrmutex_unlock(&priv->mutex);
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

int usrsock_rpmsg_server_initialize(void)
{
  FAR struct usrsock_rpmsg_s *priv;
  int ret;
  int i;

  priv = kmm_calloc(1, sizeof(*priv));
  if (priv == NULL)
    {
      return -ENOMEM;
    }

  nxrmutex_init(&priv->mutex);

  /* Setup poll callback settings */

  for (i = 0; i < CONFIG_NET_USRSOCK_RPMSG_SERVER_NSOCKS; i++)
    {
      priv->pfds[i].fd  = i;
      priv->pfds[i].arg = priv;
      priv->pfds[i].cb  = usrsock_rpmsg_poll_cb;
    }

  ret = rpmsg_register_callback(priv,
                                NULL,
                                NULL,
                                usrsock_rpmsg_ns_match,
                                usrsock_rpmsg_ns_bind);
  if (ret >= 0)
    {
      return ret;
    }

  nxrmutex_destroy(&priv->mutex);
  kmm_free(priv);
  return ret;
}