net/ipforward, tcp, and udp: Fix a chicken and egg problem by eliminating the check of the arp/neighbor tables before packet transmission
1. For buffered tcp/udp case, if CONFIG_NET_ARP_SEND/CONFIG_NET_ARP_IPIN/CONFIG_NET_ICMPv6_NEIGHBOR isn't enabled and the table doesn't contain ip<->ethaddr mapping yet, the logic will skip the realtransmission and then arp/neighbor can't steal the final buffer to generate arp/icmpv6 packet. 2.for all other case, the tcp layer or user program should already contain the retransmit logic, the check is redundancy and may generate many duplicated packets if arp/icmpv6 response is too slow because the cursor stop forward. If user still concern about the very first packet lost, he could fix the issue by enabling CONFIG_NET_ARP_SEND/CONFIG_NET_ICMPv6_NEIGHBOR at begin.
This commit is contained in:
parent
a0ec67bc4c
commit
5fd8f78bf9
@ -110,84 +110,6 @@ static inline void forward_ipselect(FAR struct forward_s *fwd)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipfwd_addrchk
|
||||
*
|
||||
* Description:
|
||||
* Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor
|
||||
* tables. If not, then the send won't actually make it out... it will be
|
||||
* replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6).
|
||||
*
|
||||
* NOTE 1: This could be an expensive check if there are a lot of
|
||||
* entries in the ARP or Neighbor tables.
|
||||
*
|
||||
* NOTE 2: If we are actually harvesting IP addresses on incoming IP
|
||||
* packets, then this check should not be necessary; the MAC mapping
|
||||
* should already be in the ARP table in many cases (IPv4 only).
|
||||
*
|
||||
* NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP
|
||||
* address mapping is already in the ARP table.
|
||||
*
|
||||
* Input Parameters:
|
||||
* fwd - The forwarding state structure
|
||||
*
|
||||
* Returned Value:
|
||||
* true - The Ethernet MAC address is in the ARP or Neighbor table (OR
|
||||
* the network device is not Ethernet).
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
static inline bool ipfwd_addrchk(FAR struct forward_s *fwd)
|
||||
{
|
||||
DEBUGASSERT(fwd != NULL && fwd->f_iob != NULL && fwd->f_dev != NULL);
|
||||
|
||||
/* REVISIT: Could the MAC address not also be in a routing table? */
|
||||
|
||||
if (fwd->f_dev->d_lltype != NET_LL_ETHERNET)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (fwd->f_domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
|
||||
FAR struct ipv4_hdr_s *ipv4 = (FAR struct ipv4_hdr_s *)fwd->f_iob->io_data;
|
||||
int ret;
|
||||
|
||||
ret = arp_find(*(in_addr_t *)ipv4->destipaddr, NULL);
|
||||
return (ret >= 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if defined(CONFIG_NET_ICMPv6_NEIGHBOR)
|
||||
FAR struct ipv6_hdr_s *ipv6 = (FAR struct ipv6_hdr_s *)fwd->f_iob->io_data;
|
||||
return (neighbor_lookup(ipv6->destipaddr, NULL) >= 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
}
|
||||
|
||||
#else /* CONFIG_NET_ETHERNET */
|
||||
# define ipfwd_addrchk(r) (true)
|
||||
#endif /* CONFIG_NET_ETHERNET */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ipfwd_eventhandler
|
||||
*
|
||||
@ -266,16 +188,6 @@ static uint16_t ipfwd_eventhandler(FAR struct net_driver_s *dev, FAR void *conn,
|
||||
|
||||
devif_forward(fwd);
|
||||
flags &= ~DEVPOLL_MASK;
|
||||
|
||||
/* Check if the destination IP address is in the ARP or Neighbor
|
||||
* table. If not, then the send won't actually make it out... it
|
||||
* will be replaced with an ARP request or Neighbor Solicitation.
|
||||
*/
|
||||
|
||||
if (!ipfwd_addrchk(fwd))
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the allocated callback structure */
|
||||
|
@ -291,140 +291,6 @@ static inline void send_ipselect(FAR struct net_driver_s *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_send_addrchck
|
||||
*
|
||||
* Description:
|
||||
* Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor
|
||||
* tables. If not, then the send won't actually make it out... it will be
|
||||
* replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6).
|
||||
*
|
||||
* NOTE 1: This could be an expensive check if there are a lot of
|
||||
* entries in the ARP or Neighbor tables.
|
||||
*
|
||||
* NOTE 2: If we are actually harvesting IP addresses on incoming IP
|
||||
* packets, then this check should not be necessary; the MAC mapping
|
||||
* should already be in the ARP table in many cases (IPv4 only).
|
||||
*
|
||||
* NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP
|
||||
* address mapping is already in the ARP table.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* true - The Ethernet MAC address is in the ARP or Neighbor table (OR
|
||||
* the network device is not Ethernet).
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn)
|
||||
{
|
||||
/* Only Ethernet drivers are supported by this function.
|
||||
*
|
||||
* REVISIT: Could the MAC address not also be in a routing table?
|
||||
*/
|
||||
|
||||
if (conn->dev->d_lltype != NET_LL_ETHERNET)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (conn->domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
/* For historical reasons, we will return true if both the ARP and the
|
||||
* routing table are disabled.
|
||||
*/
|
||||
|
||||
bool ret = true;
|
||||
#ifdef CONFIG_NET_ROUTE
|
||||
in_addr_t router;
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
|
||||
if (arp_find(conn->u.ipv4.raddr, NULL) >= 0)
|
||||
{
|
||||
/* Return true if the address was found in the ARP table */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, return false */
|
||||
|
||||
ret = false;
|
||||
#endif
|
||||
#ifdef CONFIG_NET_ROUTE
|
||||
if (net_ipv4_router(conn->u.ipv4.raddr, &router) == OK)
|
||||
{
|
||||
/* Return true if the address was found in the routing table */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, return false */
|
||||
|
||||
ret = false;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* For historical reasons, we will return true if both the ICMPv6
|
||||
* neighbor support and the routing table are disabled.
|
||||
*/
|
||||
|
||||
bool ret = true;
|
||||
#ifdef CONFIG_NET_ROUTE
|
||||
net_ipv6addr_t router;
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR)
|
||||
if (neighbor_lookup(conn->u.ipv6.raddr, NULL) >= 0)
|
||||
{
|
||||
/* Return true if the address was found in the neighbor table */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, return false */
|
||||
|
||||
ret = false;
|
||||
#endif
|
||||
#ifdef CONFIG_NET_ROUTE
|
||||
if (net_ipv6_router(conn->u.ipv6.raddr, router) == OK)
|
||||
{
|
||||
/* Return true if the address was found in the routing table */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, return false */
|
||||
|
||||
ret = false;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
}
|
||||
|
||||
#else /* CONFIG_NET_ETHERNET */
|
||||
# define psock_send_addrchck(r) (true)
|
||||
#endif /* CONFIG_NET_ETHERNET */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_send_eventhandler
|
||||
*
|
||||
@ -826,139 +692,131 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
||||
!(sq_empty(&conn->write_q)) &&
|
||||
conn->winsize > 0)
|
||||
{
|
||||
/* Check if the destination IP address is in the ARP or Neighbor
|
||||
* table. If not, then the send won't actually make it out... it
|
||||
* will be replaced with an ARP request or Neighbor Solicitation.
|
||||
FAR struct tcp_wrbuffer_s *wrb;
|
||||
uint32_t predicted_seqno;
|
||||
size_t sndlen;
|
||||
|
||||
/* Peek at the head of the write queue (but don't remove anything
|
||||
* from the write queue yet). We know from the above test that
|
||||
* the write_q is not empty.
|
||||
*/
|
||||
|
||||
if (psock_send_addrchck(conn))
|
||||
wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||
DEBUGASSERT(wrb);
|
||||
|
||||
/* Get the amount of data that we can send in the next packet.
|
||||
* We will send either the remaining data in the buffer I/O
|
||||
* buffer chain, or as much as will fit given the MSS and current
|
||||
* window size.
|
||||
*/
|
||||
|
||||
sndlen = TCP_WBPKTLEN(wrb) - TCP_WBSENT(wrb);
|
||||
if (sndlen > conn->mss)
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *wrb;
|
||||
uint32_t predicted_seqno;
|
||||
size_t sndlen;
|
||||
sndlen = conn->mss;
|
||||
}
|
||||
|
||||
/* Peek at the head of the write queue (but don't remove anything
|
||||
* from the write queue yet). We know from the above test that
|
||||
* the write_q is not empty.
|
||||
*/
|
||||
if (sndlen > conn->winsize)
|
||||
{
|
||||
sndlen = conn->winsize;
|
||||
}
|
||||
|
||||
wrb = (FAR struct tcp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||
DEBUGASSERT(wrb);
|
||||
ninfo("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u mss=%u "
|
||||
"winsize=%u\n",
|
||||
wrb, TCP_WBPKTLEN(wrb), TCP_WBSENT(wrb), sndlen, conn->mss,
|
||||
conn->winsize);
|
||||
|
||||
/* Get the amount of data that we can send in the next packet.
|
||||
* We will send either the remaining data in the buffer I/O
|
||||
* buffer chain, or as much as will fit given the MSS and current
|
||||
* window size.
|
||||
*/
|
||||
/* Set the sequence number for this segment. If we are
|
||||
* retransmitting, then the sequence number will already
|
||||
* be set for this write buffer.
|
||||
*/
|
||||
|
||||
sndlen = TCP_WBPKTLEN(wrb) - TCP_WBSENT(wrb);
|
||||
if (sndlen > conn->mss)
|
||||
{
|
||||
sndlen = conn->mss;
|
||||
}
|
||||
if (TCP_WBSEQNO(wrb) == (unsigned)-1)
|
||||
{
|
||||
TCP_WBSEQNO(wrb) = conn->isn + conn->sent;
|
||||
}
|
||||
|
||||
if (sndlen > conn->winsize)
|
||||
{
|
||||
sndlen = conn->winsize;
|
||||
}
|
||||
/* The TCP stack updates sndseq on receipt of ACK *before*
|
||||
* this function is called. In that case sndseq will point
|
||||
* to the next unacknowledged byte (which might have already
|
||||
* been sent). We will overwrite the value of sndseq here
|
||||
* before the packet is sent.
|
||||
*/
|
||||
|
||||
ninfo("SEND: wrb=%p pktlen=%u sent=%u sndlen=%u mss=%u "
|
||||
"winsize=%u\n",
|
||||
wrb, TCP_WBPKTLEN(wrb), TCP_WBSENT(wrb), sndlen, conn->mss,
|
||||
conn->winsize);
|
||||
|
||||
/* Set the sequence number for this segment. If we are
|
||||
* retransmitting, then the sequence number will already
|
||||
* be set for this write buffer.
|
||||
*/
|
||||
|
||||
if (TCP_WBSEQNO(wrb) == (unsigned)-1)
|
||||
{
|
||||
TCP_WBSEQNO(wrb) = conn->isn + conn->sent;
|
||||
}
|
||||
|
||||
/* The TCP stack updates sndseq on receipt of ACK *before*
|
||||
* this function is called. In that case sndseq will point
|
||||
* to the next unacknowledged byte (which might have already
|
||||
* been sent). We will overwrite the value of sndseq here
|
||||
* before the packet is sent.
|
||||
*/
|
||||
|
||||
tcp_setsequence(conn->sndseq, TCP_WBSEQNO(wrb) + TCP_WBSENT(wrb));
|
||||
tcp_setsequence(conn->sndseq, TCP_WBSEQNO(wrb) + TCP_WBSENT(wrb));
|
||||
|
||||
#ifdef NEED_IPDOMAIN_SUPPORT
|
||||
/* If both IPv4 and IPv6 support are enabled, then we will need to
|
||||
* select which one to use when generating the outgoing packet.
|
||||
* If only one domain is selected, then the setup is already in
|
||||
* place and we need do nothing.
|
||||
*/
|
||||
/* If both IPv4 and IPv6 support are enabled, then we will need to
|
||||
* select which one to use when generating the outgoing packet.
|
||||
* If only one domain is selected, then the setup is already in
|
||||
* place and we need do nothing.
|
||||
*/
|
||||
|
||||
send_ipselect(dev, conn);
|
||||
send_ipselect(dev, conn);
|
||||
#endif
|
||||
/* Then set-up to send that amount of data with the offset
|
||||
* corresponding to the amount of data already sent. (this
|
||||
* won't actually happen until the polling cycle completes).
|
||||
*/
|
||||
/* Then set-up to send that amount of data with the offset
|
||||
* corresponding to the amount of data already sent. (this
|
||||
* 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));
|
||||
|
||||
/* Remember how much data we send out now so that we know
|
||||
* when everything has been acknowledged. Just increment
|
||||
* the amount of data sent. This will be needed in sequence
|
||||
* number calculations.
|
||||
*/
|
||||
/* Remember how much data we send out now so that we know
|
||||
* when everything has been acknowledged. Just increment
|
||||
* the amount of data sent. This will be needed in sequence
|
||||
* number calculations.
|
||||
*/
|
||||
|
||||
conn->unacked += sndlen;
|
||||
conn->sent += sndlen;
|
||||
conn->unacked += sndlen;
|
||||
conn->sent += sndlen;
|
||||
|
||||
/* Below prediction will become true, unless retransmission occurrence */
|
||||
/* Below prediction will become true, unless retransmission occurrence */
|
||||
|
||||
predicted_seqno = tcp_getsequence(conn->sndseq) + sndlen;
|
||||
predicted_seqno = tcp_getsequence(conn->sndseq) + sndlen;
|
||||
|
||||
if ((predicted_seqno > conn->sndseq_max) ||
|
||||
(tcp_getsequence(conn->sndseq) > predicted_seqno)) /* overflow */
|
||||
{
|
||||
conn->sndseq_max = predicted_seqno;
|
||||
}
|
||||
|
||||
ninfo("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n",
|
||||
wrb, TCP_WBNRTX(wrb), conn->unacked, conn->sent);
|
||||
|
||||
/* Increment the count of bytes sent from this write buffer */
|
||||
|
||||
TCP_WBSENT(wrb) += sndlen;
|
||||
|
||||
ninfo("SEND: wrb=%p sent=%u pktlen=%u\n",
|
||||
wrb, TCP_WBSENT(wrb), TCP_WBPKTLEN(wrb));
|
||||
|
||||
/* Remove the write buffer from the write queue if the
|
||||
* last of the data has been sent from the buffer.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(TCP_WBSENT(wrb) <= TCP_WBPKTLEN(wrb));
|
||||
if (TCP_WBSENT(wrb) >= TCP_WBPKTLEN(wrb))
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *tmp;
|
||||
|
||||
ninfo("SEND: wrb=%p Move to unacked_q\n", wrb);
|
||||
|
||||
tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
|
||||
DEBUGASSERT(tmp == wrb);
|
||||
UNUSED(tmp);
|
||||
|
||||
/* Put the I/O buffer chain in the un-acked queue; the
|
||||
* segment is waiting for ACK again
|
||||
*/
|
||||
|
||||
psock_insert_segment(wrb, &conn->unacked_q);
|
||||
}
|
||||
|
||||
/* Only one data can be sent by low level driver at once,
|
||||
* tell the caller stop polling the other connection.
|
||||
*/
|
||||
|
||||
flags &= ~TCP_POLL;
|
||||
if ((predicted_seqno > conn->sndseq_max) ||
|
||||
(tcp_getsequence(conn->sndseq) > predicted_seqno)) /* overflow */
|
||||
{
|
||||
conn->sndseq_max = predicted_seqno;
|
||||
}
|
||||
|
||||
ninfo("SEND: wrb=%p nrtx=%u unacked=%u sent=%u\n",
|
||||
wrb, TCP_WBNRTX(wrb), conn->unacked, conn->sent);
|
||||
|
||||
/* Increment the count of bytes sent from this write buffer */
|
||||
|
||||
TCP_WBSENT(wrb) += sndlen;
|
||||
|
||||
ninfo("SEND: wrb=%p sent=%u pktlen=%u\n",
|
||||
wrb, TCP_WBSENT(wrb), TCP_WBPKTLEN(wrb));
|
||||
|
||||
/* Remove the write buffer from the write queue if the
|
||||
* last of the data has been sent from the buffer.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(TCP_WBSENT(wrb) <= TCP_WBPKTLEN(wrb));
|
||||
if (TCP_WBSENT(wrb) >= TCP_WBPKTLEN(wrb))
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *tmp;
|
||||
|
||||
ninfo("SEND: wrb=%p Move to unacked_q\n", wrb);
|
||||
|
||||
tmp = (FAR struct tcp_wrbuffer_s *)sq_remfirst(&conn->write_q);
|
||||
DEBUGASSERT(tmp == wrb);
|
||||
UNUSED(tmp);
|
||||
|
||||
/* Put the I/O buffer chain in the un-acked queue; the
|
||||
* segment is waiting for ACK again
|
||||
*/
|
||||
|
||||
psock_insert_segment(wrb, &conn->unacked_q);
|
||||
}
|
||||
|
||||
/* Only one data can be sent by low level driver at once,
|
||||
* tell the caller stop polling the other connection.
|
||||
*/
|
||||
|
||||
flags &= ~TCP_POLL;
|
||||
}
|
||||
|
||||
/* Continue waiting */
|
||||
|
@ -201,141 +201,6 @@ static inline void tcpsend_ipselect(FAR struct net_driver_s *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: psock_send_addrchck
|
||||
*
|
||||
* Description:
|
||||
* Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor
|
||||
* tables. If not, then the send won't actually make it out... it will be
|
||||
* replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6).
|
||||
*
|
||||
* NOTE 1: This could be an expensive check if there are a lot of
|
||||
* entries in the ARP or Neighbor tables.
|
||||
*
|
||||
* NOTE 2: If we are actually harvesting IP addresses on incoming IP
|
||||
* packets, then this check should not be necessary; the MAC mapping
|
||||
* should already be in the ARP table in many cases (IPv4 only).
|
||||
*
|
||||
* NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP
|
||||
* address mapping is already in the ARP table.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* true - The Ethernet MAC address is in the ARP or Neighbor table (OR
|
||||
* the network device is not Ethernet).
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn)
|
||||
{
|
||||
/* Only Ethernet drivers are supported by this function.
|
||||
*
|
||||
* REVISIT: Could the MAC address not also be in a routing table?
|
||||
*/
|
||||
|
||||
if (conn->dev->d_lltype != NET_LL_ETHERNET)
|
||||
{
|
||||
/* Return true for non-Ethernet devices. */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (conn->domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
/* For historical reasons, we will return true if both the ARP and the
|
||||
* routing table are disabled.
|
||||
*/
|
||||
|
||||
bool ret = true;
|
||||
#ifdef CONFIG_NET_ROUTE
|
||||
in_addr_t router;
|
||||
#endif
|
||||
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
|
||||
if (arp_find(conn->u.ipv4.raddr, NULL) >= 0)
|
||||
{
|
||||
/* Return true if the address was found in the ARP table */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, return false */
|
||||
|
||||
ret = false;
|
||||
#endif
|
||||
#ifdef CONFIG_NET_ROUTE
|
||||
if (net_ipv4_router(conn->u.ipv4.raddr, &router) == OK)
|
||||
{
|
||||
/* Return true if the address was found in the routing table */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, return false */
|
||||
|
||||
ret = false;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* For historical reasons, we will return true if both the ICMPv6
|
||||
* neighbor support and the routing table are disabled.
|
||||
*/
|
||||
|
||||
bool ret = true;
|
||||
#ifdef CONFIG_NET_ROUTE
|
||||
net_ipv6addr_t router;
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR)
|
||||
if (neighbor_lookup(conn->u.ipv6.raddr, NULL) >= 0)
|
||||
{
|
||||
/* Return true if the address was found in the neighbor table */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, return false */
|
||||
|
||||
ret = false;
|
||||
#endif
|
||||
#ifdef CONFIG_NET_ROUTE
|
||||
if (net_ipv6_router(conn->u.ipv6.raddr, router) == OK)
|
||||
{
|
||||
/* Return true if the address was found in the routing table */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, return false */
|
||||
|
||||
ret = false;
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
}
|
||||
|
||||
#else /* CONFIG_NET_ETHERNET */
|
||||
# define psock_send_addrchck(r) (true)
|
||||
#endif /* CONFIG_NET_ETHERNET */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tcpsend_eventhandler
|
||||
*
|
||||
@ -628,19 +493,11 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
|
||||
|
||||
devif_send(dev, &pstate->snd_buffer[pstate->snd_sent], sndlen);
|
||||
|
||||
/* Check if the destination IP address is in the ARP or Neighbor
|
||||
* table. If not, then the send won't actually make it out... it
|
||||
* will be replaced with an ARP request or Neighbor Solicitation.
|
||||
*/
|
||||
/* Update the amount of data sent (but not necessarily ACKed) */
|
||||
|
||||
if (pstate->snd_sent != 0 || psock_send_addrchck(conn))
|
||||
{
|
||||
/* Update the amount of data sent (but not necessarily ACKed) */
|
||||
|
||||
pstate->snd_sent += sndlen;
|
||||
ninfo("SEND: acked=%d sent=%d buflen=%d\n",
|
||||
pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen);
|
||||
}
|
||||
pstate->snd_sent += sndlen;
|
||||
ninfo("SEND: acked=%d sent=%d buflen=%d\n",
|
||||
pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen);
|
||||
}
|
||||
}
|
||||
|
||||
@ -664,6 +521,7 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev,
|
||||
return flags;
|
||||
|
||||
end_wait:
|
||||
|
||||
/* Do not allow any further callbacks */
|
||||
|
||||
pstate->snd_cb->flags = 0;
|
||||
|
@ -258,69 +258,6 @@ static uint16_t ack_eventhandler(FAR struct net_driver_s *dev,
|
||||
return flags;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sendfile_addrcheck
|
||||
*
|
||||
* Description:
|
||||
* Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor
|
||||
* tables. If not, then the send won't actually make it out... it will be
|
||||
* replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6).
|
||||
*
|
||||
* NOTE 1: This could be an expensive check if there are a lot of
|
||||
* entries in the ARP or Neighbor tables.
|
||||
*
|
||||
* NOTE 2: If we are actually harvesting IP addresses on incoming IP
|
||||
* packets, then this check should not be necessary; the MAC mapping
|
||||
* should already be in the ARP table in many cases (IPv4 only).
|
||||
*
|
||||
* NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP
|
||||
* address mapping is already in the ARP table.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The TCP connection structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
static inline bool sendfile_addrcheck(FAR struct tcp_conn_s *conn)
|
||||
{
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (conn->domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
|
||||
return (arp_find(conn->u.ipv4.raddr, NULL) >= 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR)
|
||||
return (neighbor_lookup(conn->u.ipv6.raddr, NULL) >= 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
}
|
||||
|
||||
#else /* CONFIG_NET_ETHERNET */
|
||||
# sendfile_addrcheck(r) (true)
|
||||
#endif /* CONFIG_NET_ETHERNET */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sendfile_eventhandler
|
||||
*
|
||||
@ -451,19 +388,11 @@ static uint16_t sendfile_eventhandler(FAR struct net_driver_s *dev,
|
||||
|
||||
tcp_setsequence(conn->sndseq, seqno);
|
||||
|
||||
/* Check if the destination IP address is in the ARP or Neighbor
|
||||
* table. If not, then the send won't actually make it out... it
|
||||
* will be replaced with an ARP request or Neighbor Solicitation.
|
||||
*/
|
||||
/* Update the amount of data sent (but not necessarily ACKed) */
|
||||
|
||||
if (pstate->snd_sent != 0 || sendfile_addrcheck(conn))
|
||||
{
|
||||
/* Update the amount of data sent (but not necessarily ACKed) */
|
||||
|
||||
pstate->snd_sent += sndlen;
|
||||
ninfo("pid: %d SEND: acked=%d sent=%d flen=%d\n", getpid(),
|
||||
pstate->snd_acked, pstate->snd_sent, pstate->snd_flen);
|
||||
}
|
||||
pstate->snd_sent += sndlen;
|
||||
ninfo("pid: %d SEND: acked=%d sent=%d flen=%d\n", getpid(),
|
||||
pstate->snd_acked, pstate->snd_sent, pstate->snd_flen);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -109,12 +109,6 @@
|
||||
static inline void sendto_ipselect(FAR struct net_driver_s *dev,
|
||||
FAR struct udp_conn_s *conn);
|
||||
#endif
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn,
|
||||
FAR struct net_driver_s *dev);
|
||||
#else
|
||||
# define sendto_addrcheck(c,d) (true)
|
||||
#endif
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
static inline int sendto_timeout(FAR struct socket *psock,
|
||||
FAR struct udp_conn_s *conn);
|
||||
@ -239,76 +233,6 @@ static inline void sendto_ipselect(FAR struct net_driver_s *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sendto_addrcheck
|
||||
*
|
||||
* Description:
|
||||
* Check if the destination IP address is in the IPv4 ARP or IPv6 Neighbor
|
||||
* tables. If not, then the send won't actually make it out... it will be
|
||||
* replaced with an ARP request (IPv4) or a Neighbor Solicitation (IPv6).
|
||||
*
|
||||
* NOTE 1: This could be an expensive check if there are a lot of
|
||||
* entries in the ARP or Neighbor tables.
|
||||
*
|
||||
* NOTE 2: If we are actually harvesting IP addresses on incoming IP
|
||||
* packets, then this check should not be necessary; the MAC mapping
|
||||
* should already be in the ARP table in many cases (IPv4 only).
|
||||
*
|
||||
* NOTE 3: If CONFIG_NET_ARP_SEND then we can be assured that the IP
|
||||
* address mapping is already in the ARP table.
|
||||
*
|
||||
* Input Parameters:
|
||||
* conn - The UDP connection structure
|
||||
* dev - Polling network device
|
||||
*
|
||||
* Returned Value:
|
||||
* true - The Ethernet MAC address is in the ARP or Neighbor table (OR
|
||||
* the network device is not Ethernet).
|
||||
*
|
||||
* Assumptions:
|
||||
* The network is locked
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_ETHERNET
|
||||
static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn,
|
||||
FAR struct net_driver_s *dev)
|
||||
{
|
||||
/* REVISIT: Could the MAC address not also be in a routing table? */
|
||||
|
||||
if (dev->d_lltype != NET_LL_ETHERNET)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
if (conn->domain == PF_INET)
|
||||
#endif
|
||||
{
|
||||
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
|
||||
return (arp_find(conn->u.ipv4.raddr, NULL) >= 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv4 */
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#if !defined(CONFIG_NET_ICMPv6_NEIGHBOR)
|
||||
return (neighbor_lookup(conn->u.ipv6.raddr, NULL) >= 0);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
#endif /* CONFIG_NET_IPv6 */
|
||||
}
|
||||
#endif /* CONFIG_NET_ETHERNET */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sendto_timeout
|
||||
*
|
||||
@ -514,61 +438,52 @@ 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))
|
||||
{
|
||||
/* Check if the destination IP address is in the ARP, Neighbor
|
||||
* table, or routing table. If not, then the send won't actually
|
||||
* make it out... it will be replaced with an ARP request or
|
||||
* Neighbor Solicitation.
|
||||
FAR struct udp_wrbuffer_s *wrb;
|
||||
size_t sndlen;
|
||||
|
||||
/* Peek at the head of the write queue (but don't remove anything
|
||||
* from the write queue yet). We know from the above test that
|
||||
* the write_q is not empty.
|
||||
*/
|
||||
|
||||
if (sendto_addrcheck(conn, dev))
|
||||
{
|
||||
FAR struct udp_wrbuffer_s *wrb;
|
||||
size_t sndlen;
|
||||
wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||
DEBUGASSERT(wrb != NULL);
|
||||
|
||||
/* Peek at the head of the write queue (but don't remove anything
|
||||
* from the write queue yet). We know from the above test that
|
||||
* the write_q is not empty.
|
||||
*/
|
||||
/* Get the amount of data that we can send in the next packet.
|
||||
* We will send either the remaining data in the buffer I/O
|
||||
* buffer chain, or as much as will fit given the MSS and current
|
||||
* window size.
|
||||
*/
|
||||
|
||||
wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
|
||||
DEBUGASSERT(wrb != NULL);
|
||||
|
||||
/* Get the amount of data that we can send in the next packet.
|
||||
* We will send either the remaining data in the buffer I/O
|
||||
* buffer chain, or as much as will fit given the MSS and current
|
||||
* window size.
|
||||
*/
|
||||
|
||||
sndlen = wrb->wb_iob->io_pktlen;
|
||||
ninfo("wrb=%p sndlen=%u\n", wrb, sndlen);
|
||||
sndlen = wrb->wb_iob->io_pktlen;
|
||||
ninfo("wrb=%p sndlen=%u\n", wrb, sndlen);
|
||||
|
||||
#ifdef NEED_IPDOMAIN_SUPPORT
|
||||
/* If both IPv4 and IPv6 support are enabled, then we will need to
|
||||
* select which one to use when generating the outgoing packet.
|
||||
* If only one domain is selected, then the setup is already in
|
||||
* place and we need do nothing.
|
||||
*/
|
||||
/* If both IPv4 and IPv6 support are enabled, then we will need to
|
||||
* select which one to use when generating the outgoing packet.
|
||||
* If only one domain is selected, then the setup is already in
|
||||
* place and we need do nothing.
|
||||
*/
|
||||
|
||||
sendto_ipselect(dev, conn);
|
||||
sendto_ipselect(dev, conn);
|
||||
#endif
|
||||
/* Then set-up to send that amount of data with the offset
|
||||
* corresponding to the size of the IP-dependent address structure.
|
||||
*/
|
||||
/* 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);
|
||||
|
||||
/* Free the write buffer at the head of the queue and attempt to
|
||||
* setup the next transfer.
|
||||
*/
|
||||
/* Free the write buffer at the head of the queue and attempt to
|
||||
* setup the next transfer.
|
||||
*/
|
||||
|
||||
sendto_writebuffer_release(psock, conn);
|
||||
sendto_writebuffer_release(psock, conn);
|
||||
|
||||
/* Only one data can be sent by low level driver at once,
|
||||
* tell the caller stop polling the other connections.
|
||||
*/
|
||||
/* Only one data can be sent by low level driver at once,
|
||||
* tell the caller stop polling the other connections.
|
||||
*/
|
||||
|
||||
flags &= ~UDP_POLL;
|
||||
}
|
||||
flags &= ~UDP_POLL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_SOCKOPTS
|
||||
|
Loading…
Reference in New Issue
Block a user