text: /****************************************************************************
   * drivers/wireless/socket_imp.c  - CC3000 Host Driver Implementation.
   *  Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
   *
   *   Port to nuttx:
   *      David Sidrane <david_s5@nscdg.com>
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *    Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   *    Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the
   *    distribution.
   *
   *    Neither the name of Texas Instruments Incorporated nor the names of
   *    its contributors may be used to endorse or promote products derived
   *    from this software without specific prior written permission.
   *
   *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   ****************************************************************************/
  
  /****************************************************************************
   * Included Files
   ****************************************************************************/
  
  #include <sys/time.h>
  #include <stdio.h>
  #include <string.h>
  #include <unistd.h>
  #include <debug.h>
  #include <stdlib.h>
  
  #include <nuttx/wireless/cc3000/hci.h>
  #include "cc3000_socket.h"
  #include <nuttx/wireless/cc3000/evnt_handler.h>
  #include <nuttx/wireless/cc3000/netapp.h>
  
  /****************************************************************************
   * Pre-processor Definitions
   ****************************************************************************/
  
  /* Enable this flag if and only if you must comply with BSD socket close()
   * function
   */
  
  #ifdef _API_USE_BSD_CLOSE
  #  define close(sd) closesocket(sd)
  #endif
  
  /* Enable this flag if and only if you must comply with BSD socket read() and
   * write() functions
   */
  
  #ifdef _API_USE_BSD_READ_WRITE
  #  define read(sd, buf, len, flags) recv(sd, buf, len, flags)
  #  define write(sd, buf, len, flags) send(sd, buf, len, flags)
  #endif
  
  #define SOCKET_OPEN_PARAMS_LEN             (12)
  #define SOCKET_CLOSE_PARAMS_LEN            (4)
  #define SOCKET_ACCEPT_PARAMS_LEN           (4)
  #define SOCKET_BIND_PARAMS_LEN             (20)
  #define SOCKET_LISTEN_PARAMS_LEN           (8)
  #define SOCKET_GET_HOST_BY_NAME_PARAMS_LEN (9)
  #define SOCKET_CONNECT_PARAMS_LEN          (20)
  #define SOCKET_SELECT_PARAMS_LEN           (44)
  #define SOCKET_SET_SOCK_OPT_PARAMS_LEN     (20)
  #define SOCKET_GET_SOCK_OPT_PARAMS_LEN     (12)
  #define SOCKET_RECV_FROM_PARAMS_LEN        (12)
  #define SOCKET_SENDTO_PARAMS_LEN           (24)
  #define SOCKET_MDNS_ADVERTISE_PARAMS_LEN   (12)
  
  /* The legnth of arguments for the SEND command: sd + buff_offset + len + flags,
   * while size of each parameter is 32 bit - so the total length is 16 bytes;
   */
  
  #define HCI_CMND_SEND_ARG_LENGTH          (16)
  
  #define SELECT_TIMEOUT_MIN_MICRO_SECONDS  5000
  
  #define HEADERS_SIZE_DATA                 (SPI_HEADER_SIZE + 5)
  
  #define SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE \
    (SPI_HEADER_SIZE + SIMPLE_LINK_HCI_CMND_HEADER_SIZE)
  
  #define MDNS_DEVICE_SERVICE_MAX_LENGTH    (32)
  
  /****************************************************************************
   * Public Functions
   ****************************************************************************/
  /****************************************************************************
   * Name: HostFlowControlConsumeBuff
   *
   * Input Parameters:
   *   sd  socket descriptor
   *
   * Returned Value:
   *   0 in case there are buffers available,
   *   -1 in case of bad socket
   *   -2 if there are no free buffers present (only when
   *   SEND_NON_BLOCKING is enabled)
   *
   * Decription:
   *   if SEND_NON_BLOCKING not define - block until have free buffer
   *   becomes available, else return immediately  with correct status
   *   regarding the buffers available.
   *
   ****************************************************************************/
  
  int HostFlowControlConsumeBuff(int sd)
  {
  #ifndef SEND_NON_BLOCKING
    /* Wait in busy loop */
  
    do
      {
        /* In case last transmission failed then we will return the last failure
         * reason here.
         * Note that the buffer will not be allocated in this case
         */
  
        if (tSLInformation.slTransmitDataError != 0)
          {
            set_errno(tSLInformation.slTransmitDataError);
            tSLInformation.slTransmitDataError = 0;
            return tSLInformation.slTransmitDataError;
          }
  
        if (SOCKET_STATUS_ACTIVE != get_socket_active_status(sd))
          {
            return -1;
          }
  
        /* We must yield here for the the Event to get processed that returns
         * the buffers
         */
  
        if (0 == tSLInformation.usNumberOfFreeBuffers)
          {
            usleep(100000);
          }
      }
    while (0 == tSLInformation.usNumberOfFreeBuffers);
  
    tSLInformation.usNumberOfFreeBuffers--;
  
    return 0;
  #else
  
    /* In case last transmission failed then we will return the last failure
     * reason here.
     * Note that the buffer will not be allocated in this case
     */
  
    if (tSLInformation.slTransmitDataError != 0)
      {
        set_errno(tSLInformation.slTransmitDataError);
        tSLInformation.slTransmitDataError = 0;
        return tSLInformation.slTransmitDataError;
      }
  
    if (SOCKET_STATUS_ACTIVE != get_socket_active_status(sd))
      {
        return -1;
      }
  
    /* If there are no available buffers, return -2. It is recommended to use
     * select or receive to see if there is any buffer occupied with received data
     * If so, call receive() to release the buffer.
     */
  
    if (0 == tSLInformation.usNumberOfFreeBuffers)
      {
        return -2;
      }
    else
      {
        tSLInformation.usNumberOfFreeBuffers--;
        return 0;
      }
  #endif
  }
  
  /****************************************************************************
   * Name: socket
   *
   * Decription:
   *   create an endpoint for communication. The socket function creates a
   *   socket that is bound to a specific transport service provider.  This
   *   function is called by the application layer to obtain a socket handle.
   *
   * Input Parameters:
   *   domain    selects the protocol family which will be used for
   *    communication. On this version only AF_INET is supported
   *   type      specifies the communication semantics. On this version
   *    only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW are supported
   *   protocol  specifies a particular protocol to be used with the
   *    socket IPPROTO_TCP, IPPROTO_UDP or IPPROTO_RAW are
   *    supported.
   *
   * Returned Value:
   *   On success, socket handle that is used for consequent socket
   *    operations. On error, -1 is returned.
   *
   ****************************************************************************/
  
  int cc3000_socket_impl(long domain, long type, long protocol)
  {
    long ret;
    uint8_t *ptr, *args;
  
    ret = EFAIL;
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    /* Fill in HCI packet structure */
  
    args = UINT32_TO_STREAM(args, domain);
    args = UINT32_TO_STREAM(args, type);
    args = UINT32_TO_STREAM(args, protocol);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_SOCKET, ptr, SOCKET_OPEN_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_CMND_SOCKET, &ret);
  
    /* Process the event */
  
    set_errno(ret);
    set_socket_active_status(ret, SOCKET_STATUS_ACTIVE);
    return ret;
  }
  
  /****************************************************************************
   * Name: closesocket
   *
   * Decription:
   *   The socket function closes a created socket.
   *
   * Input Parameters:
   *   sd    socket handle.
   *
   * Returned Value:
   *   On success, zero is returned. On error, -1 is returned.
   *
   ****************************************************************************/
  
  long cc3000_closesocket_impl(long sd)
  {
    long ret;
    uint8_t *ptr, *args;
  
    ret = EFAIL;
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    /* Fill in HCI packet structure */
  
    args = UINT32_TO_STREAM(args, sd);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_CLOSE_SOCKET,
                     ptr, SOCKET_CLOSE_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_CMND_CLOSE_SOCKET, &ret);
    set_errno(ret);
  
    /* Since 'close' call may result in either OK (and then it closed) or error
     * mark this socket as invalid
     */
  
    set_socket_active_status(sd, SOCKET_STATUS_INACTIVE);
  
    return ret;
  }
  
  /****************************************************************************
   * Name: accept
   *
   * Decription:
   *   accept a connection on a socket:
   *   This function is used with connection-based socket types
   *   (SOCK_STREAM). It extracts the first connection request on the
   *   queue of pending connections, creates a new connected socket, and
   *   returns a new file descriptor referring to that socket.
   *   The newly created socket is not in the listening state.
   *   The original socket sd is unaffected by this call.
   *   The argument sd is a socket that has been created with socket(),
   *   bound to a local address with bind(), and is  listening for
   *   connections after a listen(). The argument addr is a pointer
   *   to a sockaddr structure. This structure is filled in with the
   *   address of the peer socket, as known to the communications layer.
   *   The exact format of the address returned addr is determined by the
   *   socket's address family. The addrlen argument is a value-result
   *   argument: it should initially contain the size of the structure
   *   pointed to by addr, on return it will contain the actual
   *   length (in bytes) of the address returned.
   *
   * Input Parameters:
   *   sd      socket descriptor (handle)
   *   addr    the argument addr is a pointer to a sockaddr structure
   *           This structure is filled in with the address of the
   *           peer socket, as known to the communications layer.
   *           determined. The exact format of the address returned
   *           addr is by the socket's address sockaddr.
   *           On this version only AF_INET is supported.
   *           This argument returns in network order.
   *   addrlen The addrlen argument is a value-result argument:
   *           it should initially contain the size of the structure
   *            pointed to by addr.
   *
   * Returned Value:
   *   For socket in blocking mode:
   *    On success, socket handle. on failure negative
   *     For socket in non-blocking mode:
   *   - On connection establishment, socket handle
   *   - On connection pending, SOC_IN_PROGRESS (-2)
   *   - On failure, SOC_ERROR  (-1)
   *
   ****************************************************************************/
  
  long cc3000_accept_impl(long sd, struct sockaddr *addr, socklen_t *addrlen)
  {
    long ret;
    uint8_t *ptr, *args;
    tBsdReturnParams tAcceptReturnArguments;
  
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    /* Fill in temporary command buffer */
  
    args = UINT32_TO_STREAM(args, sd);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_ACCEPT,
                     ptr, SOCKET_ACCEPT_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_CMND_ACCEPT, &tAcceptReturnArguments);
  
  
    /* Need specify return parameters!!! */
  
    memcpy(addr, &tAcceptReturnArguments.tSocketAddress, CC3000_ASIC_ADDR_LEN);
    *addrlen = CC3000_ASIC_ADDR_LEN;
    set_errno(tAcceptReturnArguments.iStatus);
    ret = tAcceptReturnArguments.iStatus;
  
    /* if succeeded, iStatus = new socket descriptor. otherwise - error number */
  
    if (M_IS_VALID_SD(ret))
      {
        set_socket_active_status(ret, SOCKET_STATUS_ACTIVE);
      }
    else
      {
        set_socket_active_status(sd, SOCKET_STATUS_INACTIVE);
      }
  
    return ret;
  }
  
  /****************************************************************************
   * Name: bind
   *
   * Decription:
   *   assign a name to a socket
   *   This function gives the socket the local address addr.
   *   addr is addrlen bytes long. Traditionally, this is called when a
   *   socket is created with socket, it exists in a name space (address
   *   family) but has no name assigned.
   *   It is necessary to assign a local address before a SOCK_STREAM
   *   socket may receive connections.
   *
   * Input Parameters:
   *   sd      socket descriptor (handle)
   *   addr    specifies the destination address. On this version
   *    only AF_INET is supported.
   *   addrlen  contains the size of the structure pointed to by addr.
   *
   * Returned Value:
   *   On success, zero is returned. On error, -1 is returned.
   *
   ****************************************************************************/
  
  long cc3000_bind_impl(long sd, const struct sockaddr *addr, socklen_t addrlen)
  {
    long ret;
    uint8_t *ptr, *args;
  
    ret = EFAIL;
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    addrlen = CC3000_ASIC_ADDR_LEN;
  
    /* Fill in temporary command buffer */
  
    args = UINT32_TO_STREAM(args, sd);
    args = UINT32_TO_STREAM(args, 0x00000008);
    args = UINT32_TO_STREAM(args, addrlen);
    ARRAY_TO_STREAM(args, ((uint8_t *)addr), addrlen);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_BIND,
                     ptr, SOCKET_BIND_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_CMND_BIND, &ret);
  
    set_errno(ret);
    return ret;
  }
  
  /****************************************************************************
   * Name: listen
   *
   * Decription:
   *   listen for connections on a socket
   *   The willingness to accept incoming connections and a queue
   *   limit for incoming connections are specified with listen(),
   *   and then the connections are accepted with accept.
   *   The listen() call applies only to sockets of type SOCK_STREAM
   *   The backlog parameter defines the maximum length the queue of
   *   pending connections may grow to.
   *
   * NOTE: On this version, backlog is not supported
   *
   * Input Parameters:
   *   sd      socket descriptor (handle)
   *   backlog  specifies the listen queue depth. On this version
   *    backlog is not supported.
   *
   * Returned Value:
   *   On success, zero is returned. On error, -1 is returned.
   *
   ****************************************************************************/
  
  long cc3000_listen_impl(long sd, long backlog)
  {
    long ret;
    uint8_t *ptr, *args;
  
    ret = EFAIL;
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    /* Fill in temporary command buffer */
  
    args = UINT32_TO_STREAM(args, sd);
    args = UINT32_TO_STREAM(args, backlog);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_LISTEN,
                     ptr, SOCKET_LISTEN_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_CMND_LISTEN, &ret);
  
    set_errno(ret);
    return ret;
  }
  
  /****************************************************************************
   * Name: gethostbyname
   *
   * Decription:
   *   Get host IP by name. Obtain the IP Address of machine on network,
   *   by its name.
   *
   * NOTE: On this version, only blocking mode is supported. Also note that
   *       the function requires DNS server to be configured prior to its
   *       usage.
   *
   * Input Parameters:
   *   hostname     host name
   *   usNameLen    name length
   *   out_ip_addr  This parameter is filled in with host IP address.
   *   In case that host name is not resolved,
   *   out_ip_addr is zero.
   *
   * Returned Value:
   *   On success, positive is returned. On error, negative is returned
   *
   ****************************************************************************/
  
  #ifndef CC3000_TINY_DRIVER
  int cc3000_gethostbyname_impl(char *hostname, uint16_t usNameLen,
                                unsigned long *out_ip_addr)
  {
    tBsdGethostbynameParams ret;
    uint8_t *ptr, *args;
  
    set_errno(EFAIL);
  
    if (usNameLen > CC3000_HOSTNAME_MAX_LENGTH)
      {
        return get_errno();
      }
  
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE);
  
    /* Fill in HCI packet structure */
  
    args = UINT32_TO_STREAM(args, 8);
    args = UINT32_TO_STREAM(args, usNameLen);
    ARRAY_TO_STREAM(args, hostname, usNameLen);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_GETHOSTNAME, ptr, SOCKET_GET_HOST_BY_NAME_PARAMS_LEN
                     + usNameLen - 1);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_EVNT_BSD_GETHOSTBYNAME, &ret);
  
    set_errno(ret.retVal);
  
    (*((FAR long *)out_ip_addr)) = ret.outputAddress;
  
    return ret.retVal;
  }
  #endif
  
  /****************************************************************************
   * Name: connect
   *
   * Decription:
   *   initiate a connection on a socket
   *   Function connects the socket referred to by the socket descriptor
   *   sd, to the address specified by addr. The addrlen argument
   *   specifies the size of addr. The format of the address in addr is
   *   determined by the address space of the socket. If it is of type
   *   SOCK_DGRAM, this call specifies the peer with which the socket is
   *   to be associated; this address is that to which datagrams are to be
   *   sent, and the only address from which datagrams are to be received.
   *   If the socket is of type SOCK_STREAM, this call attempts to make a
   *   connection to another socket. The other socket is specified  by
   *   address, which is an address in the communications space of the
   *   socket. Note that the function implements only blocking behavior
   *   thus the caller will be waiting either for the connection
   *   establishment or for the connection establishment failure.
   *
   * Input Parameters:
   *   sd       socket descriptor (handle)
   *   addr     specifies the destination addr. On this version
   *     only AF_INET is supported.
   *   addrlen  contains the size of the structure pointed to by addr
   *
   * Returned Value:
   *   On success, zero is returned. On error, -1 is returned
   *
   ****************************************************************************/
  
  long cc3000_connect_impl(long sd, const struct sockaddr *addr, socklen_t addrlen)
  {
    long int ret;
    uint8_t *ptr, *args;
  
    ret = EFAIL;
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE);
    addrlen = 8;
  
    /* Fill in temporary command buffer */
  
    args = UINT32_TO_STREAM(args, sd);
    args = UINT32_TO_STREAM(args, 0x00000008);
    args = UINT32_TO_STREAM(args, addrlen);
    ARRAY_TO_STREAM(args, ((uint8_t *)addr), addrlen);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_CONNECT,
                     ptr, SOCKET_CONNECT_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_CMND_CONNECT, &ret);
  
    set_errno(ret);
    return (long)ret;
  }
  
  /****************************************************************************
   * Name: select
   *
   * Decription:
   *   Monitor socket activity
   *   Select allow a program to monitor multiple file descriptors,
   *   waiting until one or more of the file descriptors become
   *   "ready" for some class of I/O operation
   *
   * NOTE: If the timeout value set to less than 5ms it will automatically set
   *   to 5ms to prevent overload of the system
   *
   * Input Parameters:
   *   nfds       the highest-numbered file descriptor in any of the
   *     three sets, plus 1.
   *   writesds   socket descriptors list for write monitoring
   *   readsds    socket descriptors list for read monitoring
   *   exceptsds  socket descriptors list for exception monitoring
   *   timeout     is an upper bound on the amount of time elapsed
   *     before select() returns. Null means infinity
   *     timeout. The minimum timeout is 5 milliseconds,
   *    less than 5 milliseconds will be set
   *     automatically to 5 milliseconds.
   *
   * Returned Value:
   *   On success, select() returns the number of file descriptors
   *   contained in the three returned descriptor sets (that is, the
   *   total number of bits that are set in readfds, writefds,
   *   exceptfds) which may be zero if the timeout expires before
   *   anything interesting  happens.
   *   On error, -1 is returned.
   *   *readsds - return the sockets on which Read request will
   *     return without delay with valid data.
   *   *writesds - return the sockets on which Write request
   *     will return without delay.
   *   *exceptsds - return the sockets which closed recently.
   *
   ****************************************************************************/
  
  int cc3000_select_impl(long nfds, TICC3000fd_set *readsds, TICC3000fd_set *writesds,
             TICC3000fd_set *exceptsds, struct timeval *timeout)
  {
    uint8_t *ptr, *args;
    tBsdSelectRecvParams tParams;
    unsigned long is_blocking;
  
    if (timeout == NULL)
      {
        is_blocking = 1; /* blocking , infinity timeout */
      }
    else
      {
        is_blocking = 0; /* no blocking, timeout */
      }
  
    /* Fill in HCI packet structure */
  
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    /* Fill in temporary command buffer */
  
    args = UINT32_TO_STREAM(args, nfds);
    args = UINT32_TO_STREAM(args, 0x00000014);
    args = UINT32_TO_STREAM(args, 0x00000014);
    args = UINT32_TO_STREAM(args, 0x00000014);
    args = UINT32_TO_STREAM(args, 0x00000014);
    args = UINT32_TO_STREAM(args, is_blocking);
    args = UINT32_TO_STREAM(args, ((readsds) ? *(FAR unsigned long *)readsds : 0));
    args = UINT32_TO_STREAM(args, ((writesds) ? *(FAR unsigned long *)writesds : 0));
    args = UINT32_TO_STREAM(args, ((exceptsds) ? *(FAR unsigned long *)exceptsds : 0));
  
    if (timeout)
      {
        if (0 == timeout->tv_sec && timeout->tv_usec <
            SELECT_TIMEOUT_MIN_MICRO_SECONDS)
          {
            timeout->tv_usec = SELECT_TIMEOUT_MIN_MICRO_SECONDS;
          }
  
        args = UINT32_TO_STREAM(args, timeout->tv_sec);
        args = UINT32_TO_STREAM(args, timeout->tv_usec);
     }
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_BSD_SELECT, ptr, SOCKET_SELECT_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_EVNT_SELECT, &tParams);
  
    /* Update actually read FD */
  
    if (tParams.iStatus >= 0)
      {
        if (readsds)
          {
            memcpy(readsds, &tParams.uiRdfd, sizeof(tParams.uiRdfd));
          }
  
        if (writesds)
          {
            memcpy(writesds, &tParams.uiWrfd, sizeof(tParams.uiWrfd));
          }
  
        if (exceptsds)
          {
            memcpy(exceptsds, &tParams.uiExfd, sizeof(tParams.uiExfd));
          }
  
        return tParams.iStatus;
      }
    else
      {
        set_errno(tParams.iStatus);
        return -1;
      }
  }
  
  /****************************************************************************
   * Name: setsockopt
   *
   * Decription:
   *   set socket options
   *   This function manipulate the options associated with a socket.
   *   Options may exist at multiple protocol levels; they are always
   *   present at the uppermost socket level.
   *   When manipulating socket options the level at which the option
   *   resides and the name of the option must be specified.
   *   To manipulate options at the socket level, level is specified as
   *   SOL_SOCKET. To manipulate options at any other level the protocol
   *   number of the appropriate protocol controlling the option is
   *   supplied. For example, to indicate that an option is to be
   *   interpreted by the TCP protocol, level should be set to the
   *   protocol number of TCP;
   *   The parameters optval and optlen are used to access optval -
   *   use for setsockopt(). For getsockopt() they identify a buffer
   *   in which the value for the requested option(s) are to
   *   be returned. For getsockopt(), optlen is a value-result
   *   parameter, initially containing the size of the buffer
   *   pointed to by option_value, and modified on return to
   *   indicate the actual size of the value returned. If no option
   *   value is to be supplied or returned, option_value may be NULL.
   *
   * NOTE: On this version the following two socket options are enabled:
   *    The only protocol level supported in this version
   *   is SOL_SOCKET (level).
   *    1. SOCKOPT_RECV_TIMEOUT (optname)
   *     SOCKOPT_RECV_TIMEOUT configures recv and recvfrom timeout
   *    in milliseconds.
   *     In that case optval should be pointer to unsigned long.
   *    2. SOCKOPT_NONBLOCK (optname). sets the socket non-blocking mode on
   *    or off.
   *     In that case optval should be SOCK_ON or SOCK_OFF (optval).
   *
   * Input Parameters:
   *   sd          socket handle
   *   level       defines the protocol level for this option
   *   optname     defines the option name to Interrogate
   *   optval      specifies a value for the option
   *   optlen      specifies the length of the option value
   *
   * Returned Value:
   *   On success, zero is returned. On error, -1 is returned
   *
   ****************************************************************************/
  
  #ifndef CC3000_TINY_DRIVER
  int cc3000_setsockopt_impl(long sd, long level, long optname, const void *optval, socklen_t optlen)
  {
    int ret;
    uint8_t *ptr, *args;
  
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    /* Fill in temporary command buffer */
  
    args = UINT32_TO_STREAM(args, sd);
    args = UINT32_TO_STREAM(args, level);
    args = UINT32_TO_STREAM(args, optname);
    args = UINT32_TO_STREAM(args, 0x00000008);
    args = UINT32_TO_STREAM(args, optlen);
    ARRAY_TO_STREAM(args, ((uint8_t *)optval), optlen);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_SETSOCKOPT,
                     ptr, SOCKET_SET_SOCK_OPT_PARAMS_LEN  + optlen);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_CMND_SETSOCKOPT, &ret);
  
    if (ret >= 0)
      {
        return 0;
      }
    else
      {
        set_errno(ret);
        return ret;
      }
  }
  #endif
  
  /****************************************************************************
   * Name: getsockopt
   *
   * Decription:
   *   set socket options
   *   This function manipulate the options associated with a socket.
   *   Options may exist at multiple protocol levels; they are always
   *   present at the uppermost socket level.
   *   When manipulating socket options the level at which the option
   *   resides and the name of the option must be specified.
   *   To manipulate options at the socket level, level is specified as
   *   SOL_SOCKET. To manipulate options at any other level the protocol
   *   number of the appropriate protocol controlling the option is
   *   supplied. For example, to indicate that an option is to be
   *   interpreted by the TCP protocol, level should be set to the
   *   protocol number of TCP;
   *   The parameters optval and optlen are used to access optval -
   *   use for setsockopt(). For getsockopt() they identify a buffer
   *   in which the value for the requested option(s) are to
   *   be returned. For getsockopt(), optlen is a value-result
   *   parameter, initially containing the size of the buffer
   *   pointed to by option_value, and modified on return to
   *   indicate the actual size of the value returned. If no option
   *   value is to be supplied or returned, option_value may be NULL.
   *
   * NOTE: On this version the following two socket options are enabled:
   *    The only protocol level supported in this version
   *   is SOL_SOCKET (level).
   *    1. SOCKOPT_RECV_TIMEOUT (optname)
   *     SOCKOPT_RECV_TIMEOUT configures recv and recvfrom timeout
   *    in milliseconds.
   *     In that case optval should be pointer to unsigned long.
   *    2. SOCKOPT_NONBLOCK (optname). sets the socket non-blocking mode on
   *    or off.
   *     In that case optval should be SOCK_ON or SOCK_OFF (optval).
   *
   * Input Parameters:
   *   sd          socket handle
   *   level       defines the protocol level for this option
   *   optname     defines the option name to Interrogate
   *   optval      specifies a value for the option
   *   optlen      specifies the length of the option value
   *
   * Returned Value:
   *   On success, zero is returned. On error, -1 is returned
   *
   ****************************************************************************/
  
  int cc3000_getsockopt_impl(long sd, long level, long optname, void *optval, socklen_t *optlen)
  {
    uint8_t *ptr, *args;
    tBsdGetSockOptReturnParams  tRetParams;
  
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    /* Fill in temporary command buffer */
  
    args = UINT32_TO_STREAM(args, sd);
    args = UINT32_TO_STREAM(args, level);
    args = UINT32_TO_STREAM(args, optname);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_GETSOCKOPT,
                     ptr, SOCKET_GET_SOCK_OPT_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_CMND_GETSOCKOPT, &tRetParams);
  
    if (((int8_t)tRetParams.iStatus) >= 0)
      {
        *optlen = 4;
        memcpy(optval, tRetParams.ucOptValue, 4);
        return 0;
      }
    else
      {
        set_errno(tRetParams.iStatus);
        return tRetParams.iStatus;
      }
  }
  
  /****************************************************************************
   * Name: simple_link_recv
   *
   * Input Parameters:
   *   sd       socket handle
   *   buf      read buffer
   *   len      buffer length
   *   flags    indicates blocking or non-blocking operation
   *   from     pointer to an address structure indicating source address
   *   fromlen  source address structure size
   *
   * Returned Value:
   *     Return the number of bytes received, or -1 if an error
   *     occurred
   *
   * Decription:
   *     Read data from socket
   *     Return the length of the message on successful completion.
   *     If a message is too long to fit in the supplied buffer,
   *     excess bytes may be discarded depending on the type of
   *     socket the message is received from
   *
   ****************************************************************************/
  
  int simple_link_recv(long sd, void *buf, long len, long flags, struct sockaddr *from,
                       socklen_t *fromlen, long opcode)
  {
    uint8_t *ptr, *args;
    tBsdReadReturnParams tSocketReadEvent;
  
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_CMD);
  
    /* Fill in HCI packet structure */
  
    args = UINT32_TO_STREAM(args, sd);
    args = UINT32_TO_STREAM(args, len);
    args = UINT32_TO_STREAM(args, flags);
  
    /* Generate the read command, and wait for the */
  
    hci_command_send(opcode,  ptr, SOCKET_RECV_FROM_PARAMS_LEN);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(opcode, &tSocketReadEvent);
  
    /* In case the number of bytes is more then zero - read data */
  
    if (tSocketReadEvent.iNumberOfBytes > 0)
      {
        /* Wait for the data in a synchronous way. Here we assume that the bug is
         * big enough to store also parameters of receive from too....
         */
  
        SimpleLinkWaitData((uint8_t *)buf, (uint8_t *)from, (uint8_t *)fromlen);
      }
  
    set_errno(tSocketReadEvent.iNumberOfBytes);
    return tSocketReadEvent.iNumberOfBytes;
  }
  
  /****************************************************************************
   * Name: recv
   *
   * Decription:
   *     function receives a message from a connection-mode socket
   *
   * NOTE: On this version, only blocking mode is supported.
   *
   * Input Parameters:
   *   sd     socket handle
   *   buf    Points to the buffer where the message should be stored
   *   len    Specifies the length in bytes of the buffer pointed to
   *     by the buffer argument.
   *   flags   Specifies the type of message reception.
   *     On this version, this parameter is not supported.
   *
   * Returned Value:
   *     Return the number of bytes received, or -1 if an error
   *     occurred
   *
   ****************************************************************************/
  
  int cc3000_recv_impl(long sd, void *buf, long len, long flags)
  {
    return(simple_link_recv(sd, buf, len, flags, NULL, NULL, HCI_CMND_RECV));
  }
  
  /****************************************************************************
   * Name: recvfrom
   *
   * Decription:
   *    read data from socket
   *    function receives a message from a connection-mode or
   *    connectionless-mode socket. Note that raw sockets are not
   *    supported.
   *
   * NOTE: On this version, only blocking mode is supported.
   *
   * Input Parameters:
   *   sd     socket handle
   *   buf    Points to the buffer where the message should be stored
   *   len    Specifies the length in bytes of the buffer pointed to
   *     by the buffer argument.
   *   flags   Specifies the type of message reception.
   *     On this version, this parameter is not supported.
   *   from   pointer to an address structure indicating the source
   *    address: sockaddr. On this version only AF_INET is
   *    supported.
   *   fromlen   source address tructure size
   *
   * Returned Value:
   *     Return the number of bytes received, or -1 if an error
   *     occurred
   *
   ****************************************************************************/
  
  int cc3000_recvfrom_impl(long sd, void *buf, long len, long flags, struct sockaddr *from,
               socklen_t *fromlen)
  {
    return(simple_link_recv(sd, buf, len, flags, from, fromlen,
                            HCI_CMND_RECVFROM));
  }
  
  /****************************************************************************
   * Name: simple_link_send
   *
   * Input Parameters:
   *   sd       socket handle
   *   buf      write buffer
   *   len      buffer length
   *   flags    On this version, this parameter is not supported
   *   to       pointer to an address structure indicating destination
   *     address
   *   tolen    destination address structure size
   *
   * Returned Value:
   *     Return the number of bytes transmitted, or -1 if an error
   *     occurred, or -2 in case there are no free buffers available
   *    (only when SEND_NON_BLOCKING is enabled)
   *
   * Decription:
   *     This function is used to transmit a message to another
   *     socket
   *
   ****************************************************************************/
  
  int simple_link_send(long sd, const void *buf, long len, long flags,
                       const struct sockaddr *to, long tolen, long opcode)
  {
    tBsdReadReturnParams tSocketSendEvent;
    uint8_t uArgSize = 0,  addrlen;
    uint8_t *ptr, *pDataPtr = NULL, *args;
    unsigned long addr_offset = 0;
    int res;
  
    /* Check the bsd_arguments */
  
    if (0 != (res = HostFlowControlConsumeBuff(sd)))
      {
        return res;
      }
  
    /* Update the number of sent packets */
  
    tSLInformation.NumberOfSentPackets++;
  
    /* Allocate a buffer and construct a packet and send it over spi */
  
    ptr = tSLInformation.pucTxCommandBuffer;
    args = (ptr + HEADERS_SIZE_DATA);
  
    /* Update the offset of data and parameters according to the command */
  
    switch (opcode)
      {
      case HCI_CMND_SENDTO:
        {
          addr_offset = len + sizeof(len) + sizeof(len);
          addrlen = 8;
          uArgSize = SOCKET_SENDTO_PARAMS_LEN;
          pDataPtr = ptr + HEADERS_SIZE_DATA + SOCKET_SENDTO_PARAMS_LEN;
          break;
        }
  
      case HCI_CMND_SEND:
        {
          tolen = 0;
          to = NULL;
          uArgSize = HCI_CMND_SEND_ARG_LENGTH;
          pDataPtr = ptr + HEADERS_SIZE_DATA + HCI_CMND_SEND_ARG_LENGTH;
          break;
        }
  
      default:
        {
          break;
        }
    }
  
    /* Fill in temporary command buffer */
  
    args = UINT32_TO_STREAM(args, sd);
    args = UINT32_TO_STREAM(args, uArgSize - sizeof(sd));
    args = UINT32_TO_STREAM(args, len);
    args = UINT32_TO_STREAM(args, flags);
  
    if (opcode == HCI_CMND_SENDTO)
      {
        args = UINT32_TO_STREAM(args, addr_offset);
        args = UINT32_TO_STREAM(args, addrlen);
      }
  
    /* Copy the data received from user into the TX Buffer */
  
    ARRAY_TO_STREAM(pDataPtr, ((FAR uint8_t *)buf), len);
  
    /* In case we are using SendTo, copy the to parameters */
  
    if (opcode == HCI_CMND_SENDTO)
      {
        ARRAY_TO_STREAM(pDataPtr, ((FAR uint8_t *)to), tolen);
      }
  
    /* Initiate a HCI command */
  
    hci_data_send(opcode, ptr, uArgSize, len, (FAR uint8_t *)to, tolen);
  
    if (opcode == HCI_CMND_SENDTO)
      {
        SimpleLinkWaitEvent(HCI_EVNT_SENDTO, &tSocketSendEvent);
      }
    else
      {
        SimpleLinkWaitEvent(HCI_EVNT_SEND, &tSocketSendEvent);
      }
  
    return len;
  }
  
  /****************************************************************************
   * Name: send
   *
   * Decription:
   *     Write data to TCP socket
   *     This function is used to transmit a message to another
   *     socket.
   *
   * NOTE: On this version, only blocking mode is supported.
   *
   * Input Parameters:
   *   sd       socket handle
   *   buf      Points to a buffer containing the message to be sent
   *   len      message size in bytes
   *   flags    On this version, this parameter is not supported
   *
   * Returned Value:
   *     Return the number of bytes transmitted, or -1 if an
   *     error occurred
   *
   ****************************************************************************/
  
  int cc3000_send_impl(long sd, const void *buf, long len, long flags)
  {
    return(simple_link_send(sd, buf, len, flags, NULL, 0, HCI_CMND_SEND));
  }
  
  /****************************************************************************
   * Name: sendto
   *
   * Decription:
   *     Write data to TCP socket
   *     This function is used to transmit a message to another
   *     socket.
   *
   * NOTE: On this version, only blocking mode is supported.
   *
   * Input Parameters:
   *   sd       socket handle
   *   buf      Points to a buffer containing the message to be sent
   *   len      message size in bytes
   *   flags    On this version, this parameter is not supported
   *   to       pointer to an address structure indicating the destination
   *     address: sockaddr. On this version only AF_INET is
   *     supported.
   *   tolen    destination address structure size
   *
   * Returned Value:
   *     Return the number of bytes transmitted, or -1 if an
   *     error occurred
   *
   ****************************************************************************/
  
  int cc3000_sendto_impl(long sd, const void *buf, long len, long flags, const struct sockaddr *to,
             socklen_t tolen)
  {
    return(simple_link_send(sd, buf, len, flags, to, tolen, HCI_CMND_SENDTO));
  }
  
  /****************************************************************************
   * Name: mdnsAdvertiser
   *
   * Decription:
   *     Set CC3000 in mDNS advertiser mode in order to advertise itself.
   *
   * Input Parameters:
   *   mdnsEnabled             flag to enable/disable the mDNS feature
   *   deviceServiceName       Service name as part of the published
   *                           canonical domain name
   *   deviceServiceNameLength Length of the service name
   *
   * Returned Value:
   *   On success, zero is returned, return SOC_ERROR if socket was not
   *   opened successfully, or if an error occurred.
   *
   ****************************************************************************/
  
  int cc3000_mdnsadvertiser_impl(uint16_t mdnsEnabled, char * deviceServiceName,
                     uint16_t deviceServiceNameLength)
  {
    uint8_t *pTxBuffer;
    uint8_t *pArgs;
    int ret;
  
    if (deviceServiceNameLength > MDNS_DEVICE_SERVICE_MAX_LENGTH)
      {
        return EFAIL;
      }
  
    pTxBuffer = tSLInformation.pucTxCommandBuffer;
    pArgs = (pTxBuffer + SIMPLE_LINK_HCI_CMND_TRANSPORT_HEADER_SIZE);
  
    /* Fill in HCI packet structure */
  
    pArgs = UINT32_TO_STREAM(pArgs, mdnsEnabled);
    pArgs = UINT32_TO_STREAM(pArgs, 8);
    pArgs = UINT32_TO_STREAM(pArgs, deviceServiceNameLength);
    ARRAY_TO_STREAM(pArgs, deviceServiceName, deviceServiceNameLength);
  
    /* Initiate a HCI command */
  
    hci_command_send(HCI_CMND_MDNS_ADVERTISE, pTxBuffer, SOCKET_MDNS_ADVERTISE_PARAMS_LEN + deviceServiceNameLength);
  
    /* Since we are in blocking state - wait for event complete */
  
    SimpleLinkWaitEvent(HCI_EVNT_MDNS_ADVERTISE, &ret);
  
    return ret;
  }
  