Fix probably where packets dropped because there was no recv() in place were being ACKed

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@381 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2007-11-15 22:38:32 +00:00
parent 9b0f9f10d6
commit 5ea5c4cf09
18 changed files with 125 additions and 76 deletions

View File

@ -218,5 +218,11 @@
* Basic client functionality verified: socket(), bind(), connect(), recv(), send().
0.3.1 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
* Separated net/uip/uip.c into several functions in several files.
* Separated net/uip/uip.c into several functions in several files.
* Corrected a TCP problem where packets were dropped because there was no
recv() in place but the packet was being ACKed. There are still TCP
recv buffering issues, but this is part of a larger buffering issue.

View File

@ -676,6 +676,9 @@ Other memory:
0.3.1 2007-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
* Separated net/uip/uip.c into several functions in several files.
* Corrected a TCP problem where packets were dropped because there was no
recv() in place but the packet was being ACKed. There are still TCP
recv buffering issues, but this is part of a larger buffering issue.
</pre></ul>
<table width ="100%">

7
TODO
View File

@ -43,6 +43,9 @@ o Network
nececcesary
(2) Copy buffer structure into uip_driver_structure when driver requests write
data
(3) Extra read buffers will be necessary to buffer TCP data when there is no recv
in place to accept the data. At present, received data is not ACKed, but is
eventually lost in this case.
- Improve performance by stimulating the driver to accept new TX data before the
next polling interval.
@ -55,10 +58,6 @@ o Network
polling should respond with TX data only if the UDP packet is intended for the
the network supported by the driver.
(2) If there were multiple drivers, polling would occur at double the rate.
- TCP Bug:
When TCP data is received with no read in place, it appears that uIP ACKs the data
even though it was not taken accepted. We must either (1) buffer incoming data, or
(2) not ACK it so that it will be re-sent.
o USB
- Implement USB device support

View File

@ -95,8 +95,6 @@ void up_block_task(_TCB *tcb, tstate_t task_state)
_TCB *rtcb = (_TCB*)g_readytorun.head;
boolean switch_needed;
lldbg("Blocking TCB=%p\n", tcb);
/* Remove the tcb task from the ready-to-run list. If we
* are blocking the task at the head of the task list (the
* most likely case), then a context switch to the next
@ -138,7 +136,6 @@ void up_block_task(_TCB *tcb, tstate_t task_state)
*/
rtcb = (_TCB*)g_readytorun.head;
lldbg("New Active Task TCB=%p\n", rtcb);
/* Then switch contexts */
@ -157,7 +154,6 @@ void up_block_task(_TCB *tcb, tstate_t task_state)
*/
rtcb = (_TCB*)g_readytorun.head;
lldbg("New Active Task TCB=%p\n", rtcb);
/* Then switch contexts */

View File

@ -91,8 +91,6 @@ void up_unblock_task(_TCB *tcb)
{
_TCB *rtcb = (_TCB*)g_readytorun.head;
lldbg("Unblocking TCB=%p\n", tcb);
/* Remove the task from the blocked task list */
sched_removeblocked(tcb);
@ -130,7 +128,6 @@ void up_unblock_task(_TCB *tcb)
*/
rtcb = (_TCB*)g_readytorun.head;
lldbg("New Active Task TCB=%p\n", rtcb);
/* Then switch contexts */
@ -151,7 +148,6 @@ void up_unblock_task(_TCB *tcb)
*/
rtcb = (_TCB*)g_readytorun.head;
lldbg("New Active Task TCB=%p\n", rtcb);
/* Then switch contexts */

View File

@ -260,10 +260,10 @@
# define CONFIG_DM9X_MODE DM9X_MODE_AUTO
#endif
/* TX poll deley = 5 seconds. CLK_TCK is the number of clock ticks per second */
/* TX poll deley = 1 seconds. CLK_TCK is the number of clock ticks per second */
#define DM6X_WDDELAY (5*CLK_TCK)
#define DM6X_POLLHSEC (5*2)
#define DM6X_WDDELAY (1*CLK_TCK)
#define DM6X_POLLHSEC (1*2)
/* TX timeout = 1 minute */

View File

@ -158,7 +158,7 @@ void send_client(void)
}
else if (nbytesrecvd != SENDSIZE)
{
message("client: Bad recv length=%d: %d\n", nbytessent);
message("client: Bad recv length=%d: %d\n", nbytesrecvd);
close(sockfd);
exit(-1);
}

View File

@ -185,10 +185,18 @@ struct uip_conn
/* Higher level logic can retain application specific information
* in the following:
*
* data_event() is called on all events. May return one of the following:
* UIP_CLOSE - Gracefully close the current connection
* UIP_ABORT - Abort (reset) the current connection on an error that
* prevents UIP_CLOSE from working.
* data_event() is called on all events. Normally, the input flags are
* returned, however, the implemenation may set one of the following:
*
* UIP_CLOSE - Gracefully close the current connection
* UIP_ABORT - Abort (reset) the current connection on an error that
* prevents UIP_CLOSE from working.
*
* Or clear the following:
*
* UIP_NEWDATA - May be cleared to suppress returning the ACK response.
* (dev->d_len should also be set to zero in this case).
*
* accept() is called when the TCP logic has created a connection
* connection_event() is called on any of the subset of connection-related events
*/
@ -255,18 +263,17 @@ struct uip_stats
} icmp; /* ICMP statistics. */
struct
{
uip_stats_t drop; /* Number of dropped TCP segments. */
uip_stats_t recv; /* Number of recived TCP segments. */
uip_stats_t recv; /* Number of received TCP segments. */
uip_stats_t sent; /* Number of sent TCP segments. */
uip_stats_t chkerr; /* Number of TCP segments with a bad checksum. */
uip_stats_t ackerr; /* Number of TCP segments with a bad ACK number. */
uip_stats_t rst; /* Number of recevied TCP RST (reset) segments. */
uip_stats_t rexmit; /* Number of retransmitted TCP segments. */
uip_stats_t syndrop; /* Number of dropped SYNs due to too few
connections was avaliable. */
uip_stats_t synrst; /* Number of SYNs for closed ports, triggering a RST. */
available connections. */
uip_stats_t synrst; /* Number of SYNs for closed ports triggering a RST. */
} tcp; /* TCP statistics. */
#ifdef CONFIG_NET_UDP

View File

@ -259,7 +259,8 @@ static uint8 tcp_connect_interrupt(struct uip_driver_s *dev,
sem_post(&pstate->tc_sem);
}
return 0;
return flags;
}
/****************************************************************************

View File

@ -123,6 +123,10 @@ static void recvfrom_newdata(struct uip_driver_s *dev, struct recvfrom_s *pstate
pstate->rf_recvlen += recvlen;
pstate->rf_buffer += recvlen;
pstate->rf_buflen -= recvlen;
/* Indicate no data in the buffer */
dev->d_len = 0;
}
/****************************************************************************
@ -313,7 +317,7 @@ static uint8 recvfrom_tcpinterrupt(struct uip_driver_s *dev,
}
#endif /* CONFIG_NET_SOCKOPTS && !CONFIG_DISABLE_CLOCK */
}
return 0;
return flags;
}
/****************************************************************************

View File

@ -180,7 +180,8 @@ static uint8 send_interrupt(struct uip_driver_s *dev, struct uip_conn *conn, uin
sem_post(&pstate->snd_sem);
}
return 0;
return flags;
}
/****************************************************************************

View File

@ -185,7 +185,7 @@ typeerr:
ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0;
uiphdr_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr);
uiphdr_ipaddr_copy(ICMPBUF->srcipaddr, dev->d_ipaddr);
uiphdr_ipaddr_copy(ICMPBUF->srcipaddr, &dev->d_ipaddr);
ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS;
ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */
memcpy(&(ICMPBUF->options[2]), &dev->d_mac, IFHWADDRLEN);
@ -207,7 +207,7 @@ typeerr:
ICMPBUF->type = ICMP6_ECHO_REPLY;
uiphdr_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr);
uiphdr_ipaddr_copy(ICMPBUF->srcipaddr, dev->d_ipaddr);
uiphdr_ipaddr_copy(ICMPBUF->srcipaddr, &dev->d_ipaddr);
ICMPBUF->icmpchksum = 0;
ICMPBUF->icmpchksum = ~uip_icmp6chksum(dev);
}

View File

@ -100,6 +100,8 @@ void uip_tcpappsend(struct uip_driver_s *dev, struct uip_conn *conn, uint8 resul
vdbg("result: %02x\n", result);
/* Check for connection aborted */
if (result & UIP_ABORT)
{
dev->d_sndlen = 0;
@ -109,6 +111,8 @@ void uip_tcpappsend(struct uip_driver_s *dev, struct uip_conn *conn, uint8 resul
uip_tcpsend(dev, conn, TCP_RST | TCP_ACK, UIP_IPTCPH_LEN);
}
/* Check for connection closed */
else if (result & UIP_CLOSE)
{
conn->tcpstateflags = UIP_FIN_WAIT_1;
@ -120,51 +124,56 @@ void uip_tcpappsend(struct uip_driver_s *dev, struct uip_conn *conn, uint8 resul
uip_tcpsend(dev, conn, TCP_FIN | TCP_ACK, UIP_IPTCPH_LEN);
}
/* If d_sndlen > 0, the application has data to be sent. */
/* None of the above */
else if (dev->d_sndlen > 0)
else
{
/* If the connection has acknowledged data, the contents of
* the ->len variable should be discarded.
*/
/* If d_sndlen > 0, the application has data to be sent. */
if (result & UIP_ACKDATA)
if (dev->d_sndlen > 0)
{
conn->len = 0;
}
/* If the ->len variable is non-zero the connection has
* already data in transit and cannot send anymore right
* now.
*/
if (conn->len == 0)
{
/* The application cannot send more than what is
* allowed by the mss (the minumum of the MSS and the
* available window).
/* If the connection has acknowledged data, the contents of
* the ->len variable should be discarded.
*/
if (dev->d_sndlen > conn->mss)
if (result & UIP_ACKDATA)
{
dev->d_sndlen = conn->mss;
conn->len = 0;
}
/* Remember how much data we send out now so that we
* know when everything has been acknowledged.
/* If the ->len variable is non-zero the connection has
* already data in transit and cannot send anymore right
* now.
*/
conn->len = dev->d_sndlen;
}
else
{
/* If the application already had unacknowledged data,
* we make sure that the application does not send
* (i.e., retransmit) out more than it previously sent
* out.
*/
if (conn->len == 0)
{
/* The application cannot send more than what is
* allowed by the mss (the minumum of the MSS and the
* available window).
*/
dev->d_sndlen = conn->len;
if (dev->d_sndlen > conn->mss)
{
dev->d_sndlen = conn->mss;
}
/* Remember how much data we send out now so that we
* know when everything has been acknowledged.
*/
conn->len = dev->d_sndlen;
}
else
{
/* If the application already had unacknowledged data,
* we make sure that the application does not send
* (i.e., retransmit) out more than it previously sent
* out.
*/
dev->d_sndlen = conn->len;
}
}
/* Then handle the rest of the operation just as for the rexmit case */

View File

@ -75,11 +75,13 @@
uint8 uip_tcpcallback(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags)
{
/* Preserve the UIP_ACKDATA & UIP_NEWDATA in the response. These are
* needed by uIP to handle ACKing and buffer state.
/* Preserve the UIP_ACKDATA, UIP_CLOSE, and UIP_ABORT in the response.
* These is needed by uIP to handle responses and buffer state. The
* UIP_NEWDATA indication will trigger the ACK response, but must be
* explicitly set in the callback.
*/
uint8 ret = flags & (UIP_ACKDATA|UIP_NEWDATA);
uint8 ret = flags;
vdbg("flags: %02x\n", flags);
@ -87,13 +89,37 @@ uint8 uip_tcpcallback(struct uip_driver_s *dev, struct uip_conn *conn, uint8 fla
if (conn->data_event)
{
/* Perform the callback. Callback function may return on of:
* UIP_CLOSE - Gracefully close the current connection
* UIP_ABORT - Abort (reset) the current connection on an error that
* prevents UIP_CLOSE from working.
/* Perform the callback. Callback function normally returns the input flags,
* however, the implemenation may set one of the following:
*
* UIP_CLOSE - Gracefully close the current connection
* UIP_ABORT - Abort (reset) the current connection on an error that
* prevents UIP_CLOSE from working.
*
* Or clear the following:
*
* UIP_NEWDATA - May be cleared to suppress returning the ACK response.
* (dev->d_len should also be set to zero in this case).
*/
ret |= conn->data_event(dev, conn, flags);
ret = conn->data_event(dev, conn, flags);
}
else if ((flags & UIP_CONN_EVENTS) == 0)
{
/* There is no handler to receive new data in place and this is not a
* connection event (which may also include new data that must be ACKed).
* In this case, clear the UIP_NEWDATA bit so that no ACK will be sent
* and drop the packet.
*/
dbg("No listener on connection\n");
#ifdef CONFIG_NET_STATISTICS
uip_stat.tcp.drop++;
#endif
ret &= ~UIP_NEWDATA;
dev->d_len = 0;
}
/* Check if there is a connection-related event and a connection

View File

@ -316,7 +316,7 @@ void uip_tcpreset(struct uip_driver_s *dev)
/* Swap IP addresses. */
uiphdr_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr);
uiphdr_ipaddr_copy(BUF->srcipaddr, dev->d_ipaddr);
uiphdr_ipaddr_copy(BUF->srcipaddr, &dev->d_ipaddr);
/* And send out the RST packet */

View File

@ -249,7 +249,7 @@ struct uip_udp_conn *uip_udpactive(struct uip_udpip_hdr *buf)
(conn->rport == 0 || buf->srcport == conn->rport) &&
(uip_ipaddr_cmp(conn->ripaddr, all_zeroes_addr) ||
uip_ipaddr_cmp(conn->ripaddr, all_ones_addr) ||
uiphdr_ipaddr_cmp(buf->srcipaddr, conn->ripaddr)))
uiphdr_ipaddr_cmp(buf->srcipaddr, &conn->ripaddr)))
{
/* Matching connection found.. return a reference to it */

View File

@ -345,5 +345,6 @@ uint8 uip_interrupt_event(struct uip_driver_s *dev, struct uip_conn *conn, uint8
{
senddata(dev, conn);
}
return 0;
return flags;
}

View File

@ -264,7 +264,7 @@ static uint16 parse_statusline(struct uip_driver_s *dev, uint16 len)
}
else
{
g_return = UIP_ABORT;
g_return |= UIP_ABORT;
webclient_aborted();
return 0;
}
@ -409,7 +409,7 @@ static void newdata(struct uip_driver_s *dev)
uint8 uip_interrupt_event(struct uip_driver_s *dev, struct uip_conn *conn, uint8 flags)
{
#warning OBSOLETE -- needs to be redesigned
g_return = 0;
g_return = flags;
if (uip_connected_event(flags))
{