net/l2/l3/l4: add support of iob offload

1. Add new config CONFIG_NET_LL_GUARDSIZE to isolation of l2 stack,
   which will benefit l3(IP) layer for multi-MAC(l2) implementation,
   especially in some NICs such as celluler net driver.

new configuration options: CONFIG_NET_LL_GUARDSIZE

CONFIG_NET_LL_GUARDSIZE will reserved l2 buffer header size of
network buffer to isolate the L2/L3 (MAC/IP) data on network layer,
which will be beneficial to L3 network layer protocol transparent
transmission and forwarding

------------------------------------------------------------
Layout of frist iob entry:

        iob_data (aligned by CONFIG_IOB_ALIGNMENT)
            |
            |                  io_offset(CONFIG_NET_LL_GUARDSIZE)
            |                                |
            -------------------------------------------------
      iob   |            Reserved            |    io_len    |
            -------------------------------------------------

-------------------------------------------------------------
Layout of different NICs implementation:

        iob_data (aligned by CONFIG_IOB_ALIGNMENT)
            |
            |                 io_offset(CONFIG_NET_LL_GUARDSIZE)
            |                                |
            -------------------------------------------------
 Ethernet   |       Reserved    | ETH_HDRLEN |    io_len    |
            ---------------------------------|---------------
 8021Q      |   Reserved  | ETH_8021Q_HDRLEN |    io_len    |
            ---------------------------------|---------------
 ipforward  |            Reserved            |    io_len    |
            -------------------------------------------------

--------------------------------------------------------------------

2. Support iob offload to l2 driver to avoid unnecessary memory copy

Support send/receive iob vectors directly between the NICs and l3/l4
stack to avoid unnecessary memory copies, especially on hardware that
supports Scatter/gather, which can greatly improve performance.

new interface to support iob offload:

  ------------------------------------------
  |    IOB version     |     original      |
  |----------------------------------------|
  |  devif_iob_poll()  |   devif_poll()    |
  |       ...          |       ...         |
  ------------------------------------------

--------------------------------------------------------------------

1> NIC hardware support Scatter/gather transfer

TX:

                tcp_poll()/udp_poll()/pkt_poll()/...(l3|l4)
                           /              \
                          /                \
devif_poll_[l3|l4]_connections()     devif_iob_send() (nocopy:udp/icmp/...)
           /                                   \      (copy:tcp)
          /                                     \
  devif_iob_poll("NIC"_txpoll)                callback() // "NIC"_txpoll
                                                  |
                            dev->d_iob:           |
                                                ---------------         ---------------
                             io_data       iob1 |  |          |    iob3 |  |          |
                                    \           ---------------         ---------------
                                  ---------------  |       --------------- |
                             iob0 |  |          |  |  iob2 |  |          | |
                                  ---------------  |       --------------- |
                                     \             |          /           /
                                        \          |       /           /
                                   ----------------------------------------------
                    NICs io vector |    |    |    |    |    |    |    |    |    |
                                   ----------------------------------------------

RX:

  [tcp|udp|icmp|...]ipv[4|6]_data_handler()(iob_concat/append to readahead)
                    |
                    |
      [tcp|udp|icmp|...]_ipv[4|6]_in()/...
                    |
                    |
          pkt/ipv[4/6]_input()/...
                    |
                    |
     NICs io vector receive(iov_base to each iobs)

--------------------------------------------------------------------

2> CONFIG_IOB_BUFSIZE is greater than MTU:

TX:

"(CONFIG_IOB_BUFSIZE) > (MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE + CONFIG_NET_LL_GUARDSIZE)"

                tcp_poll()/udp_poll()/pkt_poll()/...(l3|l4)
                           /              \
                          /                \
devif_poll_[l3|l4]_connections()     devif_iob_send() (nocopy:udp/icmp/...)
           /                                   \      (copy:tcp)
          /                                     \
  devif_iob_poll("NIC"_txpoll)                callback() // "NIC"_txpoll
                                                  |
                                             "NIC"_send()
                          (dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE - NET_LL_HDRLEN(dev)])

RX:

  [tcp|udp|icmp|...]ipv[4|6]_data_handler()(iob_concat/append to readahead)
                    |
                    |
      [tcp|udp|icmp|...]_ipv[4|6]_in()/...
                    |
                    |
          pkt/ipv[4/6]_input()/...
                    |
                    |
     NICs io vector receive(iov_base to io_data)

--------------------------------------------------------------------

3> Compatible with all old flat buffer NICs

TX:
                tcp_poll()/udp_poll()/pkt_poll()/...(l3|l4)
                           /              \
                          /                \
devif_poll_[l3|l4]_connections()     devif_iob_send() (nocopy:udp/icmp/...)
           /                                   \      (copy:tcp)
          /                                     \
  devif_iob_poll(devif_poll_callback())  devif_poll_callback() /* new interface, gather iobs to flat buffer */
       /                                           \
      /                                             \
 devif_poll("NIC"_txpoll)                     "NIC"_send()(dev->d_buf)

RX:

  [tcp|udp|icmp|...]ipv[4|6]_data_handler()(iob_concat/append to readahead)
                    |
                    |
      [tcp|udp|icmp|...]_ipv[4|6]_in()/...
                    |
                    |
               netdev_input()  /* new interface, Scatter/gather flat/iob buffer */
                    |
                    |
          pkt/ipv[4|6]_input()/...
                    |
                    |
    NICs io vector receive(Orignal flat buffer)

3. Iperf passthrough on NuttX simulator:

  -------------------------------------------------
  |  Protocol      | Server | Client |            |
  |-----------------------------------------------|
  |  TCP           |  813   |   834  |  Mbits/sec |
  |  TCP(Offload)  | 1720   |  1100  |  Mbits/sec |
  |  UDP           |   22   |   757  |  Mbits/sec |
  |  UDP(Offload)  |   25   |  1250  |  Mbits/sec |
  -------------------------------------------------

Signed-off-by: chao an <anchao@xiaomi.com>
This commit is contained in:
chao an 2022-11-23 19:39:40 +08:00 committed by Xiang Xiao
parent c26fd6565d
commit 34d2cde8a8
59 changed files with 1766 additions and 913 deletions

View File

@ -72,6 +72,11 @@
#include "sim_internal.h"
#if CONFIG_IOB_BUFSIZE >= (MAX_NETDEV_PKTSIZE + \
CONFIG_NET_GUARDSIZE + CONFIG_NET_LL_GUARDSIZE)
# define SIM_NETDEV_IOB_OFFLOAD
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
@ -95,12 +100,23 @@ static struct net_driver_s g_sim_dev[CONFIG_SIM_NETDEV_NUMBER];
* Private Functions
****************************************************************************/
static void netdriver_reply(struct net_driver_s *dev)
static void netdriver_send(struct net_driver_s *dev)
{
int devidx = (intptr_t)dev->d_private;
#ifdef SIM_NETDEV_IOB_OFFLOAD
uint8_t *buf = &dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE -
NET_LL_HDRLEN(dev)];
#else
uint8_t *buf = dev->d_buf;
#endif
UNUSED(devidx);
sim_netdev_send(devidx, buf, dev->d_len);
}
static void netdriver_reply(struct net_driver_s *dev)
{
/* If the receiving resulted in data that should be sent out on
* the network, the field d_len is set to a value > 0.
*/
@ -110,7 +126,7 @@ static void netdriver_reply(struct net_driver_s *dev)
/* Send the packet */
NETDEV_TXPACKETS(dev);
sim_netdev_send(devidx, dev->d_buf, dev->d_len);
netdriver_send(dev);
NETDEV_TXDONE(dev);
}
}
@ -131,6 +147,14 @@ static void netdriver_recv_work(void *arg)
while (sim_netdev_avail(devidx))
{
#ifdef SIM_NETDEV_IOB_OFFLOAD
if (netdev_iob_prepare(dev, false, 0) != OK)
{
netdriver_txdone_interrupt(dev);
break;
}
#endif
/* sim_netdev_read will return 0 on a timeout event and > 0
* on a data received event
*/
@ -142,6 +166,10 @@ static void netdriver_recv_work(void *arg)
{
NETDEV_RXPACKETS(dev);
#ifdef SIM_NETDEV_IOB_OFFLOAD
iob_update_pktlen(dev->d_iob, dev->d_len - NET_LL_HDRLEN(dev));
#endif
/* Data received event. Check for valid Ethernet header with
* destination == our MAC address
*/
@ -208,7 +236,7 @@ static void netdriver_recv_work(void *arg)
if (dev->d_len > 0)
{
sim_netdev_send(devidx, dev->d_buf, dev->d_len);
netdriver_send(dev);
}
}
else
@ -224,6 +252,10 @@ static void netdriver_recv_work(void *arg)
NETDEV_RXERRORS(dev);
}
}
#ifdef SIM_NETDEV_IOB_OFFLOAD
netdev_iob_release(dev);
#endif
}
net_unlock();
@ -231,14 +263,10 @@ static void netdriver_recv_work(void *arg)
static int netdriver_txpoll(struct net_driver_s *dev)
{
int devidx = (intptr_t)dev->d_private;
UNUSED(devidx);
/* Send the packet */
NETDEV_TXPACKETS(dev);
sim_netdev_send(devidx, dev->d_buf, dev->d_len);
netdriver_send(dev);
NETDEV_TXDONE(dev);
/* If zero is returned, the polling will continue until all connections
@ -321,9 +349,8 @@ static void netdriver_rxready_interrupt(void *priv)
int sim_netdriver_init(void)
{
struct net_driver_s *dev;
void *pktbuf;
int pktsize;
int devidx;
for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++)
{
dev = &g_sim_dev[devidx];
@ -334,22 +361,19 @@ int sim_netdriver_init(void)
netdriver_txdone_interrupt,
netdriver_rxready_interrupt);
/* Update the buffer size */
pktsize = dev->d_pktsize ? dev->d_pktsize :
(MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE);
/* Allocate packet buffer */
pktbuf = kmm_malloc(pktsize);
if (pktbuf == NULL)
#ifndef SIM_NETDEV_IOB_OFFLOAD
dev->d_buf = kmm_malloc(dev->d_pktsize != 0 ?
dev->d_pktsize :
(MAX_NETDEV_PKTSIZE +
CONFIG_NET_GUARDSIZE));
if (dev->d_buf == NULL)
{
return -ENOMEM;
}
#endif
/* Set callbacks */
dev->d_buf = pktbuf;
dev->d_ifup = netdriver_ifup;
dev->d_ifdown = netdriver_ifdown;
dev->d_txavail = netdriver_txavail;

View File

@ -82,7 +82,6 @@ struct lo_driver_s
****************************************************************************/
static struct lo_driver_s g_loopback;
static uint8_t g_iobuffer[NET_LO_PKTSIZE + CONFIG_NET_GUARDSIZE];
/****************************************************************************
* Private Function Prototypes
@ -334,7 +333,6 @@ int localhost_initialize(void)
priv->lo_dev.d_addmac = lo_addmac; /* Add multicast MAC address */
priv->lo_dev.d_rmmac = lo_rmmac; /* Remove multicast MAC address */
#endif
priv->lo_dev.d_buf = g_iobuffer; /* Attach the IO buffer */
priv->lo_dev.d_private = priv; /* Used to recover private state from dev */
/* Register the loopabck device with the OS so that socket IOCTLs can b

View File

@ -127,7 +127,7 @@ struct iob_s
#if CONFIG_IOB_HEADSIZE > 0
uint8_t io_head[CONFIG_IOB_HEADSIZE];
#endif
uint8_t io_data[CONFIG_IOB_BUFSIZE];
uint8_t io_data[CONFIG_IOB_BUFSIZE] aligned_data(CONFIG_IOB_ALIGNMENT);
};
#if CONFIG_IOB_NCHAINS > 0

View File

@ -59,8 +59,11 @@
#include <net/ethernet.h>
#include <arpa/inet.h>
#include <nuttx/mm/iob.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/net.h>
#include <nuttx/net/ip.h>
#include <nuttx/nuttx.h>
#ifdef CONFIG_NET_IGMP
# include <nuttx/net/igmp.h>
@ -307,6 +310,20 @@ struct net_driver_s
net_ipv6addr_t d_ipv6draddr; /* Default router IPv6 address */
net_ipv6addr_t d_ipv6netmask; /* Network IPv6 subnet mask */
#endif
/* This is a new design that uses d_iob as packets input and output
* buffer which used by some NICs such as celluler net driver. Case for
* data input, note that d_iob maybe a linked chain only when using
* d_iob to store reassembled datagrams, otherwise d_iob uses only
* one buffer to hold the entire frame data. Case for data output, note
* that d_iob also maybe a linked chain only when using d_iob to
* store fragmented datagrams, otherwise d_iob uses only one buffer
* to hold the entire frame data.
*
* In all cases mentioned above, d_buf always points to the beginning
* of the first buffer of d_iob.
*/
FAR struct iob_s *d_iob;
/* The d_buf array is used to hold incoming and outgoing packets. The
* device driver should place incoming data into this buffer. When sending
@ -427,10 +444,6 @@ struct net_driver_s
typedef CODE int (*devif_poll_callback_t)(FAR struct net_driver_s *dev);
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
@ -560,6 +573,19 @@ int sixlowpan_input(FAR struct radio_driver_s *ieee,
* return 0;
* }
*
* Compatible with all old flat buffer NICs
*
* tcp_poll()/udp_poll()/pkt_poll()/...(l3/l4)
* / \
* / \
* devif_poll_[l3/l4]_connections() devif_iob_send() (nocopy:udp/icmp/..)
* / \ (copy:tcp)
* / \
* devif_iob_poll(devif_poll_callback()) devif_poll_callback()
* / \
* / \
* devif_poll("NIC"_txpoll) "NIC"_send()(dev->d_buf)
*
****************************************************************************/
int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback);
@ -640,6 +666,26 @@ int netdev_carrier_off(FAR struct net_driver_s *dev);
uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len);
/****************************************************************************
* Name: chksum_iob
*
* Description:
* Calculate the Internet checksum over an iob chain buffer.
*
* Input Parameters:
* sum - Partial calculations carried over from a previous call to
* chksum(). This should be zero on the first time that check
* sum is called.
* iob - An iob chain buffer over which the checksum is to be computed.
* offset - Specifies the byte offset of the start of valid data.
*
* Returned Value:
* The updated checksum value.
*
****************************************************************************/
uint16_t chksum_iob(uint16_t sum, FAR struct iob_s *iob, uint16_t offset);
/****************************************************************************
* Name: net_chksum
*
@ -668,6 +714,35 @@ uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len);
uint16_t net_chksum(FAR uint16_t *data, uint16_t len);
/****************************************************************************
* Name: net_chksum_iob
*
* Description:
* Calculate the Internet checksum over an iob chain buffer.
*
* The Internet checksum is the one's complement of the one's complement
* sum of all 16-bit words in the buffer.
*
* See RFC1071.
*
* If CONFIG_NET_ARCH_CHKSUM is defined, then this function must be
* provided by architecture-specific logic.
*
* Input Parameters:
* sum - Partial calculations carried over from a previous call to
* chksum(). This should be zero on the first time that check
* sum is called.
* iob - An iob chain buffer over which the checksum is to be computed.
* offset - Specifies the byte offset of the start of valid data.
*
* Returned Value:
* The Internet checksum of the given iob chain buffer.
*
****************************************************************************/
uint16_t net_chksum_iob(uint16_t sum, FAR struct iob_s *iob,
uint16_t offset);
/****************************************************************************
* Name: ipv4_upperlayer_chksum
*
@ -802,4 +877,54 @@ void net_incr32(FAR uint8_t *op32, uint16_t op16);
int netdev_lladdrsize(FAR struct net_driver_s *dev);
/****************************************************************************
* Name: netdev_iob_prepare
*
* Description:
* Prepare data buffer for a given NIC
* The iob offset will be updated to l2 gruard size by default:
* ----------------------------------------------------------------
* | iob entry |
* ---------------------------------------------------------------|
* |<--- CONFIG_NET_LL_GUARDSIZE -->|<--- io_len/io_pktlen(0) --->|
* ---------------------------------------------------------------|
*
* Assumptions:
* The caller has locked the network.
*
* Returned Value:
* A non-zero copy is returned on success.
*
****************************************************************************/
int netdev_iob_prepare(FAR struct net_driver_s *dev, bool throttled,
unsigned int timeout);
/****************************************************************************
* Name: netdev_iob_clear
*
* Description:
* Clean up buffer resources for a given NIC
*
* Assumptions:
* The caller has locked the network and dev->d_iob has been
* released or taken away.
*
****************************************************************************/
void netdev_iob_clear(FAR struct net_driver_s *dev);
/****************************************************************************
* Name: netdev_iob_release
*
* Description:
* Release buffer resources for a given NIC
*
* Assumptions:
* The caller has locked the network.
*
****************************************************************************/
void netdev_iob_release(FAR struct net_driver_s *dev);
#endif /* __INCLUDE_NUTTX_NET_NETDEV_H */

View File

@ -41,7 +41,7 @@ config IOB_HEADSIZE
config IOB_ALIGNMENT
int "Alignment size of each I/O buffer"
default 1
default 4
---help---
The member io_head of all I/O buffers is aligned to the value
specified by this configuration.

View File

@ -117,6 +117,15 @@ config NET_GUARDSIZE
packet size will be chopped down to the size indicated in the TCP
header.
config NET_LL_GUARDSIZE
int "Data Link Layer(L2) Guard size of Network buffer(IOB)"
default 14 if NET_ETHERNET
default 0
---help---
This is reserved l2 buffer header size of network buffer to isolate
the L2/L3 (MAC/IP) data on Network layer, which will be beneficial
to L3 network layer protocol transparent transmission and forwarding
config NET_RECV_BUFSIZE
int "Net Receive buffer size"
default 0

View File

@ -97,6 +97,10 @@ void arp_format(FAR struct net_driver_s *dev, in_addr_t ipaddr)
eth->type = HTONS(ETHTYPE_ARP);
dev->d_len = sizeof(struct arp_hdr_s) + ETH_HDRLEN;
/* Update device buffer length */
iob_update_pktlen(dev->d_iob, sizeof(struct arp_hdr_s));
}
#endif /* CONFIG_NET_ARP */

View File

@ -209,10 +209,8 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
* receive the data.
*
* Input Parameters:
* dev - The device which as active when the event was detected.
* conn - A pointer to the CAN connection structure
* buffer - A pointer to the buffer to be copied to the read-ahead
* buffers
* buflen - The number of bytes to copy to the read-ahead buffer.
*
* Returned Value:
* The number of bytes actually buffered is returned. This will be either
@ -225,8 +223,8 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
*
****************************************************************************/
uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
uint16_t buflen);
uint16_t can_datahandler(FAR struct net_driver_s *dev,
FAR struct can_conn_s *conn);
/****************************************************************************
* Name: can_recvmsg

View File

@ -61,10 +61,9 @@ static inline uint16_t
can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn,
uint16_t flags)
{
uint16_t ret;
FAR uint8_t *buffer = dev->d_appdata;
int buflen = dev->d_len;
uint16_t recvlen;
uint16_t ret;
ret = (flags & ~CAN_NEWDATA);
@ -72,7 +71,7 @@ can_data_event(FAR struct net_driver_s *dev, FAR struct can_conn_s *conn,
* partial packets will not be buffered.
*/
recvlen = can_datahandler(conn, buffer, buflen);
recvlen = can_datahandler(dev, conn);
if (recvlen < buflen)
{
/* There is no handler to receive new data and there are no free
@ -120,21 +119,6 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
if (conn)
{
#ifdef CONFIG_NET_TIMESTAMP
/* TIMESTAMP sockopt is activated, create timestamp and copy to iob */
if (conn->timestamp)
{
struct timespec *ts = (struct timespec *)
&dev->d_appdata[dev->d_len];
struct timeval *tv = (struct timeval *)
&dev->d_appdata[dev->d_len];
dev->d_len += sizeof(struct timeval);
clock_systime_timespec(ts);
tv->tv_usec = ts->tv_nsec / 1000;
}
#endif
/* Try to lock the network when successful send data to the listener */
if (net_trylock() == OK)
@ -149,6 +133,34 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
if ((flags & CAN_NEWDATA) != 0)
{
#ifdef CONFIG_NET_TIMESTAMP
/* TIMESTAMP sockopt is activated,
* create timestamp and copy to iob
*/
if (conn->timestamp)
{
struct timeval tv;
FAR struct timespec *ts = (FAR struct timespec *)&tv;
int len;
clock_systime_timespec(ts);
tv.tv_usec = ts->tv_nsec / 1000;
len = iob_trycopyin(dev->d_iob, (FAR uint8_t *)&tv,
sizeof(struct timeval), 0, false);
if (len != sizeof(struct timeval))
{
dev->d_len = 0;
return flags & ~CAN_NEWDATA;
}
else
{
dev->d_len += len;
}
}
#endif
/* Data was not handled.. dispose of it appropriately */
flags = can_data_event(dev, conn, flags);
@ -168,10 +180,8 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
* receive the data.
*
* Input Parameters:
* dev - The device which as active when the event was detected.
* conn - A pointer to the CAN connection structure
* buffer - A pointer to the buffer to be copied to the read-ahead
* buffers
* buflen - The number of bytes to copy to the read-ahead buffer.
*
* Returned Value:
* The number of bytes actually buffered is returned. This will be either
@ -184,58 +194,28 @@ uint16_t can_callback(FAR struct net_driver_s *dev,
*
****************************************************************************/
uint16_t can_datahandler(FAR struct can_conn_s *conn, FAR uint8_t *buffer,
uint16_t buflen)
uint16_t can_datahandler(FAR struct net_driver_s *dev,
FAR struct can_conn_s *conn)
{
FAR struct iob_s *iob;
FAR struct iob_s *iob = dev->d_iob;
int ret;
/* Try to allocate on I/O buffer to start the chain without waiting (and
* throttling as necessary). If we would have to wait, then drop the
* packet.
*/
iob = iob_tryalloc(true);
if (iob == NULL)
{
nerr("ERROR: Failed to create new I/O buffer chain\n");
return 0;
}
/* Copy the new appdata into the I/O buffer chain (without waiting) */
ret = iob_trycopyin(iob, buffer, buflen, 0, true);
if (ret < 0)
{
/* On a failure, iob_copyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
iob_free_chain(iob);
return 0;
}
/* Add the new I/O buffer chain to the tail of the read-ahead queue (again
* without waiting).
*/
/* Concat the iob to readahead */
ret = iob_tryadd_queue(iob, &conn->readahead);
if (ret < 0)
if (ret >= 0)
{
nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
iob_free_chain(iob);
return 0;
#ifdef CONFIG_NET_CAN_NOTIFIER
/* Provide notification(s) that additional CAN read-ahead data is
* available.
*/
can_readahead_signal(conn);
#endif
ret = iob->io_pktlen;
}
#ifdef CONFIG_NET_CAN_NOTIFIER
/* Provide notification(s) that additional CAN read-ahead data is
* available.
*/
can_readahead_signal(conn);
#endif
return buflen;
return ret;
}
#endif /* CONFIG_NET && CONFIG_NET_CAN */

View File

@ -120,8 +120,9 @@ static inline void can_add_recvlen(FAR struct can_recvfrom_s *pstate,
****************************************************************************/
static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev,
FAR struct can_recvfrom_s *pstate)
FAR struct can_recvfrom_s *pstate)
{
unsigned int offset;
size_t recvlen;
if (dev->d_len > pstate->pr_buflen)
@ -135,7 +136,13 @@ static size_t can_recvfrom_newdata(FAR struct net_driver_s *dev,
/* Copy the new packet data into the user buffer */
memcpy(pstate->pr_buffer, dev->d_buf, recvlen);
offset = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset;
recvlen = iob_copyout(pstate->pr_buffer, dev->d_iob, recvlen, offset);
/* Trim the copied buffers */
dev->d_iob = iob_trimhead(dev->d_iob, recvlen + offset);
/* Update the accumulated size of the data read */
@ -175,34 +182,7 @@ static inline void can_newdata(FAR struct net_driver_s *dev,
if (recvlen < dev->d_len)
{
FAR struct can_conn_s *conn = pstate->pr_conn;
FAR uint8_t *buffer = dev->d_appdata + recvlen;
uint16_t buflen = dev->d_len - recvlen;
#ifdef CONFIG_DEBUG_NET
uint16_t nsaved;
nsaved = can_datahandler(conn, buffer, buflen);
#else
can_datahandler(conn, buffer, buflen);
#endif
/* There are complicated buffering issues that are not addressed fully
* here. For example, what if up_datahandler() cannot buffer the
* remainder of the packet? In that case, the data will be dropped but
* still ACKed. Therefore it would not be resent.
*
* This is probably not an issue here because we only get here if the
* read-ahead buffers are empty and there would have to be something
* serioulsy wrong with the configuration not to be able to buffer a
* partial packet in this context.
*/
#ifdef CONFIG_DEBUG_NET
if (nsaved < buflen)
{
nerr("ERROR: packet data not saved (%d bytes)\n", buflen - nsaved);
}
#endif
can_datahandler(dev, pstate->pr_conn);
}
/* Indicate no data in the buffer */

View File

@ -20,39 +20,44 @@
# Network device interface source files
NET_CSRCS += devif_initialize.c devif_send.c devif_poll.c devif_callback.c
NET_CSRCS += devif_loopback.c
NET_CSRCS += devif_initialize.c devif_callback.c
# Device driver IP packet receipt interfaces
ifeq ($(CONFIG_NET_IPv4),y)
NET_CSRCS += ipv4_input.c
endif
ifeq ($(CONFIG_NET_IPv6),y)
NET_CSRCS += ipv6_input.c
endif
# IP forwarding
ifeq ($(CONFIG_NET_IPFORWARD),y)
NET_CSRCS += devif_forward.c
endif
# I/O buffer chain support required?
ifeq ($(CONFIG_MM_IOB),y)
NET_CSRCS += devif_iobsend.c
endif
# Raw packet socket support
# IP packet
ifeq ($(CONFIG_NET_PKT),y)
NET_CSRCS += devif_pktsend.c
endif
NET_CSRCS += devif_send.c devif_loopback.c
ifeq ($(CONFIG_NET_CAN),y)
NET_CSRCS += devif_cansend.c
ifeq ($(CONFIG_NET_IPv4),y)
NET_CSRCS += ipv4_input.c
endif
ifeq ($(CONFIG_NET_IPv6),y)
NET_CSRCS += ipv6_input.c
endif
# IP forwarding
ifeq ($(CONFIG_NET_IPFORWARD),y)
NET_CSRCS += devif_forward.c
endif
# I/O buffer chain support required?
NET_CSRCS += devif_poll.c
NET_CSRCS += devif_iobsend.c
# Raw packet socket support
ifeq ($(CONFIG_NET_PKT),y)
NET_CSRCS += devif_pktsend.c
endif
ifeq ($(CONFIG_NET_CAN),y)
NET_CSRCS += devif_cansend.c
endif
endif
# Include network device interface build support

View File

@ -449,7 +449,8 @@ uint16_t devif_dev_event(FAR struct net_driver_s *dev, uint16_t flags);
*
****************************************************************************/
void devif_send(FAR struct net_driver_s *dev, FAR const void *buf, int len);
void devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
int len, unsigned int offset);
/****************************************************************************
* Name: devif_iob_send
@ -469,7 +470,8 @@ void devif_send(FAR struct net_driver_s *dev, FAR const void *buf, int len);
#ifdef CONFIG_MM_IOB
struct iob_s;
void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *buf,
unsigned int len, unsigned int offset);
unsigned int len, unsigned int offset,
unsigned int target_offset);
#endif
/****************************************************************************
@ -560,6 +562,40 @@ int devif_poll_out(FAR struct net_driver_s *dev,
int devif_loopback(FAR struct net_driver_s *dev);
/****************************************************************************
* Name: netdev_input
*
* Description:
* This function will copy the flat buffer that does not support
* Scatter/gather to the iob vector buffer.
*
* Compatible with all old flat buffer NICs:
*
* [tcp|udp|icmp|...]ipv[4|6]_data_handler()
* | (iob_concat/append to readahead)
* |
* pkt/ipv[4/6]_in()/...
* |
* |
* netdev_input() // new interface, Scatter/gather flat/iobs
* |
* |
* pkt/ipv[4|6]_input()/...
* |
* |
* NICs io vector receive(Orignal flat buffer)
*
* Input Parameters:
* callback - Input callback of L3 stack
*
* Returned Value:
* A non-zero copy is returned on success.
*
****************************************************************************/
int netdev_input(FAR struct net_driver_s *dev,
devif_poll_callback_t callback, bool reply);
#undef EXTERN
#ifdef __cplusplus
}

View File

@ -32,34 +32,6 @@
#if defined(CONFIG_NET_CAN)
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Public Constant Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Constant Data
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
@ -83,16 +55,25 @@
void devif_can_send(FAR struct net_driver_s *dev, FAR const void *buf,
unsigned int len)
{
DEBUGASSERT(dev && len > 0 && len <= NETDEV_PKTSIZE(dev));
unsigned int limit = NETDEV_PKTSIZE(dev) -
CONFIG_NET_LL_GUARDSIZE;
/* Copy the data into the device packet buffer */
if (dev == NULL || len == 0 || len > limit)
{
nerr("ERROR: devif_pkt_send fail: %p, sndlen: %u, pktlen: %u\n",
dev, len, limit);
return;
}
memcpy(dev->d_buf, buf, len);
iob_update_pktlen(dev->d_iob, 0);
/* Set the number of bytes to send */
/* Copy the data into the device packet buffer and set the number of
* bytes to send
*/
dev->d_len = len;
dev->d_sndlen = len;
dev->d_sndlen = iob_copyin(dev->d_iob, buf, len, 0, false) == len ?
len : 0;
dev->d_len = dev->d_sndlen;
}
#endif /* CONFIG_NET_CAN */

View File

@ -53,19 +53,78 @@
****************************************************************************/
void devif_iob_send(FAR struct net_driver_s *dev, FAR struct iob_s *iob,
unsigned int len, unsigned int offset)
unsigned int len, unsigned int offset,
unsigned int target_offset)
{
if (dev == NULL || len == 0 || len >= NETDEV_PKTSIZE(dev))
unsigned int limit = NETDEV_PKTSIZE(dev) -
NET_LL_HDRLEN(dev) - target_offset;
unsigned int copyin;
int ret;
if (dev == NULL || len == 0 || len > limit)
{
nerr("devif_iob_send error, %p, send len: %u, pkt len: %u\n",
dev, len, NETDEV_PKTSIZE(dev));
if (dev->d_iob == NULL)
{
iob_free_chain(iob);
}
nerr("devif_iob_send error, %p, send len: %u, limit len: %u\n",
dev, len, limit);
return;
}
/* Copy the data from the I/O buffer chain to the device buffer */
/* Append the send buffer after device buffer */
iob_copyout(dev->d_appdata, iob, len, offset);
dev->d_sndlen = len;
if (dev->d_iob != NULL)
{
/* Skip the l3/l4 offset before append */
iob_update_pktlen(dev->d_iob, target_offset);
/* Skip to the I/O buffer containing the data offset */
while (iob != NULL && offset > iob->io_len)
{
offset -= iob->io_len;
iob = iob->io_flink;
}
dev->d_sndlen = len;
/* Clone the iob to target device buffer */
while (iob != NULL && len > 0)
{
copyin = (len > iob->io_len - offset) ?
iob->io_len - offset : len;
ret = iob_copyin(dev->d_iob, iob->io_data +
iob->io_offset + offset,
copyin, target_offset, false);
if (ret != copyin)
{
netdev_iob_release(dev);
dev->d_sndlen = 0;
nerr("devif_iob_send error, not enough iob entries, "
"send len: %u\n", len);
return;
}
target_offset += copyin;
len -= copyin;
offset = 0;
iob = iob->io_flink;
}
}
else
{
/* Send the iob directly if no device buffer */
dev->d_iob = iob;
dev->d_sndlen = len;
dev->d_buf = &iob->io_data[CONFIG_NET_LL_GUARDSIZE -
NET_LL_HDRLEN(dev)];
}
#ifdef CONFIG_NET_TCP_WRBUFFER_DUMP
/* Dump the outgoing device buffer */

View File

@ -31,6 +31,17 @@
#include <nuttx/net/pkt.h>
#include <nuttx/net/netdev.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* This is a helper pointer for accessing the contents of the ip header */
#define LOIPv4BUF ((FAR struct ipv4_hdr_s *) \
&dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE])
#define LOIPv6BUF ((FAR struct ipv6_hdr_s *) \
&dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE])
/****************************************************************************
* Private Functions
****************************************************************************/
@ -40,16 +51,16 @@ static bool is_loopback(FAR struct net_driver_s *dev)
if (dev->d_len > 0)
{
#ifdef CONFIG_NET_IPv4
if ((IPv4BUF->vhl & IP_VERSION_MASK) == IPv4_VERSION &&
net_ipv4addr_hdrcmp(IPv4BUF->destipaddr, &dev->d_ipaddr))
if ((LOIPv4BUF->vhl & IP_VERSION_MASK) == IPv4_VERSION &&
net_ipv4addr_hdrcmp(LOIPv4BUF->destipaddr, &dev->d_ipaddr))
{
return true;
}
#endif
#ifdef CONFIG_NET_IPv6
if ((IPv6BUF->vtc & IP_VERSION_MASK) == IPv6_VERSION &&
net_ipv6addr_hdrcmp(IPv6BUF->destipaddr, dev->d_ipv6addr))
if ((LOIPv6BUF->vtc & IP_VERSION_MASK) == IPv6_VERSION &&
net_ipv6addr_hdrcmp(LOIPv6BUF->destipaddr, dev->d_ipv6addr))
{
return true;
}
@ -99,7 +110,7 @@ int devif_loopback(FAR struct net_driver_s *dev)
/* We only accept IP packets of the configured type */
#ifdef CONFIG_NET_IPv4
if ((IPv4BUF->vhl & IP_VERSION_MASK) == IPv4_VERSION)
if ((LOIPv4BUF->vhl & IP_VERSION_MASK) == IPv4_VERSION)
{
ninfo("IPv4 frame\n");
@ -109,7 +120,7 @@ int devif_loopback(FAR struct net_driver_s *dev)
else
#endif
#ifdef CONFIG_NET_IPv6
if ((IPv6BUF->vtc & IP_VERSION_MASK) == IPv6_VERSION)
if ((LOIPv6BUF->vtc & IP_VERSION_MASK) == IPv6_VERSION)
{
ninfo("IPv6 frame\n");

View File

@ -32,34 +32,6 @@
#ifdef CONFIG_NET_PKT
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Type Declarations
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/****************************************************************************
* Public Constant Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Constant Data
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
@ -83,16 +55,25 @@
void devif_pkt_send(FAR struct net_driver_s *dev, FAR const void *buf,
unsigned int len)
{
DEBUGASSERT(dev && len > 0 && len < NETDEV_PKTSIZE(dev));
unsigned int limit = NETDEV_PKTSIZE(dev) -
CONFIG_NET_LL_GUARDSIZE;
/* Copy the data into the device packet buffer */
if (dev == NULL || len == 0 || len > limit)
{
nerr("ERROR: devif_pkt_send fail: %p, sndlen: %u, pktlen: %u\n",
dev, len, limit);
return;
}
memcpy(dev->d_buf, buf, len);
iob_update_pktlen(dev->d_iob, 0);
/* Set the number of bytes to send */
/* Copy the data into the device packet buffer and set the number of
* bytes to send
*/
dev->d_len = len;
dev->d_sndlen = len;
dev->d_sndlen = iob_copyin(dev->d_iob, buf, len, 0, false) == len ?
len : 0;
dev->d_len = dev->d_sndlen;
}
#endif /* CONFIG_NET_PKT */

View File

@ -618,11 +618,7 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev,
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: devif_poll
* Name: devif_poll_connections
*
* Description:
* This function will traverse each active network connection structure and
@ -646,9 +642,10 @@ static inline int devif_poll_tcp_connections(FAR struct net_driver_s *dev,
*
****************************************************************************/
int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
static int devif_poll_connections(FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
int bstop = false;
int bstop;
/* Traverse all of the active packet connections and perform the poll
* action.
@ -772,6 +769,217 @@ int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
return bstop;
}
/****************************************************************************
* Name: devif_iob_poll
*
* Description:
* This function will traverse each active network connection structure and
* will perform network polling operations. devif_poll() may be called
* asynchronously with the network driver can accept another outgoing
* packet.
*
* This function will call the provided callback function for every active
* connection. Polling will continue until all connections have been polled
* or until the user-supplied function returns a non-zero value (which it
* should do only if it cannot accept further write data).
*
* When the callback function is called, there may be an outbound packet
* waiting for service in the device packet buffer, and if so the d_len
* field is set to a value larger than zero. The device driver should then
* send out the packet.
*
* This is the iob buffer version of devif_input(),
* this function will support send/receive iob vectors directly between
* the driver and l3/l4 stack to avoid unnecessary memory copies,
* especially on hardware that supports Scatter/gather, which can
* greatly improve performance
* this function will uses d_iob as packets input which used by some
* NICs such as celluler net driver.
*
* If NIC hardware support Scatter/gather transfer
*
* tcp_poll()/udp_poll()/pkt_poll()/...(l3/l4)
* / \
* / \
* devif_poll_[l3|l4]_connections() devif_iob_send() (nocopy:udp/icmp/...)
* / \ (copy:tcp)
* / \
* devif_iob_poll("NIC"_txpoll) callback() // "NIC"_txpoll
*
*
* Assumptions:
* This function is called from the MAC device driver with the network
* locked.
*
****************************************************************************/
static int devif_iob_poll(FAR struct net_driver_s *dev,
devif_poll_callback_t callback)
{
int bstop;
/* Device polling, prepare iob buffer */
if (netdev_iob_prepare(dev, false, 0) != OK)
{
return true;
}
/* Perform all connections poll */
bstop = devif_poll_connections(dev, callback);
/* Device polling completed, release iob */
netdev_iob_release(dev);
dev->d_buf = NULL;
return bstop;
}
/****************************************************************************
* Name: devif_poll_callback
*
* Description:
* This function will help us to gather multiple iob memory slices into a
* linear device buffer. if devices with small memory, this function will
* trigger a memory copy if net device start transmit the iob slices to
* flat buffer
*
****************************************************************************/
static int devif_poll_callback(FAR struct net_driver_s *dev)
{
if (dev->d_len > 0)
{
return true;
}
return false;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: devif_poll
*
* Description:
* This function will traverse each active network connection structure and
* will perform network polling operations. devif_poll() may be called
* asynchronously with the network driver can accept another outgoing
* packet.
*
* This function will call the provided callback function for every active
* connection. Polling will continue until all connections have been polled
* or until the user-supplied function returns a non-zero value (which it
* should do only if it cannot accept further write data).
*
* When the callback function is called, there may be an outbound packet
* waiting for service in the device packet buffer, and if so the d_len
* field is set to a value larger than zero. The device driver should then
* send out the packet.
*
* Compatible with all old flat buffer NICs
*
* tcp_poll()/udp_poll()/pkt_poll()/...(l3|l4)
* / \
* / \
* devif_poll_[l3|l4]_connections() devif_iob_send() (nocopy:udp/icmp/..)
* / \ (copy:tcp)
* / \
* devif_iob_poll(devif_poll_callback()) devif_poll_callback()
* / \
* / \
* devif_poll("NIC"_txpoll) "NIC"_send()(dev->d_buf)
*
*
* Assumptions:
* This function is called from the MAC device driver with the network
* locked.
*
****************************************************************************/
int devif_poll(FAR struct net_driver_s *dev, devif_poll_callback_t callback)
{
uint16_t llhdrlen;
int bstop = false;
FAR uint8_t *buf;
if (dev->d_buf == NULL)
{
return devif_iob_poll(dev, callback);
}
buf = dev->d_buf;
/* Device polling, prepare iob buffer */
if (netdev_iob_prepare(dev, false, 0) != OK)
{
return true;
}
llhdrlen = NET_LL_HDRLEN(dev);
do
{
/* Perform all connections poll */
bstop = devif_poll_connections(dev, devif_poll_callback);
if (dev->d_len > 0)
{
/* Copy iob to flat buffer */
iob_copyout(buf + llhdrlen,
dev->d_iob, dev->d_len, 0);
/* Copy l2 header (arp out) */
memcpy(buf, dev->d_iob->io_data +
(CONFIG_NET_LL_GUARDSIZE - llhdrlen), llhdrlen);
/* Restore flat buffer pointer */
dev->d_buf = buf;
/* Call the real device callback */
bstop = callback(dev);
/* Flat buffer changed by NIC ? */
if (dev->d_buf != buf)
{
if (dev->d_buf == NULL)
{
break;
}
buf = dev->d_buf;
}
/* Finish copy, reset iob */
netdev_iob_prepare(dev, false, 0);
iob_update_pktlen(dev->d_iob, 0);
}
}
while (bstop);
/* Device polling completed, release iob */
netdev_iob_release(dev);
/* Restore the flat buffer */
dev->d_buf = buf;
return bstop;
}
/****************************************************************************
* Name: devif_out
*

View File

@ -65,10 +65,23 @@
*
****************************************************************************/
void devif_send(struct net_driver_s *dev, const void *buf, int len)
void devif_send(FAR struct net_driver_s *dev, FAR const void *buf,
int len, unsigned int offset)
{
DEBUGASSERT(dev != NULL && len > 0 && len < NETDEV_PKTSIZE(dev));
unsigned int limit = NETDEV_PKTSIZE(dev) -
CONFIG_NET_LL_GUARDSIZE - offset;
memcpy(dev->d_appdata, buf, len);
dev->d_sndlen = len;
if (dev == NULL || len == 0 || len > limit)
{
nerr("ERROR: devif_send fail: %p, sndlen: %u, pktlen: %u\n",
dev, len, limit);
return;
}
iob_update_pktlen(dev->d_iob, offset);
/* Copy in iob to target device buffer */
dev->d_sndlen = iob_copyin(dev->d_iob, buf, len, offset, false) == len ?
len : 0;
}

View File

@ -116,13 +116,23 @@
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ipv4_input
* Name: ipv4_in
*
* Description:
* Receive an IPv4 packet from the network device. Verify and forward to
* L3 packet handling logic if the packet is destined for us.
*
* This is the iob buffer version of ipv4_input(),
* this function will support send/receive iob vectors directly between
* the driver and l3/l4 stack to avoid unnecessary memory copies,
* especially on hardware that supports Scatter/gather, which can
* greatly improve performance
* this function will uses d_iob as packets input which used by some
* NICs such as celluler net driver.
*
* Input Parameters:
* dev - The device on which the packet was received and which contains
* the IPv4 packet.
*
* Returned Value:
* OK - The packet was processed (or dropped) and can be discarded.
@ -133,11 +143,10 @@
*
****************************************************************************/
int ipv4_input(FAR struct net_driver_s *dev)
static int ipv4_in(FAR struct net_driver_s *dev)
{
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
in_addr_t destipaddr;
uint16_t llhdrlen;
uint16_t totlen;
int ret = OK;
@ -175,15 +184,12 @@ int ipv4_input(FAR struct net_driver_s *dev)
/* Get the size of the packet minus the size of link layer header */
llhdrlen = NET_LL_HDRLEN(dev);
if ((llhdrlen + IPv4_HDRLEN) > dev->d_len)
if (IPv4_HDRLEN > dev->d_len)
{
nwarn("WARNING: Packet shorter than IPv4 header\n");
goto drop;
}
dev->d_len -= llhdrlen;
/* Make sure that all packet processing logic knows that there is an IPv4
* packet in the device buffer.
*/
@ -198,11 +204,12 @@ int ipv4_input(FAR struct net_driver_s *dev)
*/
totlen = (ipv4->len[0] << 8) + ipv4->len[1];
if (totlen <= dev->d_len)
if (totlen < dev->d_len)
{
iob_update_pktlen(dev->d_iob, totlen);
dev->d_len = totlen;
}
else
else if (totlen > dev->d_len)
{
nwarn("WARNING: IP packet shorter than length in IP header\n");
goto drop;
@ -420,4 +427,52 @@ drop:
dev->d_len = 0;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ipv4_input
*
* Description:
* Receive an IPv4 packet from the network device. Verify and forward to
* L3 packet handling logic if the packet is destined for us.
*
* Input Parameters:
* dev - The device on which the packet was received and which contains
* the IPv4 packet.
*
* Returned Value:
* OK - The packet was processed (or dropped) and can be discarded.
* ERROR - Hold the packet and try again later. There is a listening
* socket but no receive in place to catch the packet yet. The
* device's d_len will be set to zero in this case as there is
* no outgoing data.
*
****************************************************************************/
int ipv4_input(FAR struct net_driver_s *dev)
{
FAR uint8_t *buf;
int ret;
if (dev->d_iob != NULL)
{
buf = dev->d_buf;
/* Set the device buffer to l2 */
dev->d_buf = &dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE -
NET_LL_HDRLEN(dev)];
ret = ipv4_in(dev);
dev->d_buf = buf;
return ret;
}
return netdev_input(dev, ipv4_in, true);
}
#endif /* CONFIG_NET_IPv4 */

View File

@ -185,16 +185,20 @@ static bool check_destipaddr(FAR struct net_driver_s *dev,
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ipv6_input
* Name: ipv6_in
*
* Description:
* Receive an IPv6 packet from the network device. Verify and forward to
* L3 packet handling logic if the packet is destined for us.
*
* This is the iob buffer version of ipv6_input(),
* this function will support send/receive iob vectors directly between
* the driver and l3/l4 stack to avoid unnecessary memory copies,
* especially on hardware that supports Scatter/gather, which can
* greatly improve performance
* this function will uses d_iob as packets input which used by some
* NICs such as celluler net driver.
*
* Input Parameters:
* dev - The device on which the packet was received and which contains
* the IPv6 packet.
@ -214,11 +218,10 @@ static bool check_destipaddr(FAR struct net_driver_s *dev,
*
****************************************************************************/
int ipv6_input(FAR struct net_driver_s *dev)
static int ipv6_in(FAR struct net_driver_s *dev)
{
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
FAR uint8_t *payload;
uint16_t llhdrlen;
uint16_t iphdrlen;
uint16_t paylen;
uint8_t nxthdr;
@ -251,15 +254,12 @@ int ipv6_input(FAR struct net_driver_s *dev)
/* Get the size of the packet minus the size of link layer header */
llhdrlen = NET_LL_HDRLEN(dev);
if ((llhdrlen + IPv6_HDRLEN) > dev->d_len)
if (IPv6_HDRLEN > dev->d_len)
{
nwarn("WARNING: Packet shorter than IPv6 header\n");
goto drop;
}
dev->d_len -= llhdrlen;
/* Make sure that all packet processing logic knows that there is an IPv6
* packet in the device buffer.
*/
@ -287,11 +287,12 @@ int ipv6_input(FAR struct net_driver_s *dev)
paylen = ((uint16_t)ipv6->len[0] << 8) + (uint16_t)ipv6->len[1] +
IPv6_HDRLEN;
if (paylen <= dev->d_len)
if (paylen < dev->d_len)
{
iob_update_pktlen(dev->d_iob, paylen);
dev->d_len = paylen;
}
else
else if (paylen > dev->d_len)
{
nwarn("WARNING: IP packet shorter than length in IP header\n");
goto drop;
@ -525,4 +526,57 @@ drop:
dev->d_len = 0;
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ipv6_input
*
* Description:
* Receive an IPv6 packet from the network device. Verify and forward to
* L3 packet handling logic if the packet is destined for us.
*
* Input Parameters:
* dev - The device on which the packet was received and which contains
* the IPv6 packet.
* Returned Value:
* OK - The packet was processed (or dropped) and can be discarded.
* ERROR - Hold the packet and try again later. There is a listening
* socket but no receive in place to catch the packet yet. The
* device's d_len will be set to zero in this case as there is
* no outgoing data.
*
* If this function returns to the network driver with dev->d_len > 0,
* that is an indication to the driver that there is an outgoing response
* to this input.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
int ipv6_input(FAR struct net_driver_s *dev)
{
FAR uint8_t *buf;
int ret;
if (dev->d_iob != NULL)
{
buf = dev->d_buf;
/* Set the device buffer to l2 */
dev->d_buf = &dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE -
NET_LL_HDRLEN(dev)];
ret = ipv6_in(dev);
dev->d_buf = buf;
return ret;
}
return netdev_input(dev, ipv6_in, true);
}
#endif /* CONFIG_NET_IPv6 */

View File

@ -100,28 +100,14 @@ static uint16_t icmp_datahandler(FAR struct net_driver_s *dev,
FAR struct ipv4_hdr_s *ipv4;
struct sockaddr_in inaddr;
FAR struct iob_s *iob;
uint16_t offset;
uint16_t buflen;
uint16_t iphdrlen;
uint8_t addrsize;
uint16_t buflen;
int ret;
/* Try to allocate on I/O buffer to start the chain without waiting (and
* throttling as necessary). If we would have to wait, then drop the
* packet.
*/
iob = iob_tryalloc(true);
if (iob == NULL)
{
nerr("ERROR: Failed to create new I/O buffer chain\n");
goto drop;
}
/* Put the IPv4 address at the beginning of the read-ahead buffer */
ipv4 = IPv4BUF;
iob = dev->d_iob;
ipv4 = IPv4BUF;
inaddr.sin_family = AF_INET;
inaddr.sin_port = 0;
@ -129,57 +115,23 @@ static uint16_t icmp_datahandler(FAR struct net_driver_s *dev,
net_ip4addr_conv32(ipv4->srcipaddr));
memset(inaddr.sin_zero, 0, sizeof(inaddr.sin_zero));
/* Copy the src address info into the I/O buffer chain. We will not wait
* for an I/O buffer to become available in this context. It there is
* any failure to allocated, the entire I/O buffer chain will be discarded.
*/
addrsize = sizeof(struct sockaddr_in);
ret = iob_trycopyin(iob, &addrsize, sizeof(uint8_t), 0, true);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to length to the I/O buffer chain: %d\n", ret);
goto drop_with_chain;
}
offset = sizeof(uint8_t);
ret = iob_trycopyin(iob, (FAR const uint8_t *)&inaddr,
sizeof(struct sockaddr_in), offset, true);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to source address to the I/O buffer chain: %d\n",
ret);
goto drop_with_chain;
}
offset += sizeof(struct sockaddr_in);
/* Get the IP header length (accounting for possible options). */
iphdrlen = (ipv4->vhl & IPv4_HLMASK) << 2;
/* Copy the src address info into the front of I/O buffer chain which
* overwrites the contents of the packet header field.
*/
memcpy(iob->io_data, &inaddr, sizeof(struct sockaddr_in));
/* Copy the new ICMP reply into the I/O buffer chain (without waiting) */
buflen = ICMPSIZE(iphdrlen);
ret = iob_trycopyin(iob, IPBUF(iphdrlen), buflen, offset, true);
if (ret < 0)
{
/* On a failure, iob_copyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
goto drop_with_chain;
}
/* Trim l3 header */
iob = iob_trimhead(iob, iphdrlen);
/* Add the new I/O buffer chain to the tail of the read-ahead queue (again
* without waiting).
@ -189,19 +141,18 @@ static uint16_t icmp_datahandler(FAR struct net_driver_s *dev,
if (ret < 0)
{
nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
goto drop_with_chain;
iob_free_chain(iob);
}
else
{
ninfo("Buffered %d bytes\n", buflen);
}
ninfo("Buffered %d bytes\n", buflen + addrsize + 1);
dev->d_len = 0;
/* Device buffer must be enqueue or freed, clear the handle */
netdev_iob_clear(dev);
return buflen;
drop_with_chain:
iob_free_chain(iob);
drop:
dev->d_len = 0;
return 0;
}
#endif

View File

@ -227,10 +227,8 @@ static inline ssize_t icmp_readahead(FAR struct icmp_conn_s *conn,
FAR struct sockaddr_in *from,
FAR socklen_t *fromlen)
{
FAR struct sockaddr_in bitbucket;
FAR struct iob_s *iob;
ssize_t ret = -ENODATA;
int recvlen;
/* Check there is any ICMP replies already buffered in a read-ahead
* buffer.
@ -238,68 +236,26 @@ static inline ssize_t icmp_readahead(FAR struct icmp_conn_s *conn,
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
{
FAR struct iob_s *tmp;
uint16_t offset;
uint8_t addrsize;
DEBUGASSERT(iob->io_pktlen > 0);
/* Transfer that buffered data from the I/O buffer chain into
* the user buffer.
*/
/* First get the size of the address */
recvlen = iob_copyout(&addrsize, iob, sizeof(uint8_t), 0);
if (recvlen != sizeof(uint8_t))
{
ret = -EIO;
goto out;
}
offset = sizeof(uint8_t);
if (addrsize > sizeof(struct sockaddr_in))
{
ret = -EINVAL;
goto out;
}
/* Then get address */
if (from == NULL)
if (from != NULL)
{
from = &bitbucket;
memcpy(from, iob->io_data, sizeof(struct sockaddr_in));
}
recvlen = iob_copyout((FAR uint8_t *)from, iob, addrsize, offset);
if (recvlen != addrsize)
{
ret = -EIO;
goto out;
}
/* Copy to user */
if (fromlen != NULL)
{
*fromlen = addrsize;
}
offset += addrsize;
/* And finally, get the buffered data */
ret = (ssize_t)iob_copyout(buf, iob, buflen, offset);
ret = (ssize_t)iob_copyout(buf, iob, buflen, 0);
ninfo("Received %ld bytes (of %u)\n", (long)ret, iob->io_pktlen);
out:
/* Remove the I/O buffer chain from the head of the read-ahead
* buffer queue.
*/
tmp = iob_remove_queue(&conn->readahead);
DEBUGASSERT(tmp == iob);
UNUSED(tmp);
iob_remove_queue(&conn->readahead);
/* And free the I/O buffer chain */

View File

@ -91,7 +91,7 @@ void icmp_reply(FAR struct net_driver_s *dev, int type, int code)
{
int ipicmplen = IPv4_HDRLEN + sizeof(struct icmp_hdr_s);
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
FAR struct icmp_hdr_s *icmp = (FAR struct icmp_hdr_s *)(ipv4 + 1);
FAR struct icmp_hdr_s *icmp;
uint16_t datalen;
#ifdef CONFIG_NET_BROADCAST
const in_addr_t bcast = INADDR_BROADCAST;
@ -119,20 +119,75 @@ void icmp_reply(FAR struct net_driver_s *dev, int type, int code)
if (datalen > ICMP_MAXMSGLEN - ipicmplen)
{
datalen = ICMP_MAXMSGLEN - ipicmplen;
iob_trimtail(dev->d_iob, dev->d_iob->io_pktlen - datalen);
}
/* Save the original datagram */
if (CONFIG_IOB_BUFSIZE >= datalen + ipicmplen +
CONFIG_NET_LL_GUARDSIZE)
{
/* Reuse current iob */
memmove((FAR char *)ipv4 + ipicmplen, ipv4, datalen);
/* Skip icmp header from iob */
iob_update_pktlen(dev->d_iob, datalen + ipicmplen);
}
else
{
FAR struct iob_s *iob;
/* Save the original datagram to iob chain */
iob = dev->d_iob;
dev->d_iob = NULL;
/* Re-prepare device buffer */
if (netdev_iob_prepare(dev, false, 0) != OK)
{
dev->d_len = 0;
dev->d_iob = iob;
netdev_iob_release(dev);
return;
}
/* Copy ipv4 header to device buffer */
if (iob_trycopyin(dev->d_iob, (FAR void *)ipv4,
IPv4_HDRLEN, 0, false) != IPv4_HDRLEN)
{
dev->d_len = 0;
netdev_iob_release(dev);
iob_free_chain(iob);
return;
}
/* Skip icmp header from iob */
iob_update_pktlen(dev->d_iob, dev->d_iob->io_pktlen +
sizeof(struct icmp_hdr_s));
/* Concat new icmp packet before original datagram */
iob_concat(dev->d_iob, iob);
/* IPv4 header to new iob */
ipv4 = IPBUF(0);
}
dev->d_len = ipicmplen + datalen;
/* Copy fields from original packet */
memmove(icmp + 1, ipv4, datalen);
ipv4_build_header(IPv4BUF, dev->d_len, IP_PROTO_ICMP,
&dev->d_ipaddr, (FAR in_addr_t *)ipv4->srcipaddr,
IP_TTL_DEFAULT, NULL);
/* Initialize the ICMP header */
icmp = (FAR struct icmp_hdr_s *)(ipv4 + 1);
icmp->type = type;
icmp->icode = code;
icmp->data[0] = 0;
@ -141,7 +196,7 @@ void icmp_reply(FAR struct net_driver_s *dev, int type, int code)
/* Calculate the ICMP checksum. */
icmp->icmpchksum = 0;
icmp->icmpchksum = ~icmp_chksum(dev, datalen + sizeof(*icmp));
icmp->icmpchksum = ~icmp_chksum_iob(dev->d_iob);
if (icmp->icmpchksum == 0)
{
icmp->icmpchksum = 0xffff;

View File

@ -114,7 +114,11 @@ static void sendto_request(FAR struct net_driver_s *dev,
/* Copy the ICMP header and payload into place after the IPv4 header */
icmp = IPBUF(IPv4_HDRLEN);
memcpy(icmp, pstate->snd_buf, pstate->snd_buflen);
iob_update_pktlen(dev->d_iob, IPv4_HDRLEN);
iob_copyin(dev->d_iob, pstate->snd_buf,
pstate->snd_buflen, IPv4_HDRLEN, false);
/* Initialize the IP header. */
@ -125,7 +129,7 @@ static void sendto_request(FAR struct net_driver_s *dev,
/* Calculate the ICMP checksum. */
icmp->icmpchksum = 0;
icmp->icmpchksum = ~(icmp_chksum(dev, pstate->snd_buflen));
icmp->icmpchksum = ~icmp_chksum_iob(dev->d_iob);
if (icmp->icmpchksum == 0)
{
icmp->icmpchksum = 0xffff;

View File

@ -103,6 +103,10 @@ void icmpv6_advertise(FAR struct net_driver_s *dev,
memcpy(adv->tgtlladdr, &dev->d_mac, lladdrsize);
/* Update device buffer length */
iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size);
/* Calculate the checksum over both the ICMP header and payload */
adv->chksum = 0;

View File

@ -87,82 +87,32 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
unsigned int iplen)
{
FAR struct ipv6_hdr_s *ipv6;
FAR struct icmpv6_hdr_s *icmpv6;
FAR struct iob_s *iob;
struct sockaddr_in6 inaddr;
uint16_t offset;
FAR struct iob_s *iob;
uint16_t buflen;
uint8_t addrsize;
int ret;
/* Try to allocate on I/O buffer to start the chain without waiting (and
* throttling as necessary). If we would have to wait, then drop the
* packet.
*/
iob = iob_tryalloc(true);
if (iob == NULL)
{
nerr("ERROR: Failed to create new I/O buffer chain\n");
goto drop;
}
/* Put the IPv6 address at the beginning of the read-ahead buffer */
iob = dev->d_iob;
ipv6 = IPv6BUF;
inaddr.sin6_family = AF_INET6;
inaddr.sin6_port = 0;
net_ipv6addr_copy(inaddr.sin6_addr.s6_addr16, ipv6->srcipaddr);
/* Copy the src address info into the I/O buffer chain. We will not wait
* for an I/O buffer to become available in this context. It there is
* any failure to allocated, the entire I/O buffer chain will be discarded.
/* Copy the src address info into the front of I/O buffer chain which
* overwrites the contents of the packet header field.
*/
addrsize = sizeof(struct sockaddr_in6);
ret = iob_trycopyin(iob, &addrsize, sizeof(uint8_t), 0, true);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to length to the I/O buffer chain: %d\n", ret);
goto drop_with_chain;
}
offset = sizeof(uint8_t);
ret = iob_trycopyin(iob, (FAR const uint8_t *)&inaddr,
sizeof(struct sockaddr_in6), offset, true);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to source address to the I/O buffer chain: %d\n",
ret);
goto drop_with_chain;
}
offset += sizeof(struct sockaddr_in6);
memcpy(iob->io_data, &inaddr, sizeof(struct sockaddr_in6));
/* Copy the new ICMPv6 reply into the I/O buffer chain (without waiting) */
buflen = ICMPv6SIZE;
icmpv6 = IPBUF(iplen);
ret = iob_trycopyin(iob, (FAR uint8_t *)ICMPv6REPLY, buflen, offset, true);
if (ret < 0)
{
/* On a failure, iob_copyin return a negated error value but does
* not free any I/O buffers.
*/
/* Trim l3 header */
nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
goto drop_with_chain;
}
iob = iob_trimhead(iob, iplen);
/* Add the new I/O buffer chain to the tail of the read-ahead queue (again
* without waiting).
@ -172,19 +122,17 @@ static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
if (ret < 0)
{
nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
goto drop_with_chain;
iob_free_chain(iob);
}
else
{
ninfo("Buffered %d bytes\n", buflen);
}
ninfo("Buffered %d bytes\n", buflen + addrsize + 1);
dev->d_len = 0;
/* Device buffer must be enqueue or freed, clear the handle */
netdev_iob_clear(dev);
return buflen;
drop_with_chain:
iob_free_chain(iob);
drop:
dev->d_len = 0;
return 0;
}
#endif

View File

@ -193,6 +193,10 @@ void icmpv6_radvertise(FAR struct net_driver_s *dev)
ipv6addr_mask(prefix->prefix, dev->d_ipv6addr, dev->d_ipv6netmask);
#endif /* CONFIG_NET_ICMPv6_ROUTER_MANUAL */
/* Update device buffer length */
iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size);
/* Calculate the checksum over both the ICMP header and payload */
adv->chksum = 0;

View File

@ -232,10 +232,8 @@ static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn,
FAR struct sockaddr_in6 *from,
FAR socklen_t *fromlen)
{
FAR struct sockaddr_in6 bitbucket;
FAR struct iob_s *iob;
ssize_t ret = -ENODATA;
int recvlen;
/* Check there is any ICMPv6 replies already buffered in a read-ahead
* buffer.
@ -243,68 +241,26 @@ static inline ssize_t icmpv6_readahead(FAR struct icmpv6_conn_s *conn,
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
{
FAR struct iob_s *tmp;
uint16_t offset;
uint8_t addrsize;
DEBUGASSERT(iob->io_pktlen > 0);
/* Transfer that buffered data from the I/O buffer chain into
* the user buffer.
*/
/* First get the size of the address */
recvlen = iob_copyout(&addrsize, iob, sizeof(uint8_t), 0);
if (recvlen != sizeof(uint8_t))
{
ret = -EIO;
goto out;
}
offset = sizeof(uint8_t);
if (addrsize > sizeof(struct sockaddr_in6))
{
ret = -EINVAL;
goto out;
}
/* Then get address */
if (from == NULL)
if (from != NULL)
{
from = &bitbucket;
memcpy(from, iob->io_data, sizeof(struct sockaddr_in6));
}
recvlen = iob_copyout((FAR uint8_t *)from, iob, addrsize, offset);
if (recvlen != addrsize)
{
ret = -EIO;
goto out;
}
/* Copy to user */
if (fromlen != NULL)
{
*fromlen = addrsize;
}
offset += addrsize;
/* And finally, get the buffered data */
ret = (ssize_t)iob_copyout(buf, iob, buflen, offset);
ret = iob_copyout(buf, iob, buflen, 0);
ninfo("Received %ld bytes (of %u)\n", (long)ret, iob->io_pktlen);
out:
/* Remove the I/O buffer chain from the head of the read-ahead
* buffer queue.
*/
tmp = iob_remove_queue(&conn->readahead);
DEBUGASSERT(tmp == iob);
UNUSED(tmp);
iob_remove_queue(&conn->readahead);
/* And free the I/O buffer chain */

View File

@ -86,7 +86,7 @@ void icmpv6_reply(FAR struct net_driver_s *dev, int type, int code, int data)
{
int ipicmplen = IPv6_HDRLEN + sizeof(struct icmpv6_hdr_s);
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
FAR struct icmpv6_hdr_s *icmpv6 = (FAR struct icmpv6_hdr_s *)(ipv6 + 1);
FAR struct icmpv6_hdr_s *icmpv6;
uint16_t datalen;
if (net_ipv6addr_cmp(ipv6->destipaddr, g_ipv6_unspecaddr)
@ -108,19 +108,74 @@ void icmpv6_reply(FAR struct net_driver_s *dev, int type, int code, int data)
if (datalen > ICMPv6_MINMTULEN - ipicmplen)
{
datalen = ICMPv6_MINMTULEN - ipicmplen;
iob_trimtail(dev->d_iob, dev->d_iob->io_pktlen - datalen);
}
/* Save the original datagram */
if (CONFIG_IOB_BUFSIZE >= datalen + ipicmplen +
CONFIG_NET_LL_GUARDSIZE)
{
/* Reuse current iob */
memmove((FAR char *)ipv6 + ipicmplen, ipv6, datalen);
/* Skip icmp header from iob */
iob_update_pktlen(dev->d_iob, datalen + ipicmplen);
}
else
{
FAR struct iob_s *iob;
/* Save the original datagram to iob chain */
iob = dev->d_iob;
dev->d_iob = NULL;
/* Re-prepare device buffer */
if (netdev_iob_prepare(dev, false, 0) != OK)
{
dev->d_len = 0;
dev->d_iob = iob;
netdev_iob_release(dev);
return;
}
/* Copy ipv4 header to device buffer */
if (iob_trycopyin(dev->d_iob, (FAR void *)ipv6,
IPv6_HDRLEN, 0, false) != IPv6_HDRLEN)
{
dev->d_len = 0;
netdev_iob_release(dev);
iob_free_chain(iob);
return;
}
/* Skip icmp header from iob */
iob_update_pktlen(dev->d_iob, dev->d_iob->io_pktlen +
sizeof(struct icmpv6_hdr_s));
/* Concat new icmp packet before original datagram */
iob_concat(dev->d_iob, iob);
/* IPv6 header to new iob */
ipv6 = IPBUF(0);
}
dev->d_len = ipicmplen + datalen;
/* Copy fields from original packet */
memmove(icmpv6 + 1, ipv6, datalen);
ipv6_build_header(IPv6BUF, dev->d_len - IPv6_HDRLEN, IP_PROTO_ICMP6,
dev->d_ipv6addr, ipv6->srcipaddr, 255);
/* Initialize the ICMPv6 header */
icmpv6 = (FAR struct icmpv6_hdr_s *)(ipv6 + 1);
icmpv6->type = type;
icmpv6->code = code;
icmpv6->data[0] = htons(data >> 16);

View File

@ -97,6 +97,10 @@ void icmpv6_rsolicit(FAR struct net_driver_s *dev)
memcpy(sol->srclladdr, &dev->d_mac, lladdrsize);
/* Update device buffer length */
iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size);
/* Calculate the checksum over both the ICMP header and payload */
sol->chksum = 0;

View File

@ -116,7 +116,11 @@ static void sendto_request(FAR struct net_driver_s *dev,
/* Copy the ICMPv6 request and payload into place after the IPv6 header */
icmpv6 = IPBUF(IPv6_HDRLEN);
memcpy(icmpv6, pstate->snd_buf, pstate->snd_buflen);
iob_update_pktlen(dev->d_iob, IPv6_HDRLEN);
iob_copyin(dev->d_iob, pstate->snd_buf,
pstate->snd_buflen, IPv6_HDRLEN, false);
/* Calculate the ICMPv6 checksum over the ICMPv6 header and payload. */

View File

@ -120,6 +120,10 @@ void icmpv6_solicit(FAR struct net_driver_s *dev,
memcpy(sol->srclladdr, &dev->d_mac, lladdrsize);
/* Update device buffer length */
iob_update_pktlen(dev->d_iob, IPv6_HDRLEN + l3size);
/* Calculate the checksum over both the ICMP header and payload */
sol->chksum = 0;

View File

@ -120,6 +120,10 @@ void igmp_send(FAR struct net_driver_s *dev, FAR struct igmp_group_s *group,
dev->d_len = iphdrlen + IGMP_HDRLEN;
/* Update device buffer length */
iob_update_pktlen(dev->d_iob, dev->d_len);
/* The total size of the data is the size of the IGMP header */
dev->d_sndlen = IGMP_HDRLEN;

View File

@ -265,35 +265,9 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
}
#endif
/* Try to allocate the head of an IOB chain. If this fails, the
* packet will be dropped; we are not operating in a context
* where waiting for an IOB is a good idea
*/
/* Relay the device buffer */
fwd->f_iob = iob_tryalloc(false);
if (fwd->f_iob == NULL)
{
nwarn("WARNING: iob_tryalloc() failed\n");
ret = -ENOMEM;
goto errout_with_fwd;
}
/* Copy the L2/L3 headers plus any following payload into an IOB chain.
* iob_trycopin() will not wait, but will fail there are no available
* IOBs.
*
* REVISIT: Consider an alternative design that does not require data
* copying. This would require a pool of d_buf's that are managed by
* the network rather than the network device.
*/
ret = iob_trycopyin(fwd->f_iob, (FAR const uint8_t *)ipv4,
dev->d_len, 0, false);
if (ret < 0)
{
nwarn("WARNING: iob_trycopyin() failed: %d\n", ret);
goto errout_with_iobchain;
}
fwd->f_iob = dev->d_iob;
/* Decrement the TTL in the copy of the IPv4 header (retaining the
* original TTL in the source to handle the broadcast case). If the
@ -305,7 +279,7 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
{
nwarn("WARNING: Hop limit exceeded... Dropping!\n");
ret = -EMULTIHOP;
goto errout_with_iobchain;
goto errout_with_fwd;
}
#ifdef CONFIG_NET_NAT
@ -317,7 +291,7 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
if (ret < 0)
{
nwarn("WARNING: Performing NAT outbound failed, dropping!\n");
goto errout_with_iobchain;
goto errout_with_fwd;
}
#endif
@ -326,16 +300,10 @@ static int ipv4_dev_forward(FAR struct net_driver_s *dev,
ret = ipfwd_forward(fwd);
if (ret >= 0)
{
dev->d_len = 0;
netdev_iob_clear(dev);
return OK;
}
errout_with_iobchain:
if (fwd != NULL && fwd->f_iob != NULL)
{
iob_free_chain(fwd->f_iob);
}
errout_with_fwd:
if (fwd != NULL)
{

View File

@ -399,35 +399,9 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
}
#endif
/* Try to allocate the head of an IOB chain. If this fails, the
* packet will be dropped; we are not operating in a context where
* waiting for an IOB is a good idea
*/
/* Relay the device buffer */
fwd->f_iob = iob_tryalloc(false);
if (fwd->f_iob == NULL)
{
nwarn("WARNING: iob_tryalloc() failed\n");
ret = -ENOMEM;
goto errout_with_fwd;
}
/* Copy the L2/L3 headers plus any following payload into an IOB
* chain. iob_trycopin() will not wait, but will fail there are no
* available IOBs.
*
* REVISIT: Consider an alternative design that does not require data
* copying. This would require a pool of d_buf's that are managed by
* the network rather than the network device.
*/
ret = iob_trycopyin(fwd->f_iob, (FAR const uint8_t *)ipv6,
dev->d_len, 0, false);
if (ret < 0)
{
nwarn("WARNING: iob_trycopyin() failed: %d\n", ret);
goto errout_with_iobchain;
}
fwd->f_iob = dev->d_iob;
/* Decrement the TTL in the copy of the IPv6 header (retaining the
* original TTL in the sourcee to handle the broadcast case). If the
@ -439,7 +413,7 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
{
nwarn("WARNING: Hop limit exceeded... Dropping!\n");
ret = -EMULTIHOP;
goto errout_with_iobchain;
goto errout_with_fwd;
}
/* Then set up to forward the packet according to the protocol. */
@ -447,17 +421,11 @@ static int ipv6_dev_forward(FAR struct net_driver_s *dev,
ret = ipfwd_forward(fwd);
if (ret >= 0)
{
dev->d_len = 0;
netdev_iob_clear(dev);
return OK;
}
}
errout_with_iobchain:
if (fwd != NULL && fwd->f_iob != NULL)
{
iob_free_chain(fwd->f_iob);
}
errout_with_fwd:
if (fwd != NULL)
{

View File

@ -159,6 +159,10 @@ void mld_send(FAR struct net_driver_s *dev, FAR struct mld_group_s *group,
dev->d_sndlen = RASIZE + mldsize;
/* Update device buffer length */
iob_update_pktlen(dev->d_iob, dev->d_len);
/* Select the IPv6 destination address.
* This varies with the type of message being sent:
*

View File

@ -196,6 +196,10 @@ void neighbor_ethernet_out(FAR struct net_driver_s *dev)
memcpy(eth->src, dev->d_mac.ether.ether_addr_octet, ETHER_ADDR_LEN);
eth->type = HTONS(ETHTYPE_IP6);
/* Update device buffer length */
iob_update_pktlen(dev->d_iob, dev->d_len);
/* Add the size of the layer layer header to the total size of the
* outgoing packet.
*/

View File

@ -26,6 +26,10 @@ NETDEV_CSRCS += netdev_count.c netdev_ifconf.c netdev_foreach.c
NETDEV_CSRCS += netdev_unregister.c netdev_carrier.c netdev_default.c
NETDEV_CSRCS += netdev_verify.c netdev_lladdrsize.c
ifeq ($(CONFIG_MM_IOB),y)
NETDEV_CSRCS += netdev_input.c netdev_iob.c
endif
ifeq ($(CONFIG_NETDOWN_NOTIFIER),y)
SOCK_CSRCS += netdown_notifier.c
endif

View File

@ -31,6 +31,7 @@
#include <stdbool.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/netdev.h>
#ifdef CONFIG_NETDOWN_NOTIFIER
# include <nuttx/wqueue.h>

117
net/netdev/netdev_input.c Normal file
View File

@ -0,0 +1,117 @@
/****************************************************************************
* net/netdev/netdev_input.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 <nuttx/net/netdev.h>
#include "utils/utils.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: netdev_input
*
* Description:
* This function will copy the flat buffer that does not support
* Scatter/gather to the iob vector buffer.
*
* Compatible with all old flat buffer NICs:
*
* [tcp|udp|icmp|...]ipv[4|6]_data_handler()
* | (iob_concat/append to readahead)
* |
* pkt/ipv[4/6]_in()/...
* |
* |
* netdev_input() // new interface, Scatter/gather flat/iobs
* |
* |
* pkt/ipv[4|6]_input()/...
* |
* |
* NICs io vector receive(Orignal flat buffer)
*
* Input Parameters:
* NULL
*
* Returned Value:
* Pointer to default network driver on success; null on failure
*
****************************************************************************/
int netdev_input(FAR struct net_driver_s *dev,
devif_poll_callback_t callback, bool reply)
{
uint16_t llhdrlen = NET_LL_HDRLEN(dev);
unsigned int offset = CONFIG_NET_LL_GUARDSIZE - llhdrlen;
FAR uint8_t *buf = dev->d_buf;
unsigned int l3l4len;
int ret;
/* Prepare iob buffer */
ret = netdev_iob_prepare(dev, false, 0);
if (ret != OK)
{
return ret;
}
/* Copy l2 header to gruard area */
memcpy(dev->d_iob->io_data + offset, buf, llhdrlen);
/* Copy l3/l4 data to iob entry */
l3l4len = dev->d_len - llhdrlen;
ret = iob_trycopyin(dev->d_iob, buf + llhdrlen,
l3l4len, 0, false);
if (ret == l3l4len)
{
/* Update device buffer to l2 start */
dev->d_buf = dev->d_iob->io_data + offset;
iob_update_pktlen(dev->d_iob, l3l4len);
ret = callback(dev);
if (dev->d_iob != NULL && reply)
{
if (ret == OK && dev->d_len > 0)
{
iob_copyout(buf + llhdrlen, dev->d_iob, dev->d_len, 0);
memcpy(buf, dev->d_iob->io_data + offset, llhdrlen);
}
}
}
netdev_iob_release(dev);
dev->d_buf = buf;
return ret;
}

128
net/netdev/netdev_iob.c Normal file
View File

@ -0,0 +1,128 @@
/****************************************************************************
* net/netdev/netdev_iob.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 <nuttx/net/netdev.h>
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: netdev_iob_prepare
*
* Description:
* Prepare data buffer for a given NIC
* The iob offset will be updated to l2 gruard size by default:
* ----------------------------------------------------------------
* | iob entry |
* ---------------------------------------------------------------|
* |<--- CONFIG_NET_LL_GUARDSIZE -->|<--- io_len/io_pktlen(0) --->|
* ---------------------------------------------------------------|
*
* Assumptions:
* The caller has locked the network.
*
* Returned Value:
* A non-zero copy is returned on success.
*
****************************************************************************/
int netdev_iob_prepare(FAR struct net_driver_s *dev, bool throttled,
unsigned int timeout)
{
/* Prepare iob buffer */
if (dev->d_iob == NULL)
{
dev->d_iob = net_iobtimedalloc(false, timeout);
if (dev->d_iob == NULL && throttled)
{
dev->d_iob = net_iobtimedalloc(true, timeout);
}
}
if (dev->d_iob == NULL)
{
return -ENOMEM;
}
/* Set the device buffer to l2 */
dev->d_buf = &dev->d_iob->io_data[CONFIG_NET_LL_GUARDSIZE -
NET_LL_HDRLEN(dev)];
/* Update l2 gruard size */
iob_reserve(dev->d_iob, CONFIG_NET_LL_GUARDSIZE);
return OK;
}
/****************************************************************************
* Name: netdev_iob_clear
*
* Description:
* Clean up buffer resources for a given NIC
*
* Assumptions:
* The caller has locked the network and dev->d_iob has been
* released or taken away.
*
****************************************************************************/
void netdev_iob_clear(FAR struct net_driver_s *dev)
{
/* Clear the device buffer */
dev->d_iob = NULL;
dev->d_buf = NULL;
dev->d_len = 0;
}
/****************************************************************************
* Name: netdev_iob_release
*
* Description:
* Release buffer resources for a given NIC
*
* Assumptions:
* The caller has locked the network.
*
****************************************************************************/
void netdev_iob_release(FAR struct net_driver_s *dev)
{
/* Release device buffer */
if (dev->d_iob != NULL)
{
iob_free_chain(dev->d_iob);
dev->d_iob = NULL;
}
}

View File

@ -36,21 +36,23 @@
#include "pkt/pkt.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define PKTBUF ((FAR struct eth_hdr_s *)dev->d_buf)
/****************************************************************************
* Public Functions
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: pkt_input
* Name: pkt_in
*
* Description:
* Handle incoming packet input
*
* This is the iob buffer version of pkt_input(),
* this function will support send/receive iob vectors directly between
* the driver and l3/l4 stack to avoid unnecessary memory copies,
* especially on hardware that supports Scatter/gather, which can
* greatly improve performance
* this function will uses d_iob as packets input which used by some
* NICs such as celluler net driver.
*
* Input Parameters:
* dev - The device driver structure containing the received packet
*
@ -65,10 +67,10 @@
*
****************************************************************************/
int pkt_input(struct net_driver_s *dev)
static int pkt_in(FAR struct net_driver_s *dev)
{
FAR struct pkt_conn_s *conn;
FAR struct eth_hdr_s *pbuf = PKTBUF;
FAR struct eth_hdr_s *pbuf = ETHBUF;
int ret = OK;
conn = pkt_active(pbuf);
@ -109,4 +111,38 @@ int pkt_input(struct net_driver_s *dev)
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: pkt_input
*
* Description:
* Handle incoming packet input
*
* Input Parameters:
* dev - The device driver structure containing the received packet
*
* Returned Value:
* OK The packet has been processed and can be deleted
* -EAGAIN 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:
* The network is locked.
*
****************************************************************************/
int pkt_input(FAR struct net_driver_s *dev)
{
if (dev->d_iob != NULL)
{
return pkt_in(dev);
}
return netdev_input(dev, pkt_in, false);
}
#endif /* CONFIG_NET && CONFIG_NET_PKT */

View File

@ -115,6 +115,7 @@ static inline void pkt_add_recvlen(FAR struct pkt_recvfrom_s *pstate,
static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev,
FAR struct pkt_recvfrom_s *pstate)
{
unsigned int offset;
size_t recvlen;
if (dev->d_len > pstate->pr_buflen)
@ -128,7 +129,10 @@ static void pkt_recvfrom_newdata(FAR struct net_driver_s *dev,
/* Copy the new packet data into the user buffer */
memcpy(pstate->pr_buffer, dev->d_buf, recvlen);
offset = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset;
recvlen = iob_copyout(pstate->pr_buffer, dev->d_iob, recvlen, offset);
ninfo("Received %d bytes (of %d)\n", (int)recvlen, (int)dev->d_len);
/* Update the accumulated size of the data read */

View File

@ -35,6 +35,7 @@
#include <nuttx/mm/iob.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/net.h>
#include <nuttx/net/tcp.h>
#include <nuttx/wqueue.h>
#ifdef CONFIG_NET_TCP
@ -1250,8 +1251,9 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
*
****************************************************************************/
uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
uint16_t nbytes);
uint16_t tcp_datahandler(FAR struct net_driver_s *dev,
FAR struct tcp_conn_s *conn,
uint16_t offset);
/****************************************************************************
* Name: tcp_backlogcreate
@ -2044,6 +2046,22 @@ int tcp_ioctl(FAR struct tcp_conn_s *conn, int cmd, unsigned long arg);
void tcp_sendbuffer_notify(FAR struct tcp_conn_s *conn);
#endif /* CONFIG_NET_SEND_BUFSIZE */
/****************************************************************************
* Name: tcpip_hdrsize
*
* Description:
* Get the total size of L3 and L4 TCP header
*
* Input Parameters:
* conn The connection structure associated with the socket
*
* Returned Value:
* the total size of L3 and L4 TCP header
*
****************************************************************************/
uint16_t tcpip_hdrsize(FAR struct tcp_conn_s *conn);
#ifdef __cplusplus
}
#endif

View File

@ -61,13 +61,13 @@ static inline uint16_t
tcp_data_event(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
uint16_t flags)
{
uint16_t ret;
uint16_t recvlen;
/* Assume that we will ACK the data. The data will be ACKed if it is
* placed in the read-ahead buffer -OR- if it zero length
*/
ret = (flags & ~TCP_NEWDATA) | TCP_SNDACK;
flags = (flags & ~TCP_NEWDATA) | TCP_SNDACK;
/* Is there new data? With non-zero length? (Certain connection events
* can have zero-length with TCP_NEWDATA set just to cause an ACK).
@ -75,46 +75,25 @@ tcp_data_event(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
if (dev->d_len > 0)
{
uint8_t *buffer = dev->d_appdata;
int buflen = dev->d_len;
uint16_t recvlen;
ninfo("No listener on connection\n");
/* Save as the packet data as in the read-ahead buffer. NOTE that
* partial packets will not be buffered.
*/
recvlen = tcp_datahandler(conn, buffer, buflen);
if (recvlen < buflen)
{
/* There is no handler to receive new data and there are no free
* read-ahead buffers to retain the data -- drop the packet.
*/
ninfo("Dropped %d/%d bytes\n", buflen - recvlen, buflen);
#ifdef CONFIG_NET_STATISTICS
g_netstats.tcp.drop++;
#endif
/* Clear the TCP_SNDACK bit so that no ACK will be sent.
* Clear the TCP_CLOSE because we effectively dropped
* the FIN as well.
*
* Revisit: It might make more sense to send a dup ack
* to give a hint to the peer.
*/
ret &= ~(TCP_SNDACK | TCP_CLOSE);
}
recvlen = tcp_datahandler(dev, conn,
(dev->d_appdata - dev->d_iob->io_data) -
dev->d_iob->io_offset);
net_incr32(conn->rcvseq, recvlen);
netdev_iob_clear(dev);
}
/* In any event, the new data has now been handled */
dev->d_len = 0;
return ret;
return flags;
}
/****************************************************************************
@ -139,6 +118,13 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
uint16_t orig = flags;
#endif
/* Prepare device buffer */
if (dev->d_iob == NULL && netdev_iob_prepare(dev, true, 0) != OK)
{
return 0;
}
/* Preserve the TCP_ACKDATA, TCP_CLOSE, and TCP_ABORT in the response.
* These is needed by the network to handle responses and buffer state.
* The TCP_NEWDATA indication will trigger the ACK response, but must be
@ -202,6 +188,13 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
}
#endif
/* Re-prepare the device buffer if d_iob is consumed by the stack */
if (dev->d_iob == NULL)
{
netdev_iob_prepare(dev, true, 0);
}
return flags;
}
@ -231,84 +224,41 @@ uint16_t tcp_callback(FAR struct net_driver_s *dev,
*
****************************************************************************/
uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
uint16_t buflen)
uint16_t tcp_datahandler(FAR struct net_driver_s *dev,
FAR struct tcp_conn_s *conn,
uint16_t offset)
{
FAR struct iob_s *iob;
uint16_t copied = 0;
int ret;
unsigned int i;
FAR struct iob_s *iob = dev->d_iob;
uint16_t buflen;
/* Try to allocate I/O buffers and copy the data into them
* without waiting (and throttling as necessary).
*/
iob = conn->readahead;
for (i = 0; i < 2; i++)
if (offset > 0)
{
bool throttled = i == 0; /* try throttled=true first */
/* Remove 'bufoff' bytes from the beginning of the input I/O chain */
if (!throttled)
{
#if CONFIG_IOB_THROTTLE > 0
if (conn->readahead != NULL)
{
ninfo("Do not use throttled=false because of "
"non-empty readahead\n");
break;
}
#else
break;
#endif
}
if (iob == NULL)
{
iob = iob_tryalloc(throttled);
if (iob == NULL)
{
continue;
}
iob->io_pktlen = 0;
}
if (iob != NULL)
{
uint32_t olen = iob->io_pktlen;
ret = iob_trycopyin(iob, buffer + copied, buflen - copied,
olen, throttled);
copied += iob->io_pktlen - olen;
if (ret < 0)
{
/* On a failure, iob_copyin return a negated error value but
* does not free any I/O buffers.
*/
continue;
}
}
break;
iob = iob_trimhead(iob, offset);
}
DEBUGASSERT(conn->readahead == iob || conn->readahead == NULL);
if (iob == NULL)
/* Trim tail if l3/l4 header has been removed */
if (dev->d_len < iob->io_pktlen)
{
nerr("ERROR: Failed to create new I/O buffer chain\n");
DEBUGASSERT(copied == 0);
return 0;
iob = iob_trimtail(iob, iob->io_pktlen - dev->d_len);
}
if (copied == 0)
buflen = iob->io_pktlen;
/* Concat the iob to readahead */
if (conn->readahead == NULL)
{
nerr("ERROR: Failed to append new I/O buffer\n");
DEBUGASSERT(conn->readahead == iob);
return 0;
conn->readahead = iob;
}
else
{
iob_concat(conn->readahead, iob);
}
conn->readahead = iob;
netdev_iob_clear(dev);
#ifdef CONFIG_NET_TCP_NOTIFIER
/* Provide notification(s) that additional TCP read-ahead data is
@ -318,8 +268,8 @@ uint16_t tcp_datahandler(FAR struct tcp_conn_s *conn, FAR uint8_t *buffer,
tcp_readahead_signal(conn);
#endif
ninfo("Buffered %" PRIu16 " bytes\n", copied);
return copied;
ninfo("Buffered %" PRIu16 " bytes\n", buflen);
return buflen;
}
#endif /* NET_TCP_HAVE_STACK */

View File

@ -113,6 +113,7 @@ static inline void tcp_update_recvlen(FAR struct tcp_recvfrom_s *pstate,
static size_t tcp_recvfrom_newdata(FAR struct net_driver_s *dev,
FAR struct tcp_recvfrom_s *pstate)
{
unsigned int offset;
size_t recvlen;
/* Get the length of the data to return */
@ -128,7 +129,14 @@ static size_t tcp_recvfrom_newdata(FAR struct net_driver_s *dev,
/* Copy the new appdata into the user buffer */
memcpy(pstate->ir_buffer, dev->d_appdata, recvlen);
offset = (dev->d_appdata - dev->d_iob->io_data) - dev->d_iob->io_offset;
recvlen = iob_copyout(pstate->ir_buffer, dev->d_iob, recvlen, offset);
/* Trim the copied buffers */
dev->d_iob = iob_trimhead(dev->d_iob, recvlen + offset);
ninfo("Received %d bytes (of %d)\n", (int)recvlen, (int)dev->d_len);
/* Update the accumulated size of the data read */
@ -172,11 +180,10 @@ static inline uint16_t tcp_newdata(FAR struct net_driver_s *dev,
if (recvlen < dev->d_len)
{
FAR uint8_t *buffer = (FAR uint8_t *)dev->d_appdata + recvlen;
uint16_t buflen = dev->d_len - recvlen;
uint16_t nsaved;
uint16_t buflen = dev->d_len - recvlen;
nsaved = tcp_datahandler(conn, buffer, buflen);
nsaved = tcp_datahandler(dev, conn, 0);
if (nsaved < buflen)
{
nwarn("WARNING: packet data not fully saved "
@ -189,6 +196,10 @@ static inline uint16_t tcp_newdata(FAR struct net_driver_s *dev,
recvlen += nsaved;
}
else
{
netdev_iob_release(dev);
}
if (recvlen < dev->d_len)
{
@ -379,16 +390,16 @@ static uint16_t tcp_recvhandler(FAR struct net_driver_s *dev,
if ((flags & TCP_NEWDATA) != 0)
{
/* Save the sender's address in the caller's 'from' location */
tcp_sender(dev, pstate);
/* Copy the data from the packet (saving any unused bytes from the
* packet in the read-ahead buffer).
*/
flags = tcp_newdata(dev, pstate, flags);
/* Save the sender's address in the caller's 'from' location */
tcp_sender(dev, pstate);
/* Indicate that the data has been consumed and that an ACK
* should be sent.
*/

View File

@ -168,6 +168,10 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
tcp->urgp[0] = 0;
tcp->urgp[1] = 0;
/* Update device buffer length before setup the IP header */
iob_update_pktlen(dev->d_iob, dev->d_len);
/* Calculate chk & build L3 header */
#ifdef CONFIG_NET_IPv6
@ -263,8 +267,14 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
void tcp_send(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
uint16_t flags, uint16_t len)
{
FAR struct tcp_hdr_s *tcp = tcp_header(dev);
FAR struct tcp_hdr_s *tcp;
if (dev->d_iob == NULL)
{
return;
}
tcp = tcp_header(dev);
tcp->flags = flags;
dev->d_len = len;
tcp->tcpoffset = (TCP_HDRLEN / 4) << 4;
@ -290,18 +300,25 @@ void tcp_send(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
void tcp_reset(FAR struct net_driver_s *dev)
{
FAR struct tcp_hdr_s *tcp = tcp_header(dev);
FAR struct tcp_hdr_s *tcp;
uint32_t ackno;
uint16_t tmp16;
uint16_t acklen = 0;
uint8_t seqbyte;
if (dev->d_iob == NULL)
{
return;
}
#ifdef CONFIG_NET_STATISTICS
g_netstats.tcp.rst++;
#endif
/* TCP setup */
tcp = tcp_header(dev);
if ((tcp->flags & TCP_SYN) != 0 || (tcp->flags & TCP_FIN) != 0)
{
acklen++;
@ -313,7 +330,12 @@ void tcp_reset(FAR struct net_driver_s *dev)
#endif
{
FAR struct ipv6_hdr_s *ip = IPv6BUF;
acklen += (ip->len[0] << 8 | ip->len[1]);
/* Set the packet length to the size of the IPv6 + TCP headers */
dev->d_len = IPv6TCP_HDRLEN;
}
#endif /* CONFIG_NET_IPv6 */
@ -323,7 +345,12 @@ void tcp_reset(FAR struct net_driver_s *dev)
#endif
{
FAR struct ipv4_hdr_s *ip = IPv4BUF;
acklen += (ip->len[0] << 8) + ip->len[1] - (ip->vhl & 0x0f) * 4;
/* Set the packet length to the size of the IPv4 + TCP headers */
dev->d_len = IPv4TCP_HDRLEN;
}
#endif /* CONFIG_NET_IPv4 */
@ -373,6 +400,10 @@ void tcp_reset(FAR struct net_driver_s *dev)
tcp->urgp[0] = 0;
tcp->urgp[0] = 0;
/* Update device buffer length before setup the IP header */
iob_update_pktlen(dev->d_iob, dev->d_len);
/* Calculate chk & build L3 header */
#ifdef CONFIG_NET_IPv6
@ -382,10 +413,6 @@ void tcp_reset(FAR struct net_driver_s *dev)
{
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
/* Set the packet length to the size of the IPv6 + TCP headers */
dev->d_len = IPv6TCP_HDRLEN;
ipv6_build_header(ipv6, dev->d_len - IPv6_HDRLEN,
IP_PROTO_TCP, dev->d_ipv6addr, ipv6->srcipaddr,
IP_TTL_DEFAULT);
@ -402,10 +429,6 @@ void tcp_reset(FAR struct net_driver_s *dev)
{
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
/* Set the packet length to the size of the IPv4 + TCP headers */
dev->d_len = IPv4TCP_HDRLEN;
ipv4_build_header(IPv4BUF, dev->d_len, IP_PROTO_TCP,
&dev->d_ipaddr, (FAR in_addr_t *)ipv4->srcipaddr,
IP_TTL_DEFAULT, NULL);
@ -485,6 +508,11 @@ void tcp_synack(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
uint16_t tcp_mss;
int16_t optlen = 0;
if (dev->d_iob == NULL)
{
return;
}
/* Get values that vary with the underlying IP domain */
#ifdef CONFIG_NET_IPv6
@ -596,4 +624,44 @@ void tcp_send_txnotify(FAR struct socket *psock,
#endif /* CONFIG_NET_IPv6 */
}
/****************************************************************************
* Name: tcpip_hdrsize
*
* Description:
* Get the total size of L3 and L4 TCP header
*
* Input Parameters:
* conn The connection structure associated with the socket
*
* Returned Value:
* the total size of L3 and L4 TCP header
*
****************************************************************************/
uint16_t tcpip_hdrsize(FAR struct tcp_conn_s *conn)
{
uint16_t hdrsize = sizeof(struct tcp_hdr_s);
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
if (conn->domain == PF_INET)
{
/* Select the IPv4 domain */
return sizeof(struct ipv4_hdr_s) + hdrsize;
}
else /* if (domain == PF_INET6) */
{
/* Select the IPv6 domain */
return sizeof(struct ipv6_hdr_s) + hdrsize;
}
#elif defined(CONFIG_NET_IPv4)
((void)conn);
return sizeof(struct ipv4_hdr_s) + hdrsize;
#elif defined(CONFIG_NET_IPv6)
((void)conn);
return sizeof(struct ipv6_hdr_s) + hdrsize;
#endif
}
#endif /* CONFIG_NET && CONFIG_NET_TCP */

View File

@ -596,7 +596,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* happen until the polling cycle completes).
*/
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen, 0);
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
0, tcpip_hdrsize(conn));
/* Reset the retransmission timer. */
@ -882,7 +883,8 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
* won't actually happen until the polling cycle completes).
*/
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen, TCP_WBSENT(wrb));
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen,
TCP_WBSENT(wrb), tcpip_hdrsize(conn));
/* Remember how much data we send out now so that we know
* when everything has been acknowledged. Just increment

View File

@ -326,9 +326,8 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
* happen until the polling cycle completes).
*/
devif_send(dev,
&pstate->snd_buffer[pstate->snd_acked],
sndlen);
devif_send(dev, &pstate->snd_buffer[pstate->snd_acked],
sndlen, tcpip_hdrsize(conn));
/* Continue waiting */
@ -409,7 +408,8 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
* happen until the polling cycle completes).
*/
devif_send(dev, &pstate->snd_buffer[pstate->snd_sent], sndlen);
devif_send(dev, &pstate->snd_buffer[pstate->snd_sent],
sndlen, tcpip_hdrsize(conn));
/* Update the amount of data sent (but not necessarily ACKed) */

View File

@ -34,6 +34,7 @@
#include <nuttx/semaphore.h>
#include <nuttx/net/ip.h>
#include <nuttx/net/net.h>
#include <nuttx/net/udp.h>
#include <nuttx/mm/iob.h>
#ifdef CONFIG_NET_UDP_NOTIFIER
@ -894,7 +895,7 @@ void udp_readahead_signal(FAR struct udp_conn_s *conn);
* When write buffer becomes empty, *all* of the workers waiting
* for that event data will be executed. If there are multiple workers
* waiting for read-ahead data then only the first to execute will get the
* data. Others will need to call tcp_writebuffer_notifier_setup() once
* data. Others will need to call udp_writebuffer_notifier_setup() once
* again.
*
* Input Parameters:
@ -964,6 +965,22 @@ int udp_ioctl(FAR struct udp_conn_s *conn, int cmd, unsigned long arg);
void udp_sendbuffer_notify(FAR struct udp_conn_s *conn);
#endif /* CONFIG_NET_SEND_BUFSIZE */
/****************************************************************************
* Name: udpip_hdrsize
*
* Description:
* Get the total size of L3 and L4 UDP header
*
* Input Parameters:
* conn The connection structure associated with the socket
*
* Returned Value:
* the total size of L3 and L4 TCP header
*
****************************************************************************/
uint16_t udpip_hdrsize(FAR struct udp_conn_s *conn);
#undef EXTERN
#ifdef __cplusplus
}

View File

@ -70,8 +70,8 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
};
#endif
FAR void *src_addr;
uint8_t src_addr_size;
FAR void *src_addr;
uint8_t offset = 0;
#if CONFIG_NET_RECV_BUFSIZE > 0
@ -82,16 +82,7 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
}
#endif
/* Allocate on I/O buffer to start the chain (throttling as necessary).
* We will not wait for an I/O buffer to become available in this context.
*/
iob = iob_tryalloc(true);
if (iob == NULL)
{
nerr("ERROR: Failed to create new I/O buffer chain\n");
return 0;
}
iob = dev->d_iob;
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
@ -157,71 +148,18 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
}
#endif /* CONFIG_NET_IPv4 */
/* Copy the src address info into the I/O buffer chain. We will not wait
* for an I/O buffer to become available in this context. It there is
* any failure to allocated, the entire I/O buffer chain will be discarded.
*/
ret = iob_trycopyin(iob, (FAR const uint8_t *)&src_addr_size,
sizeof(uint8_t), offset, true);
offset += sizeof(uint8_t);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
iob_free_chain(iob);
return 0;
}
ret = iob_trycopyin(iob, (FAR const uint8_t *)src_addr, src_addr_size,
offset, true);
offset += src_addr_size;
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
iob_free_chain(iob);
return 0;
}
/* Override the address info begin of io_data */
#ifdef CONFIG_NETDEV_IFINDEX
ret = iob_trycopyin(iob, &dev->d_ifindex, sizeof(uint8_t), offset, true);
offset += sizeof(uint8_t);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but does
* not free any I/O buffers.
*/
nerr("ERROR: Failed to add dindex to the I/O buffer chain: %d\n", ret);
iob_free_chain(iob);
return 0;
}
iob->io_data[offset++] = dev->d_ifindex;
#endif
iob->io_data[offset++] = src_addr_size;
memcpy(&iob->io_data[offset], src_addr, src_addr_size);
if (buflen > 0)
{
/* Copy the new appdata into the I/O buffer chain */
/* Trim l3/l4 offset */
ret = iob_trycopyin(iob, buffer, buflen, offset, true);
if (ret < 0)
{
/* On a failure, iob_trycopyin return a negated error value but
* does not free any I/O buffers.
*/
nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n",
ret);
iob_free_chain(iob);
return 0;
}
}
iob = iob_trimhead(iob, (dev->d_appdata - iob->io_data) -
iob->io_offset);
/* Add the new I/O buffer chain to the tail of the read-ahead queue */
@ -229,19 +167,24 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev,
if (ret < 0)
{
nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
iob_free_chain(iob);
return 0;
buflen = 0;
}
#ifdef CONFIG_NET_UDP_NOTIFIER
/* Provided notification(s) that additional UDP read-ahead data is
* available.
*/
else
{
ninfo("Buffered %d bytes\n", buflen);
udp_readahead_signal(conn);
/* Provided notification(s) that additional UDP read-ahead data is
* available.
*/
udp_readahead_signal(conn);
}
#endif
ninfo("Buffered %d bytes\n", buflen);
netdev_iob_clear(dev);
return buflen;
}

View File

@ -126,19 +126,19 @@ out:
* Copy the read data from the packet
*
* Input Parameters:
* dev The structure of the network driver that generated the event.
* dev The structure of the network driver that generated the event
* pstate recvfrom state structure
*
* Returned Value:
* The number of bytes taken from the packet.
* None.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static size_t udp_recvfrom_newdata(FAR struct net_driver_s *dev,
FAR struct udp_recvfrom_s *pstate)
static inline size_t udp_recvfrom_newdata(FAR struct net_driver_s *dev,
FAR struct udp_recvfrom_s *pstate)
{
size_t recvlen;
@ -155,50 +155,23 @@ static size_t udp_recvfrom_newdata(FAR struct net_driver_s *dev,
/* Copy the new appdata into the user buffer */
memcpy(pstate->ir_msg->msg_iov->iov_base, dev->d_appdata, recvlen);
ninfo("Received %zu bytes (of %" PRIu16 ")\n", recvlen, dev->d_len);
recvlen = iob_copyout(pstate->ir_msg->msg_iov->iov_base, dev->d_iob,
recvlen, dev->d_appdata - dev->d_iob->io_data -
dev->d_iob->io_offset);
/* Update the size of the data read */
pstate->ir_recvlen = recvlen;
return recvlen;
}
/****************************************************************************
* Name: udp_newdata
*
* Description:
* Copy the read data from the packet
*
* Input Parameters:
* dev The structure of the network driver that generated the event
* pstate recvfrom state structure
*
* Returned Value:
* None.
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
static inline void udp_newdata(FAR struct net_driver_s *dev,
FAR struct udp_recvfrom_s *pstate)
{
/* Take as much data from the packet as we can */
udp_recvfrom_newdata(dev, pstate);
/* Indicate no data in the buffer */
dev->d_len = 0;
return recvlen;
}
static inline void udp_readahead(struct udp_recvfrom_s *pstate)
{
FAR struct udp_conn_s *conn = pstate->ir_conn;
FAR struct iob_s *iob;
int recvlen;
/* Check there is any UDP datagram already buffered in a read-ahead
* buffer.
@ -208,44 +181,34 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate)
if ((iob = iob_peek_queue(&conn->readahead)) != NULL)
{
FAR struct iob_s *tmp;
#ifdef CONFIG_NET_IPv6
uint8_t srcaddr[sizeof(struct sockaddr_in6)];
#else
uint8_t srcaddr[sizeof(struct sockaddr_in)];
#endif
int recvlen = pstate->ir_msg->msg_iov->iov_len;
uint8_t src_addr_size;
uint8_t offset = 0;
uint8_t ifindex = 0;
uint8_t offset = 0;
FAR void *srcaddr;
uint8_t ifindex;
DEBUGASSERT(iob->io_pktlen > 0);
/* Transfer that buffered data from the I/O buffer chain into
* the user buffer.
*/
recvlen = iob_copyout(&src_addr_size, iob, sizeof(uint8_t), offset);
offset += sizeof(uint8_t);
if (recvlen != sizeof(uint8_t))
{
goto out;
}
recvlen = iob_copyout(srcaddr, iob, src_addr_size, offset);
offset += src_addr_size;
if (recvlen != src_addr_size)
{
goto out;
}
/* Unflatten saved connection information */
#ifdef CONFIG_NETDEV_IFINDEX
recvlen = iob_copyout(&ifindex, iob, sizeof(uint8_t), offset);
offset += sizeof(uint8_t);
if (recvlen != sizeof(uint8_t))
{
goto out;
}
ifindex = iob->io_data[offset++];
#else
ifindex = 0;
#endif
src_addr_size = iob->io_data[offset++];
srcaddr = &iob->io_data[offset];
/* Copy to user */
recvlen = iob_copyout(pstate->ir_msg->msg_iov->iov_base,
iob, recvlen, 0);
/* Update the accumulated size of the data read */
pstate->ir_recvlen = recvlen;
ninfo("Received %d bytes (of %d)\n", recvlen, iob->io_pktlen);
if (pstate->ir_msg->msg_name)
{
@ -257,33 +220,13 @@ static inline void udp_readahead(struct udp_recvfrom_s *pstate)
pstate->ir_msg->msg_namelen);
}
if (pstate->ir_msg->msg_iov->iov_len > 0)
{
recvlen = iob_copyout(pstate->ir_msg->msg_iov->iov_base,
iob, pstate->ir_msg->msg_iov->iov_len,
offset);
ninfo("Received %d bytes (of %d)\n", recvlen, iob->io_pktlen);
/* Update the accumulated size of the data read */
pstate->ir_recvlen = recvlen;
}
else
{
pstate->ir_recvlen = 0;
}
udp_recvpktinfo(pstate, srcaddr, ifindex);
out:
/* Remove the I/O buffer chain from the head of the read-ahead
* buffer queue.
*/
tmp = iob_remove_queue(&conn->readahead);
DEBUGASSERT(tmp == iob);
UNUSED(tmp);
iob_remove_queue(&conn->readahead);
/* And free the I/O buffer chain */
@ -481,18 +424,18 @@ static uint16_t udp_eventhandler(FAR struct net_driver_s *dev,
else if ((flags & UDP_NEWDATA) != 0)
{
/* Save the sender's address in the caller's 'from' location */
udp_sender(dev, pstate);
/* Copy the data from the packet */
udp_newdata(dev, pstate);
udp_recvfrom_newdata(dev, pstate);
/* We are finished. */
ninfo("UDP done\n");
/* Save the sender's address in the caller's 'from' location */
udp_sender(dev, pstate);
/* Don't allow any further UDP call backs. */
udp_terminate(pstate, OK);
@ -500,6 +443,12 @@ static uint16_t udp_eventhandler(FAR struct net_driver_s *dev,
/* Indicate that the data has been consumed */
flags &= ~UDP_NEWDATA;
/* Indicate no data in the buffer */
netdev_iob_release(dev);
dev->d_buf = NULL;
}
}

View File

@ -172,6 +172,10 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
udp->udplen = HTONS(dev->d_sndlen + UDP_HDRLEN);
udp->udpchksum = 0;
/* Update the device buffer length */
iob_update_pktlen(dev->d_iob, dev->d_len);
#ifdef CONFIG_NET_UDP_CHECKSUMS
/* Calculate UDP checksum. */
@ -208,4 +212,46 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
#endif
}
}
/****************************************************************************
* Name: udpip_hdrsize
*
* Description:
* Get the total size of L3 and L4 UDP header
*
* Input Parameters:
* conn The connection structure associated with the socket
*
* Returned Value:
* the total size of L3 and L4 TCP header
*
****************************************************************************/
uint16_t udpip_hdrsize(FAR struct udp_conn_s *conn)
{
uint16_t hdrsize = sizeof(struct udp_hdr_s);
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
/* Which domain the socket used */
if (conn->domain == PF_INET)
{
/* Select the IPv4 domain */
return sizeof(struct ipv4_hdr_s) + hdrsize;
}
else /* if (domain == PF_INET6) */
{
/* Select the IPv6 domain */
return sizeof(struct ipv6_hdr_s) + hdrsize;
}
#elif defined(CONFIG_NET_IPv4)
((void)conn);
return sizeof(struct ipv4_hdr_s) + hdrsize;
#elif defined(CONFIG_NET_IPv6)
((void)conn);
return sizeof(struct ipv6_hdr_s) + hdrsize;
#endif
}
#endif /* CONFIG_NET && CONFIG_NET_UDP */

View File

@ -152,6 +152,12 @@ static void sendto_writebuffer_release(FAR struct udp_conn_s *conn)
wrb = (FAR struct udp_wrbuffer_s *)sq_remfirst(&conn->write_q);
DEBUGASSERT(wrb != NULL);
/* Do not need to release wb_iob, the life cycle of wb_iob is
* handed over to the network device
*/
wrb->wb_iob = NULL;
udp_wrbuffer_release(wrb);
/* Set up for the next packet transfer by setting the connection
@ -399,6 +405,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
if (dev->d_sndlen <= 0 && (flags & UDP_NEWDATA) == 0 &&
(flags & UDP_POLL) != 0 && !sq_empty(&conn->write_q))
{
uint16_t udpiplen = udpip_hdrsize(conn);
FAR struct udp_wrbuffer_s *wrb;
size_t sndlen;
@ -424,7 +431,7 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
* window size.
*/
sndlen = wrb->wb_iob->io_pktlen;
sndlen = wrb->wb_iob->io_pktlen - udpiplen;
ninfo("wrb=%p sndlen=%zu\n", wrb, sndlen);
#ifdef NEED_IPDOMAIN_SUPPORT
@ -436,11 +443,16 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
sendto_ipselect(dev, conn);
#endif
/* Release current device buffer and bypass the iob to l2 driver */
netdev_iob_release(dev);
/* Then set-up to send that amount of data with the offset
* corresponding to the size of the IP-dependent address structure.
*/
devif_iob_send(dev, wrb->wb_iob, sndlen, 0);
devif_iob_send(dev, wrb->wb_iob, sndlen, 0, udpiplen);
/* Free the write buffer at the head of the queue and attempt to
* setup the next transfer.
@ -496,6 +508,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
FAR struct udp_wrbuffer_s *wrb;
FAR struct udp_conn_s *conn;
unsigned int timeout;
uint16_t udpiplen;
bool nonblock;
bool empty;
int ret = OK;
@ -737,6 +750,13 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
memcpy(&wrb->wb_dest, to, tolen);
}
/* Skip l2/l3/l4 offset before copy */
udpiplen = udpip_hdrsize(conn);
iob_reserve(wrb->wb_iob, CONFIG_NET_LL_GUARDSIZE);
iob_update_pktlen(wrb->wb_iob, udpiplen);
/* Copy the user data into the write buffer. We cannot wait for
* buffer space if the socket was opened non-blocking.
*/
@ -744,7 +764,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
if (nonblock)
{
ret = iob_trycopyin(wrb->wb_iob, (FAR uint8_t *)buf,
len, 0, false);
len, udpiplen, false);
}
else
{
@ -757,7 +777,8 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
*/
blresult = net_breaklock(&count);
ret = iob_copyin(wrb->wb_iob, (FAR uint8_t *)buf, len, 0, false);
ret = iob_copyin(wrb->wb_iob, (FAR uint8_t *)buf,
len, udpiplen, false);
if (blresult >= 0)
{
net_restorelock(count);

View File

@ -62,9 +62,7 @@
struct sendto_s
{
#ifdef NEED_IPDOMAIN_SUPPORT
FAR struct udp_conn_s *st_conn; /* The UDP connection of interest */
#endif
FAR struct devif_callback_s *st_cb; /* Reference to callback instance */
FAR struct net_driver_s *st_dev; /* Driver that will perform the transmission */
sem_t st_sem; /* Semaphore signals sendto completion */
@ -206,7 +204,8 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
/* Copy the user data into d_appdata and send it */
devif_send(dev, pstate->st_buffer, pstate->st_buflen);
devif_send(dev, pstate->st_buffer,
pstate->st_buflen, udpip_hdrsize(pstate->st_conn));
pstate->st_sndlen = pstate->st_buflen;
}
@ -400,13 +399,11 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
state.st_buflen = len;
state.st_buffer = buf;
#ifdef NEED_IPDOMAIN_SUPPORT
/* Save the reference to the conn structure if it will be needed for
* asynchronous processing.
*/
state.st_conn = conn;
#endif
/* Check if the socket is connected */

View File

@ -90,6 +90,51 @@ uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len)
}
#endif /* CONFIG_NET_ARCH_CHKSUM */
/****************************************************************************
* Name: chksum_iob
*
* Description:
* Calculate the Internet checksum over an iob chain buffer.
*
* Input Parameters:
* sum - Partial calculations carried over from a previous call to
* chksum(). This should be zero on the first time that check
* sum is called.
* iob - An iob chain buffer over which the checksum is to be computed.
* offset - Specifies the byte offset of the start of valid data.
*
* Returned Value:
* The updated checksum value.
*
****************************************************************************/
#ifdef CONFIG_MM_IOB
uint16_t chksum_iob(uint16_t sum, FAR struct iob_s *iob, uint16_t offset)
{
/* Skip to the I/O buffer containing the data offset */
while (iob != NULL && offset > iob->io_len)
{
offset -= iob->io_len;
iob = iob->io_flink;
}
/* If the link pointer is not empty, loop to walk through all I/O buffer
* and accumulate the sum
*/
while (iob != NULL)
{
sum = chksum(sum, iob->io_data + iob->io_offset + offset,
iob->io_len - offset);
iob = iob->io_flink;
offset = 0;
}
return sum;
}
#endif /* CONFIG_MM_IOB */
/****************************************************************************
* Name: net_chksum
*
@ -123,6 +168,39 @@ uint16_t net_chksum(FAR uint16_t *data, uint16_t len)
}
#endif /* CONFIG_NET_ARCH_CHKSUM */
/****************************************************************************
* Name: net_chksum_iob
*
* Description:
* Calculate the Internet checksum over an iob chain buffer.
*
* The Internet checksum is the one's complement of the one's complement
* sum of all 16-bit words in the buffer.
*
* See RFC1071.
*
* If CONFIG_NET_ARCH_CHKSUM is defined, then this function must be
* provided by architecture-specific logic.
*
* Input Parameters:
* sum - Partial calculations carried over from a previous call to
* chksum(). This should be zero on the first time that check
* sum is called.
* iob - An iob chain buffer over which the checksum is to be computed.
* offset - Specifies the byte offset of the start of valid data.
*
* Returned Value:
* The Internet checksum of the given iob chain buffer.
*
****************************************************************************/
#ifdef CONFIG_MM_IOB
uint16_t net_chksum_iob(uint16_t sum, FAR struct iob_s *iob, uint16_t offset)
{
return HTONS(chksum_iob(sum, iob, offset));
}
#endif /* CONFIG_MM_IOB */
/****************************************************************************
* Name: net_chksum_adjust
*

View File

@ -61,6 +61,22 @@ uint16_t icmp_chksum(FAR struct net_driver_s *dev, int len)
}
#endif /* CONFIG_NET_ICMP */
/****************************************************************************
* Name: icmp_chksum_iob
*
* Description:
* Calculate the checksum of the ICMP message, the input can be an I/O
* buffer chain
*
****************************************************************************/
#if defined(CONFIG_NET_ICMP) && defined(CONFIG_MM_IOB)
uint16_t icmp_chksum_iob(FAR struct iob_s *iob)
{
return net_chksum_iob(0, iob, 0);
}
#endif /* CONFIG_NET_ICMP */
/****************************************************************************
* Name: icmpv6_chksum
*

View File

@ -93,7 +93,17 @@ uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto)
/* Sum IP payload data. */
sum = chksum(sum, IPBUF(iphdrlen), upperlen);
#ifdef CONFIG_MM_IOB
if (dev->d_iob != NULL)
{
sum = chksum_iob(sum, dev->d_iob, iphdrlen);
}
else
#endif
{
sum = chksum(sum, IPBUF(iphdrlen), upperlen);
}
return (sum == 0) ? 0xffff : HTONS(sum);
}
#endif /* CONFIG_NET_ARCH_CHKSUM */
@ -160,7 +170,17 @@ uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev,
/* Sum IP payload data. */
sum = chksum(sum, IPBUF(iplen), upperlen);
#ifdef CONFIG_MM_IOB
if (dev->d_iob != NULL)
{
sum = chksum_iob(sum, dev->d_iob, iplen);
}
else
#endif
{
sum = chksum(sum, IPBUF(iplen), upperlen);
}
return (sum == 0) ? 0xffff : HTONS(sum);
}
#endif /* CONFIG_NET_ARCH_CHKSUM */

View File

@ -286,6 +286,19 @@ uint16_t udp_ipv6_chksum(FAR struct net_driver_s *dev);
uint16_t icmp_chksum(FAR struct net_driver_s *dev, int len);
#endif
/****************************************************************************
* Name: icmp_chksum_iob
*
* Description:
* Calculate the checksum of the ICMP message, the input can be an I/O
* buffer chain
*
****************************************************************************/
#if defined(CONFIG_NET_ICMP) && defined(CONFIG_MM_IOB)
uint16_t icmp_chksum_iob(FAR struct iob_s *iob);
#endif /* CONFIG_NET_ICMP && CONFIG_MM_IOB */
/****************************************************************************
* Name: icmpv6_chksum
*