/****************************************************************************
 * net/pkt/pkt.h
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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.
 *
 ****************************************************************************/

#ifndef __NET_PKT_PKT_H
#define __NET_PKT_PKT_H

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

#include <nuttx/config.h>

#include <sys/types.h>

#include <nuttx/mutex.h>
#include <nuttx/net/net.h>

#ifdef CONFIG_NET_PKT

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Allocate a new packet socket data callback */

#define pkt_callback_alloc(dev,conn) \
  devif_callback_alloc(dev, &conn->sconn.s_list, &conn->sconn.s_listtail)
#define pkt_callback_free(dev,conn,cb) \
  devif_conn_callback_free(dev, cb, &conn->sconn.s_list, &conn->sconn.s_listtail)

/****************************************************************************
 * Public Type Definitions
 ****************************************************************************/

/* Representation of a packet socket connection */

struct devif_callback_s; /* Forward reference */
struct pollfd;           /* Forward reference */

/* This is a container that holds the poll-related information */

struct pkt_poll_s
{
  FAR struct pkt_conn_s       *conn; /* Needed to handle loss of connection */
  FAR struct pollfd           *fds;  /* Needed to handle poll events */
  FAR struct devif_callback_s *cb;   /* Needed to teardown the poll */
};

struct pkt_conn_s
{
  /* Common prologue of all connection structures. */

  struct socket_conn_s sconn;

  /* Pkt socket-specific content follows */

  uint8_t    ifindex;
  uint8_t    crefs;    /* Reference counts on this instance */
  uint16_t   type;     /* The Ethernet type of the packet */

#ifdef CONFIG_NET_PKT_WRITE_BUFFERS
  /* Write buffering
   *
   *   write_q   - The queue of unsent I/O buffers.  The head of this
   *               list may be partially sent.  FIFO ordering.
   */

  struct iob_queue_s write_q;     /* Write buffering for pkt messages */

  /* Callback instance for pkt send */

  FAR struct devif_callback_s *sndcb;
#endif

  /* Read-ahead buffering.
   *
   *   readahead - A singly linked list of type struct iob_qentry_s
   *               where the PKT read-ahead data is retained.
   *
   * TODO: Maybe support PACKET_MMAP for further optimize.
   */

  struct iob_queue_s readahead;   /* Read-ahead buffering */

#ifdef CONFIG_NET_TIMESTAMPING
  struct iob_queue_s errahead;    /* Error-ahead buffering */
#endif

  FAR struct iob_s  *pendiob;     /* The iob currently being sent */

  /* The following is a list of poll structures of threads waiting for
   * socket events.
   */

  struct pkt_poll_s  pollinfo[CONFIG_NET_PKT_NPOLLWAITERS];
};

/****************************************************************************
 * Public Data
 ****************************************************************************/

#ifdef __cplusplus
#  define EXTERN extern "C"
extern "C"
{
#else
#  define EXTERN extern
#endif

/* The packet socket interface */

EXTERN const struct sock_intf_s g_pkt_sockif;

/* The PKT connections rmutex */

DECLARE_PER_CPU_BMP(rmutex_t, g_pkt_connections_lock);
#define g_pkt_connections_lock this_cpu_var_bmp(g_pkt_connections_lock)

/****************************************************************************
 * Name: pkt_conn_list_lock()
 *
 * Description:
 *   Lock the packet connection list
 *
 * Assumptions:
 *   This function must be called by driver thread.
 *
 ****************************************************************************/

static inline_function void pkt_conn_list_lock(void)
{
  nxrmutex_lock(&g_pkt_connections_lock);
}

/****************************************************************************
 * Name: pkt_conn_list_unlock()
 *
 * Description:
 *   Unlock the packet connection list
 *
 * Assumptions:
 *   This function must be called by driver thread.
 *
 ****************************************************************************/

static inline_function void pkt_conn_list_unlock(void)
{
  nxrmutex_unlock(&g_pkt_connections_lock);
}

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

struct net_driver_s; /* Forward reference */
struct socket;       /* Forward reference */

/****************************************************************************
 * Name: pkt_alloc()
 *
 * Description:
 *   Allocate a new, uninitialized packet socket connection structure. This
 *   is normally something done by the implementation of the socket() API
 *
 ****************************************************************************/

FAR struct pkt_conn_s *pkt_alloc(void);

/****************************************************************************
 * Name: pkt_free()
 *
 * Description:
 *   Free a packet socket connection structure that is no longer in use.
 *   This should be done by the implementation of close().
 *
 ****************************************************************************/

void pkt_free(FAR struct pkt_conn_s *conn);

/****************************************************************************
 * Name: pkt_active()
 *
 * Description:
 *   Find a connection structure that is the appropriate connection to be
 *   used with the provided network device
 *
 * Input Parameters:
 *   dev  - The device driver structure containing the received packet
 *   conn - A pointer to the PKT connection structure
 *   loopback - Indicate whether it is a loopback packet
 *
 *
 * Assumptions:
 *   This function is called from network logic at with the network locked.
 *
 ****************************************************************************/

FAR struct pkt_conn_s *pkt_active(FAR struct net_driver_s *dev,
                                  FAR struct pkt_conn_s *conn,
                                  bool loopback);

/****************************************************************************
 * Name: pkt_nextconn()
 *
 * Description:
 *   Traverse the list of allocated packet connections
 *
 * Assumptions:
 *   This function is called from network logic at with the network locked.
 *
 ****************************************************************************/

FAR struct pkt_conn_s *pkt_nextconn(FAR struct pkt_conn_s *conn);

/****************************************************************************
 * Name: pkt_sendmsg_is_valid
 *
 * Description:
 *   Validate the sendmsg() parameters for a packet socket.
 *
 * Input Parameters:
 *   psock - The socket structure to validate
 *   msg   - The message header containing the data to be sent
 *   dev   - The network device to be used to send the packet
 *
 * Returned Value:
 *   Zero (OK) on success; a negated errno value on failure.
 *
 ****************************************************************************/

int pkt_sendmsg_is_valid(FAR struct socket *psock,
                         FAR const struct msghdr *msg,
                         FAR struct net_driver_s **dev);

/****************************************************************************
 * Name: pkt_callback
 *
 * Description:
 *   Inform the application holding the packet socket of a change in state.
 *
 * Returned Value:
 *   OK if packet has been processed, otherwise ERROR.
 *
 * Assumptions:
 *   This function is called from network logic at with the network locked.
 *
 ****************************************************************************/

uint32_t pkt_callback(FAR struct net_driver_s *dev,
                      FAR struct pkt_conn_s *conn, uint32_t flags);

/****************************************************************************
 * Name: pkt_input
 *
 * Description:
 *   Handle incoming packet input
 *
 *   This function provides the interface between Ethernet device drivers and
 *   packet socket logic.  All frames that are received should be provided to
 *   pkt_input() prior to other routing.
 *
 * Input Parameters:
 *   dev - The device driver structure containing the received packet
 *
 * Returned Value:
 *   OK    The packet has been processed  and can be deleted
 *   ERROR There is a matching connection, but could not dispatch the packet
 *         yet.  Useful when a packet arrives before a recv call is in
 *         place.
 *
 * Assumptions:
 *   Called from the network diver with the network locked.
 *
 ****************************************************************************/

/* pkt_input() is prototyped in include/nuttx/net/pkt.h */

/****************************************************************************
 * Name: pkt_recvmsg
 *
 * Description:
 *   Implements the socket recvmsg interface for the case of the AF_INET
 *   and AF_INET6 address families.  pkt_recvmsg() receives messages from
 *   a socket, and may be used to receive data on a socket whether or not it
 *   is connection-oriented.
 *
 *   If 'msg_name' is not NULL, and the underlying protocol provides the
 *   source address, this source address is filled in.  The argument
 *   'msg_namelen' is initialized to the size of the buffer associated with
 *   msg_name, and modified on return to indicate the actual size of the
 *   address stored there.
 *
 * Input Parameters:
 *   psock    A pointer to a NuttX-specific, internal socket structure
 *   msg      Buffer to receive the message
 *   flags    Receive flags
 *
 * Returned Value:
 *   On success, returns the number of characters received. If no data is
 *   available to be received and the peer has performed an orderly shutdown,
 *   recvmsg() will return 0.  Otherwise, on errors, a negated errno value is
 *   returned (see recvmsg() for the list of appropriate error values).
 *
 ****************************************************************************/

ssize_t pkt_recvmsg(FAR struct socket *psock, FAR struct msghdr *msg,
                    int flags);

/****************************************************************************
 * Name: pkt_find_device
 *
 * Description:
 *   Select the network driver to use with the PKT transaction.
 *
 * Input Parameters:
 *   conn - PKT connection structure.
 *
 * Returned Value:
 *   A pointer to the network driver to use.
 *
 ****************************************************************************/

FAR struct net_driver_s *pkt_find_device(FAR struct pkt_conn_s *conn);

/****************************************************************************
 * Name: pkt_poll
 *
 * Description:
 *   Poll a packet "connection" structure for availability of TX data
 *
 * Input Parameters:
 *   dev - The device driver structure to use in the send operation
 *   conn - The packet "connection" to poll for TX data
 *
 * Returned Value:
 *   None
 *
 * Assumptions:
 *   Called from the network device interface (devif) with the network
 *   locked.
 *
 ****************************************************************************/

void pkt_poll(FAR struct net_driver_s *dev, FAR struct pkt_conn_s *conn);

/****************************************************************************
 * Name: pkt_pollsetup
 *
 * Description:
 *   Setup to monitor events on one PKT socket
 *
 * Input Parameters:
 *   psock - The PKT socket of interest
 *   fds   - The structure describing the events to be monitored, OR NULL if
 *           this is a request to stop monitoring events.
 *
 * Returned Value:
 *  0: Success; Negated errno on failure
 *
 ****************************************************************************/

int pkt_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds);

/****************************************************************************
 * Name: pkt_pollteardown
 *
 * Description:
 *   Teardown monitoring of events on an PKT socket
 *
 * Input Parameters:
 *   psock - The PKT socket of interest
 *   fds   - The structure describing the events to be monitored, OR NULL if
 *           this is a request to stop monitoring events.
 *
 * Returned Value:
 *  0: Success; Negated errno on failure
 *
 ****************************************************************************/

int pkt_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds);

/****************************************************************************
 * Name: pkt_sendmsg
 *
 * Description:
 *   The pkt_sendmsg() call may be used only when the packet socket is in
 *   a connected state (so that the intended recipient is known).
 *
 * Input Parameters:
 *   psock    An instance of the internal socket structure.
 *   msg      Message to send
 *   flags    Send flags
 *
 * Returned Value:
 *   On success, returns the number of characters sent. On error, a negated
 *   errno value is returned (see sendmsg() for the complete list of return
 *   values.
 *
 ****************************************************************************/

ssize_t pkt_sendmsg(FAR struct socket *psock, FAR const struct msghdr *msg,
                    int flags);

#ifdef CONFIG_NET_PKTPROTO_OPTIONS
/****************************************************************************
 * Name: pkt_getsockopt
 *
 * Description:
 *   pkt_getsockopt() retrieves the value for the option specified by the
 *   'option' argument for the socket specified by the 'psock' argument.  If
 *   the size of the option value is greater than 'value_len', the value
 *   stored in the object pointed to by the 'value' argument will be silently
 *   truncated. Otherwise, the length pointed to by the 'value_len' argument
 *   will be modified to indicate the actual length of the 'value'.
 *
 *   See <sys/socket.h> a complete list of values for the socket-level
 *   'option' argument.  Protocol-specific options are are protocol specific
 *   header files (such as nuttx/pkt.h for the case of the PKT protocol).
 *
 * Input Parameters:
 *   psock     Socket structure of the socket to query
 *   level     Protocol level to set the option
 *   option    identifies the option to get
 *   value     Points to the argument value
 *   value_len The length of the argument value
 *
 * Returned Value:
 *   Returns zero (OK) on success.  On failure, it returns a negated errno
 *   value to indicate the nature of the error.  See psock_getsockopt() for
 *   the complete list of appropriate return error codes.
 *
 ****************************************************************************/

int pkt_getsockopt(FAR struct socket *psock, int level, int option,
                   FAR void *value, FAR socklen_t *value_len);

/****************************************************************************
 * Name: pkt_setsockopt
 *
 * Description:
 *   pkt_setsockopt() sets the PKT-protocol option specified by the
 *   'option' argument to the value pointed to by the 'value' argument for
 *   the socket specified by the 'psock' argument.
 *
 *   See <nuttx/pkt.h> for the a complete list of values of PKT protocol
 *   options.
 *
 * Input Parameters:
 *   psock     Socket structure of socket to operate on
 *   level     Protocol level to set the option
 *   option    identifies the option to set
 *   value     Points to the argument value
 *   value_len The length of the argument value
 *
 * Returned Value:
 *   Returns zero (OK) on success.  On failure, it returns a negated errno
 *   value to indicate the nature of the error.  See psock_setcockopt() for
 *   the list of possible error values.
 *
 ****************************************************************************/

int pkt_setsockopt(FAR struct socket *psock, int level, int option,
                   FAR const void *value, socklen_t value_len);

#endif

#undef EXTERN
#ifdef __cplusplus
}
#endif

#endif /* CONFIG_NET_PKT */
#endif /* __NET_PKT_PKT_H */