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:
parent
c26fd6565d
commit
34d2cde8a8
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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:
|
||||
*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
117
net/netdev/netdev_input.c
Normal 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
128
net/netdev/netdev_iob.c
Normal 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;
|
||||
}
|
||||
}
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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) */
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user