Beispiel #1
0
void uip_igmpwaitmsg(FAR struct igmp_group_s *group, uint8_t msgid)
{
  uip_lock_t flags;

  /* Schedule to send the message */

  flags = uip_lock();
  DEBUGASSERT(!IS_WAITMSG(group->flags));
  SET_WAITMSG(group->flags);
  uip_igmpschedmsg(group, msgid);

  /* Then wait for the message to be sent */

  while (IS_SCHEDMSG(group->flags))
    {
      /* Wait for the semaphore to be posted */

      while (uip_lockedwait(&group->sem) != 0)
        {
          /* The only error that should occur from uip_lockedwait() is if
           * the wait is awakened by a signal.
           */
 
          ASSERT(errno == EINTR);
        }
    }

  /* The message has been sent and we are no longer waiting */

  CLR_WAITMSG(group->flags);
  uip_unlock(flags);
}
static inline void _uip_semtake(sem_t *sem)
{
  /* Take the semaphore (perhaps waiting) */

  while (uip_lockedwait(sem) != 0)
    {
      /* The only case that an error should occur here is if
       * the wait was awakened by a signal.
       */

      ASSERT(*get_errno_ptr() == EINTR);
    }
}
Beispiel #3
0
static inline void netclose_disconnect(FAR struct socket *psock)
{
  struct tcp_close_s state;
  uip_lock_t flags;

  /* Interrupts are disabled here to avoid race conditions */

  flags = uip_lock();

  /* Is the TCP socket in a connected state? */

  if (_SS_ISCONNECTED(psock->s_flags))
    {
       struct uip_conn *conn = (struct uip_conn*)psock->s_conn;

       /* Check for the case where the host beat us and disconnected first */

       if (conn->tcpstateflags == UIP_ESTABLISHED)
         {
           /* Set up to receive TCP data event callbacks */

           state.cl_cb = uip_tcpcallbackalloc(conn);
           if (state.cl_cb)
             {
               state.cl_psock       = psock;
               sem_init(&state.cl_sem, 0, 0);

               state.cl_cb->flags   = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT;
               state.cl_cb->priv    = (void*)&state;
               state.cl_cb->event   = netclose_interrupt;

              /* Notify the device driver of the availaibilty of TX data */

               netdev_txnotify(&conn->ripaddr);

               /* Wait for the disconnect event */

               (void)uip_lockedwait(&state.cl_sem);

               /* We are now disconnected */

               sem_destroy(&state.cl_sem);
               uip_tcpcallbackfree(conn, state.cl_cb);
            }
        }
    }

  uip_unlock(flags);
}
ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf,
                     size_t len, int flags, FAR const struct sockaddr *to,
                     socklen_t tolen)
{
#ifdef CONFIG_NET_UDP
  FAR struct uip_udp_conn *conn;
#ifdef CONFIG_NET_IPv6
  FAR const struct sockaddr_in6 *into = (const struct sockaddr_in6 *)to;
#else
  FAR const struct sockaddr_in *into = (const struct sockaddr_in *)to;
#endif
  struct sendto_s state;
  uip_lock_t save;
  int ret;
#endif
  int err;

  /* If to is NULL or tolen is zero, then this function is same as send (for
   * connected socket types)
   */

  if (!to || !tolen)
    {
#ifdef CONFIG_NET_TCP
      return psock_send(psock, buf, len, flags);
#else
      err = EINVAL;
      goto errout;
#endif
    }

  /* Verify that a valid address has been provided */

#ifdef CONFIG_NET_IPv6
  if (to->sa_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6))
#else
  if (to->sa_family != AF_INET || tolen < sizeof(struct sockaddr_in))
#endif
  {
      err = EBADF;
      goto errout;
  }

  /* Verify that the psock corresponds to valid, allocated socket */

  if (!psock || psock->s_crefs <= 0)
    {
      err = EBADF;
      goto errout;
    }

  /* If this is a connected socket, then return EISCONN */

  if (psock->s_type != SOCK_DGRAM)
    {
      err = EISCONN;
      goto errout;
    }

  /* Perform the UDP sendto operation */

#ifdef CONFIG_NET_UDP
  /* Set the socket state to sending */

  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);

  /* Initialize the state structure.  This is done with interrupts
   * disabled because we don't want anything to happen until we
   * are ready.
   */

  save = uip_lock();
  memset(&state, 0, sizeof(struct sendto_s));
  sem_init(&state.st_sem, 0, 0);
  state.st_buflen = len;
  state.st_buffer = buf;

  /* Set the initial time for calculating timeouts */

#ifdef CONFIG_NET_SENDTO_TIMEOUT
  state.st_sock = psock;
  state.st_time = clock_systimer();
#endif

  /* Setup the UDP socket */

  conn = (struct uip_udp_conn *)psock->s_conn;
  ret = uip_udpconnect(conn, into);
  if (ret < 0)
    {
      uip_unlock(save);
      err = -ret;
      goto errout;
    }

  /* Set up the callback in the connection */

  state.st_cb = uip_udpcallbackalloc(conn);
  if (state.st_cb)
    {
      state.st_cb->flags   = UIP_POLL;
      state.st_cb->priv    = (void*)&state;
      state.st_cb->event   = sendto_interrupt;

      /* Notify the device driver of the availabilty of TX data */

      netdev_txnotify(conn->ripaddr);

      /* Wait for either the receive to complete or for an error/timeout to occur.
       * NOTES:  (1) uip_lockedwait will also terminate if a signal is received, (2)
       * interrupts may be disabled!  They will be re-enabled while the task sleeps
       * and automatically re-enabled when the task restarts.
       */

      uip_lockedwait(&state.st_sem);

      /* Make sure that no further interrupts are processed */

      uip_udpcallbackfree(conn, state.st_cb);
    }
  uip_unlock(save);

  sem_destroy(&state.st_sem);

  /* Set the socket state to idle */

  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);

  /* Check for errors */

  if (state.st_sndlen < 0)
    {
      err = -state.st_sndlen;
      goto errout;
    }

  /* Sucess */

  return state.st_sndlen;
#else
  err = ENOSYS;
#endif

errout:
  set_errno(err);
  return ERROR;
}
Beispiel #5
0
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
{
  FAR struct socket *psock = sockfd_socket(sockfd);
  FAR struct socket *pnewsock;
  FAR struct uip_conn *conn;
  struct accept_s state;
#ifdef CONFIG_NET_IPv6
  FAR struct sockaddr_in6 *inaddr = (struct sockaddr_in6 *)addr;
#else
  FAR struct sockaddr_in *inaddr = (struct sockaddr_in *)addr;
#endif
  uip_lock_t save;
  int newfd;
  int err;
  int ret;

  /* Verify that the sockfd corresponds to valid, allocated socket */

  if (!psock || psock->s_crefs <= 0)
    {
      /* It is not a valid socket description.  Distinguish between the cases
       * where sockfd is a just valid and when it is a valid file descriptor used
       * in the wrong context.
       */

#if CONFIG_NFILE_DESCRIPTORS > 0
      if ((unsigned int)sockfd < CONFIG_NFILE_DESCRIPTORS)
        {
          err = ENOTSOCK;
        }
      else
#endif
        {
          err = EBADF;
        }
      goto errout;
    }

  /* We have a socket descriptor, but it is a stream? */

  if (psock->s_type != SOCK_STREAM)
    {
      err = EOPNOTSUPP;
      goto errout;
    }

  /* Is the socket listening for a connection? */

  if (!_SS_ISLISTENING(psock->s_flags))
    {
      err = EINVAL;
      goto errout;
    }

  /* Verify that a valid memory block has been provided to receive the
   * address
   */

  if (addr)
    {
#ifdef CONFIG_NET_IPv6
      if (*addrlen < sizeof(struct sockaddr_in6))
#else
      if (*addrlen < sizeof(struct sockaddr_in))
#endif
        {
          err = EBADF;
          goto errout;
        }
    }

  /* Allocate a socket descriptor for the new connection now (so that it
   * cannot fail later)
   */

  newfd = sockfd_allocate(0);
  if (newfd < 0)
    {
      err = ENFILE;
      goto errout;
    }

  pnewsock = sockfd_socket(newfd);
  if (!pnewsock)
    {
      err = ENFILE;
      goto errout_with_socket;
    }

  /* Check the backlog to see if there is a connection already pending for
   * this listener.
   */

  save = uip_lock();
  conn = (struct uip_conn *)psock->s_conn;

#ifdef CONFIG_NET_TCPBACKLOG
  state.acpt_newconn = uip_backlogremove(conn);
  if (state.acpt_newconn)
    {
      /* Yes... get the address of the connected client */

      nvdbg("Pending conn=%p\n", state.acpt_newconn);
      accept_tcpsender(state.acpt_newconn, inaddr);
    }

  /* In general, this uIP-based implementation will not support non-blocking
   * socket operations... except in a few cases:  Here for TCP accept with backlog
   * enabled.  If this socket is configured as non-blocking then return EAGAIN
   * if there is no pending connection in the backlog.
   */

  else if (_SS_ISNONBLOCK(psock->s_flags))
    {
      err = EAGAIN;
      goto errout_with_lock;
    }
  else
#endif
    {
      /* Set the socket state to accepting */

      psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_ACCEPT);

      /* Perform the TCP accept operation */

      /* Initialize the state structure.  This is done with interrupts
       * disabled because we don't want anything to happen until we
       * are ready.
       */

      state.acpt_addr       = inaddr;
      state.acpt_newconn    = NULL;
      state.acpt_result     = OK;
      sem_init(&state.acpt_sem, 0, 0);

      /* Set up the callback in the connection */

      conn->accept_private  = (void*)&state;
      conn->accept          = accept_interrupt;

      /* Wait for the send to complete or an error to occur:  NOTES: (1)
       * uip_lockedwait will also terminate if a signal is received, (2) interrupts
       * may be disabled!  They will be re-enabled while the task sleeps and
       * automatically re-enabled when the task restarts.
       */

      ret = uip_lockedwait(&state.acpt_sem);

      /* Make sure that no further interrupts are processed */

      conn->accept_private = NULL;
      conn->accept         = NULL;

      sem_destroy(&state. acpt_sem);

      /* Set the socket state to idle */

      psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);

      /* Check for a errors.  Errors are signaled by negative errno values
       * for the send length.
       */

      if (state.acpt_result != 0)
        {
          err = state.acpt_result;
          goto errout_with_lock;
        }

      /* If uip_lockedwait failed, then we were probably reawakened by a signal. In
       * this case, uip_lockedwait will have set errno appropriately.
       */

      if (ret < 0)
        {
          err = -ret;
          goto errout_with_lock;
        }
    }

  /* Initialize the socket structure and mark the socket as connected.
   * (The reference count on the new connection structure was set in the
   * interrupt handler).
   */

  pnewsock->s_type   = SOCK_STREAM;
  pnewsock->s_conn   = state.acpt_newconn;
  pnewsock->s_flags |= _SF_CONNECTED;
  pnewsock->s_flags &= ~_SF_CLOSED;

  /* Begin monitoring for TCP connection events on the newly connected socket */

  net_startmonitor(pnewsock);
  uip_unlock(save);
  return newfd;

errout_with_lock:
  uip_unlock(save);

errout_with_socket:
  sockfd_release(newfd);

errout:
  errno = err;
  return ERROR;
}
Beispiel #6
0
int uip_ping(uip_ipaddr_t addr, uint16_t id, uint16_t seqno,
             uint16_t datalen, int dsecs)
{
  struct icmp_ping_s state;
  uip_lock_t save;

  /* Initialize the state structure */

  sem_init(&state.png_sem, 0, 0);
  state.png_ticks  = DSEC2TICK(dsecs); /* System ticks to wait */
  state.png_result = -ENOMEM;          /* Assume allocation failure */
  state.png_addr   = addr;             /* Address of the peer to be ping'ed */
  state.png_id     = id;               /* The ID to use in the ECHO request */
  state.png_seqno  = seqno;            /* The seqno to use int the ECHO request */
  state.png_datlen = datalen;          /* The length of data to send in the ECHO request */
  state.png_sent   = false;            /* ECHO request not yet sent */

  save             = uip_lock();
  state.png_time   = clock_systimer();

  /* Set up the callback */

  state.png_cb = uip_icmpcallbackalloc();
  if (state.png_cb)
    {
      state.png_cb->flags   = UIP_POLL|UIP_ECHOREPLY;
      state.png_cb->priv    = (void*)&state;
      state.png_cb->event   = ping_interrupt;
      state.png_result      = -EINTR; /* Assume sem-wait interrupted by signal */

      /* Notify the device driver of the availaibilty of TX data */

      netdev_txnotify(&state.png_addr);

      /* Wait for either the full round trip transfer to complete or
       * for timeout to occur. (1) uip_lockedwait will also terminate if a
       * signal is received, (2) interrupts may be disabled!  They will
       * be re-enabled while the task sleeps and automatically
       * re-enabled when the task restarts.
       */

      nlldbg("Start time: 0x%08x seqno: %d\n", state.png_time, seqno);
      uip_lockedwait(&state.png_sem);

      uip_icmpcallbackfree(state.png_cb);
    }
  uip_unlock(save);

  /* Return the negated error number in the event of a failure, or the
   * sequence number of the ECHO reply on success.
   */

  if (!state.png_result)
    {
      nlldbg("Return seqno=%d\n", state.png_seqno);
      return (int)state.png_seqno;
    }
  else
    {
      nlldbg("Return error=%d\n", -state.png_result);
      return state.png_result;
    }
}
Beispiel #7
0
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
{
  FAR struct socket *psock = sockfd_socket(sockfd);
  struct send_s state;
  uip_lock_t save;
  int err;
  int ret = OK;

  /* Verify that the sockfd corresponds to valid, allocated socket */

  if (!psock || psock->s_crefs <= 0)
    {
      err = EBADF;
      goto errout;
    }

  /* If this is an un-connected socket, then return ENOTCONN */

  if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags))
    {
      err = ENOTCONN;
      goto errout;
    }

  /* Set the socket state to sending */

  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);

  /* Perform the TCP send operation */

  /* Initialize the state structure.  This is done with interrupts
   * disabled because we don't want anything to happen until we
   * are ready.
   */

  save                = uip_lock();
  memset(&state, 0, sizeof(struct send_s));
  (void)sem_init(&state. snd_sem, 0, 0); /* Doesn't really fail */
  state.snd_sock      = psock;             /* Socket descriptor to use */
  state.snd_buflen    = len;               /* Number of bytes to send */
  state.snd_buffer    = buf;               /* Buffer to send from */

  if (len > 0)
    {
      struct uip_conn *conn = (struct uip_conn*)psock->s_conn;

      /* Allocate resources to receive a callback */

      state.snd_cb = uip_tcpcallbackalloc(conn);
      if (state.snd_cb)
        {
          /* Get the initial sequence number that will be used */

          state.snd_isn         = uip_tcpgetsequence(conn->sndseq);

          /* There is no outstanding, unacknowledged data after this
           * initial sequence number.
           */

          conn->unacked         = 0;

          /* Update the initial time for calculating timeouts */

#if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK)
          state.snd_time        = clock_systimer();
#endif
          /* Set up the callback in the connection */

          state.snd_cb->flags   = UIP_ACKDATA|UIP_REXMIT|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT;
          state.snd_cb->priv    = (void*)&state;
          state.snd_cb->event   = send_interrupt;

          /* Notify the device driver of the availaibilty of TX data */

          netdev_txnotify(&conn->ripaddr);

          /* Wait for the send to complete or an error to occur:  NOTES: (1)
           * uip_lockedwait will also terminate if a signal is received, (2) interrupts
           * may be disabled!  They will be re-enabled while the task sleeps and
           * automatically re-enabled when the task restarts.
           */

          ret = uip_lockedwait(&state. snd_sem);

          /* Make sure that no further interrupts are processed */

          uip_tcpcallbackfree(conn, state.snd_cb);
        }
    }

  sem_destroy(&state. snd_sem);
  uip_unlock(save);

  /* Set the socket state to idle */

  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE);

  /* Check for a errors.  Errors are signaled by negative errno values
   * for the send length
   */

  if (state.snd_sent < 0)
    {
      err = state.snd_sent;
      goto errout;
    }

  /* If uip_lockedwait failed, then we were probably reawakened by a signal. In
   * this case, uip_lockedwait will have set errno appropriately.
   */

  if (ret < 0)
    {
      err = -ret;
      goto errout;
    }

  /* Return the number of bytes actually sent */

  return state.snd_sent;

errout:
  *get_errno_ptr() = err;
  return ERROR;
}
Beispiel #8
0
static ssize_t tcp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
                            FAR struct sockaddr_in *infrom )
#endif
{
  struct recvfrom_s       state;
  uip_lock_t              save;
  int                     ret;

  /* Initialize the state structure.  This is done with interrupts
   * disabled because we don't want anything to happen until we
   * are ready.
   */

  save = uip_lock();
  recvfrom_init(psock, buf, len, infrom, &state);

  /* Handle any any TCP data already buffered in a read-ahead buffer.  NOTE
   * that there may be read-ahead data to be retrieved even after the
   * socket has been disconnected.
   */

#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
  recvfrom_readahead(&state);

  /* The default return value is the number of bytes that we just copied into
   * the user buffer.  We will return this if the socket has become disconnected
   * or if the user request was completely satisfied with data from the readahead
   * buffers.
   */
   
  ret = state.rf_recvlen;

#else
  /* Otherwise, the default return value of zero is used (only for the case
   * where len == state.rf_buflen is zero).
   */

  ret = 0;
#endif

  /* Verify that the SOCK_STREAM has been and still is connected */

  if (!_SS_ISCONNECTED(psock->s_flags))
    {
      /* Was any data transferred from the readahead buffer after we were
       * disconnected?  If so, then return the number of bytes received.  We
       * will wait to return end disconnection indications the next time that
       * recvfrom() is called.
       *
       * If no data was received (i.e.,  ret == 0  -- it will not be negative)
       * and the connection was gracefully closed by the remote peer, then return
       * success.  If rf_recvlen is zero, the caller of recvfrom() will get an
       * end-of-file indication.
       */

#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
      if (ret <= 0 && !_SS_ISCLOSED(psock->s_flags))
#else
      if (!_SS_ISCLOSED(psock->s_flags))
#endif
        {
          /* Nothing was previously received from the readahead buffers.
           * The SOCK_STREAM must be (re-)connected in order to receive any
           * additional data.
           */

          ret = -ENOTCONN;
        }
    }

  /* In general, this uIP-based implementation will not support non-blocking
   * socket operations... except in a few cases:  Here for TCP receive with read-ahead
   * enabled.  If this socket is configured as non-blocking then return EAGAIN
   * if no data was obtained from the read-ahead buffers.
   */

  else
#if CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
  if (_SS_ISNONBLOCK(psock->s_flags))
    {
      /* Return the number of bytes read from the read-ahead buffer if
       * something was received (already in 'ret'); EAGAIN if not.
       */

      if (ret <= 0)
        {
          /* Nothing was received */

          ret = -EAGAIN;
        }
    }

  /* It is okay to block if we need to.  If there is space to receive anything
   * more, then we will wait to receive the data.  Otherwise return the number
   * of bytes read from the read-ahead buffer (already in 'ret').
   */

  else
#endif

  /* We get here when we we decide that we need to setup the wait for incoming
   * TCP/IP data.  Just a few more conditions to check:
   *
   * 1) Make sure thet there is buffer space to receive additional data
   *    (state.rf_buflen > 0).  This could be zero, for example, if read-ahead
   *    buffering was enabled and we filled the user buffer with data from
   *    the read-ahead buffers.  Aand
   * 2) if read-ahead buffering is enabled (CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0)
   *    and delay logic is disabled (CONFIG_NET_TCP_RECVDELAY == 0), then we
   *    not want to wait if we already obtained some data from the read-ahead
   *    buffer.  In that case, return now with what we have (don't want for more
   *    because there may be no timeout).
   */

#if CONFIG_NET_TCP_RECVDELAY == 0 && CONFIG_NET_NTCP_READAHEAD_BUFFERS > 0
  if (state.rf_recvlen == 0 && state.rf_buflen > 0)
#else
  if (state.rf_buflen > 0)
#endif
    {
      struct uip_conn *conn = (struct uip_conn *)psock->s_conn;

      /* Set up the callback in the connection */

      state.rf_cb = uip_tcpcallbackalloc(conn);
      if (state.rf_cb)
        {
          state.rf_cb->flags   = UIP_NEWDATA|UIP_POLL|UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT;
          state.rf_cb->priv    = (void*)&state;
          state.rf_cb->event   = recvfrom_tcpinterrupt;

          /* Wait for either the receive to complete or for an error/timeout to occur.
           * NOTES:  (1) uip_lockedwait will also terminate if a signal is received, (2)
           * interrupts may be disabled!  They will be re-enabled while the task sleeps
           * and automatically re-enabled when the task restarts.
           */

          ret = uip_lockedwait(&state.rf_sem);

          /* Make sure that no further interrupts are processed */

          uip_tcpcallbackfree(conn, state.rf_cb);
          ret = recvfrom_result(ret, &state);
        }
      else
        {
          ret = -EBUSY;
        }
    }

  uip_unlock(save);
  recvfrom_uninit(&state);
  return (ssize_t)ret;
}
Beispiel #9
0
static ssize_t udp_recvfrom(FAR struct socket *psock, FAR void *buf, size_t len,
                            FAR struct sockaddr_in *infrom )
#endif
{
  struct uip_udp_conn *conn = (struct uip_udp_conn *)psock->s_conn;
  struct recvfrom_s    state;
  uip_lock_t           save;
  int                  ret;

  /* Perform the UDP recvfrom() operation */

  /* Initialize the state structure.  This is done with interrupts
   * disabled because we don't want anything to happen until we
   * are ready.
   */

  save = uip_lock();
  recvfrom_init(psock, buf, len, infrom, &state);

  /* Setup the UDP remote connection */

  ret = uip_udpconnect(conn, NULL);
  if (ret < 0)
    {
      goto errout_with_state;
    }

  /* Set up the callback in the connection */

  state.rf_cb = uip_udpcallbackalloc(conn);
  if (state.rf_cb)
    {
      /* Set up the callback in the connection */

      state.rf_cb->flags   = UIP_NEWDATA|UIP_POLL;
      state.rf_cb->priv    = (void*)&state;
      state.rf_cb->event   = recvfrom_udpinterrupt;

      /* Enable the UDP socket */

      uip_udpenable(conn);

      /* Wait for either the receive to complete or for an error/timeout to occur.
       * NOTES:  (1) uip_lockedwait will also terminate if a signal is received, (2)
       * interrupts are disabled!  They will be re-enabled while the task sleeps
       * and automatically re-enabled when the task restarts.
       */

      ret = uip_lockedwait(&state. rf_sem);

      /* Make sure that no further interrupts are processed */

      uip_udpdisable(conn);
      uip_udpcallbackfree(conn, state.rf_cb);
      ret = recvfrom_result(ret, &state);
    }
  else
    {
      ret = -EBUSY;
    }

errout_with_state:
  uip_unlock(save);
  recvfrom_uninit(&state);
  return ret;
}
Beispiel #10
0
static inline int tcp_connect(FAR struct socket *psock, const struct sockaddr_in *inaddr)
#endif
{
  struct tcp_connect_s state;
  uip_lock_t           flags;
  int                  ret = OK;

  /* Interrupts must be disabled through all of the following because
   * we cannot allow the network callback to occur until we are completely
   * setup.
   */

  flags = uip_lock();

  /* Get the connection reference from the socket */

  if (!psock->s_conn) /* Should always be non-NULL */
    {
      ret = -EINVAL;
    }
  else
    {
      /* Perform the uIP connection operation */

      ret = uip_tcpconnect(psock->s_conn, inaddr);
    }

  if (ret >= 0)
    {
      /* Set up the callbacks in the connection */

      ret = tcp_setup_callbacks(psock, &state);
      if (ret >= 0)
        {
          /* Wait for either the connect to complete or for an error/timeout
           * to occur. NOTES:  (1) uip_lockedwait will also terminate if a signal
           * is received, (2) interrupts may be disabled!  They will be re-
           * enabled while the task sleeps and automatically re-disabled
           * when the task restarts.
           */

          ret = uip_lockedwait(&state.tc_sem);

          /* Uninitialize the state structure */

          (void)sem_destroy(&state.tc_sem);

          /* If uip_lockedwait failed, recover the negated error (probably -EINTR) */

          if (ret < 0)
            {
              ret = -errno;
            }
          else
            {
              /* If the wait succeeded, then get the new error value from
               * the state structure
               */

              ret = state.tc_result;
            }

          /* Make sure that no further interrupts are processed */

          tcp_teardown_callbacks(&state, ret);
        }

      /* Mark the connection bound and connected */

      if (ret >= 0)
        {
          psock->s_flags |= (_SF_BOUND|_SF_CONNECTED);
        }
    }

    uip_unlock(flags);
    return ret;
}