mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-01-27 12:35:26 +00:00
Kieran Mansley - 14th July 2004
* Fixed whitespace indenting in parts of tcp_in.c * Changed adjustment of ssthresh in response to fast retransmit * Commented out iteration of unsent list when new ACK received as we no longer put all unacked data on unsent list when retransmitting
This commit is contained in:
parent
8d052ecf24
commit
c356f560e8
@ -700,43 +700,48 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
pcb->acked = 0;
|
pcb->acked = 0;
|
||||||
|
|
||||||
if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){
|
if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){
|
||||||
++pcb->dupacks;
|
++pcb->dupacks;
|
||||||
if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
|
if (pcb->dupacks >= 3 && pcb->unacked != NULL) {
|
||||||
if (!(pcb->flags & TF_INFR)) {
|
if (!(pcb->flags & TF_INFR)) {
|
||||||
/* This is fast retransmit. Retransmit the first unacked segment. */
|
/* This is fast retransmit. Retransmit the first unacked segment. */
|
||||||
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %u (%lu), fast retransmit %lu\n",
|
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %u (%lu), fast retransmit %lu\n",
|
||||||
(unsigned int)pcb->dupacks, pcb->lastack,
|
(unsigned int)pcb->dupacks, pcb->lastack,
|
||||||
ntohl(pcb->unacked->tcphdr->seqno)));
|
ntohl(pcb->unacked->tcphdr->seqno)));
|
||||||
tcp_rexmit(pcb);
|
tcp_rexmit(pcb);
|
||||||
/* Set ssthresh to max (FlightSize / 2, 2*SMSS) */
|
/* Set ssthresh to max (FlightSize / 2, 2*SMSS) */
|
||||||
pcb->ssthresh = LWIP_MAX((pcb->snd_max -
|
/*pcb->ssthresh = LWIP_MAX((pcb->snd_max -
|
||||||
pcb->lastack) / 2,
|
pcb->lastack) / 2,
|
||||||
2 * pcb->mss);
|
2 * pcb->mss);*/
|
||||||
|
/* Set ssthresh to half of the minimum of the currenct cwnd and the advertised window */
|
||||||
|
if(pcb->cwnd > pcb->snd_wnd)
|
||||||
|
pcb->ssthresh = pcb->snd_wnd / 2;
|
||||||
|
else
|
||||||
|
pcb->ssthresh = pcb->cwnd / 2;
|
||||||
|
|
||||||
pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
|
pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;
|
||||||
pcb->flags |= TF_INFR;
|
pcb->flags |= TF_INFR;
|
||||||
} else {
|
} else {
|
||||||
/* Inflate the congestion window, but not if it means that
|
/* Inflate the congestion window, but not if it means that
|
||||||
the value overflows. */
|
the value overflows. */
|
||||||
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
|
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
|
||||||
pcb->cwnd += pcb->mss;
|
pcb->cwnd += pcb->mss;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %lu %lu\n",
|
LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %lu %lu\n",
|
||||||
pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));
|
pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));
|
||||||
}
|
}
|
||||||
} else if (TCP_SEQ_LT(pcb->lastack, ackno) &&
|
} else if (TCP_SEQ_LT(pcb->lastack, ackno) &&
|
||||||
TCP_SEQ_LEQ(ackno, pcb->snd_max)) {
|
TCP_SEQ_LEQ(ackno, pcb->snd_max)) {
|
||||||
/* We come here when the ACK acknowledges new data. */
|
/* We come here when the ACK acknowledges new data. */
|
||||||
|
|
||||||
/* Reset the "IN Fast Retransmit" flag, since we are no longer
|
/* Reset the "IN Fast Retransmit" flag, since we are no longer
|
||||||
in fast retransmit. Also reset the congestion window to the
|
in fast retransmit. Also reset the congestion window to the
|
||||||
slow start threshold. */
|
slow start threshold. */
|
||||||
if (pcb->flags & TF_INFR) {
|
if (pcb->flags & TF_INFR) {
|
||||||
pcb->flags &= ~TF_INFR;
|
pcb->flags &= ~TF_INFR;
|
||||||
pcb->cwnd = pcb->ssthresh;
|
pcb->cwnd = pcb->ssthresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the number of retransmissions. */
|
/* Reset the number of retransmissions. */
|
||||||
@ -757,86 +762,91 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
ssthresh). */
|
ssthresh). */
|
||||||
if (pcb->state >= ESTABLISHED) {
|
if (pcb->state >= ESTABLISHED) {
|
||||||
if (pcb->cwnd < pcb->ssthresh) {
|
if (pcb->cwnd < pcb->ssthresh) {
|
||||||
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
|
if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
|
||||||
pcb->cwnd += pcb->mss;
|
pcb->cwnd += pcb->mss;
|
||||||
}
|
}
|
||||||
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %u\n", pcb->cwnd));
|
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %u\n", pcb->cwnd));
|
||||||
} else {
|
} else {
|
||||||
u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
|
u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
|
||||||
if (new_cwnd > pcb->cwnd) {
|
if (new_cwnd > pcb->cwnd) {
|
||||||
pcb->cwnd = new_cwnd;
|
pcb->cwnd = new_cwnd;
|
||||||
}
|
}
|
||||||
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %u\n", pcb->cwnd));
|
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %u\n", pcb->cwnd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %lu, unacked->seqno %lu:%lu\n",
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %lu, unacked->seqno %lu:%lu\n",
|
||||||
ackno,
|
ackno,
|
||||||
pcb->unacked != NULL?
|
pcb->unacked != NULL?
|
||||||
ntohl(pcb->unacked->tcphdr->seqno): 0,
|
ntohl(pcb->unacked->tcphdr->seqno): 0,
|
||||||
pcb->unacked != NULL?
|
pcb->unacked != NULL?
|
||||||
ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
|
ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));
|
||||||
|
|
||||||
/* Remove segment from the unacknowledged list if the incoming
|
/* Remove segment from the unacknowledged list if the incoming
|
||||||
ACK acknowlegdes them. */
|
ACK acknowlegdes them. */
|
||||||
while (pcb->unacked != NULL &&
|
while (pcb->unacked != NULL &&
|
||||||
TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
|
TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +
|
||||||
TCP_TCPLEN(pcb->unacked), ackno)) {
|
TCP_TCPLEN(pcb->unacked), ackno)) {
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unacked\n",
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unacked\n",
|
||||||
ntohl(pcb->unacked->tcphdr->seqno),
|
ntohl(pcb->unacked->tcphdr->seqno),
|
||||||
ntohl(pcb->unacked->tcphdr->seqno) +
|
ntohl(pcb->unacked->tcphdr->seqno) +
|
||||||
TCP_TCPLEN(pcb->unacked)));
|
TCP_TCPLEN(pcb->unacked)));
|
||||||
|
|
||||||
next = pcb->unacked;
|
next = pcb->unacked;
|
||||||
pcb->unacked = pcb->unacked->next;
|
pcb->unacked = pcb->unacked->next;
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));
|
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));
|
||||||
pcb->snd_queuelen -= pbuf_clen(next->p);
|
pcb->snd_queuelen -= pbuf_clen(next->p);
|
||||||
tcp_seg_free(next);
|
tcp_seg_free(next);
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unacked)\n", (unsigned int)pcb->snd_queuelen));
|
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unacked)\n", (unsigned int)pcb->snd_queuelen));
|
||||||
if (pcb->snd_queuelen != 0) {
|
if (pcb->snd_queuelen != 0) {
|
||||||
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
|
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
|
||||||
pcb->unsent != NULL);
|
pcb->unsent != NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pcb->polltmr = 0;
|
pcb->polltmr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We go through the ->unsent list to see if any of the segments
|
/* We go through the ->unsent list to see if any of the segments
|
||||||
on the list are acknowledged by the ACK. This may seem
|
on the list are acknowledged by the ACK. This may seem
|
||||||
strange since an "unsent" segment shouldn't be acked. The
|
strange since an "unsent" segment shouldn't be acked. The
|
||||||
rationale is that lwIP puts all outstanding segments on the
|
rationale is that lwIP puts all outstanding segments on the
|
||||||
->unsent list after a retransmission, so these segments may
|
->unsent list after a retransmission, so these segments may
|
||||||
in fact have been sent once. */
|
in fact have been sent once. */
|
||||||
while (pcb->unsent != NULL &&
|
/* KJM 13th July 2004
|
||||||
TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent),
|
I don't think is is necessary as we no longer move all unacked
|
||||||
ackno) &&
|
segments on the unsent queue when performing retransmit */
|
||||||
TCP_SEQ_LEQ(ackno, pcb->snd_max)) {
|
/*
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unsent\n",
|
while (pcb->unsent != NULL &&
|
||||||
ntohl(pcb->unsent->tcphdr->seqno),
|
TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent),
|
||||||
ntohl(pcb->unsent->tcphdr->seqno) +
|
ackno) &&
|
||||||
TCP_TCPLEN(pcb->unsent)));
|
TCP_SEQ_LEQ(ackno, pcb->snd_max)) {
|
||||||
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %lu:%lu from pcb->unsent\n",
|
||||||
|
ntohl(pcb->unsent->tcphdr->seqno),
|
||||||
|
ntohl(pcb->unsent->tcphdr->seqno) +
|
||||||
|
TCP_TCPLEN(pcb->unsent)));
|
||||||
|
|
||||||
next = pcb->unsent;
|
next = pcb->unsent;
|
||||||
pcb->unsent = pcb->unsent->next;
|
pcb->unsent = pcb->unsent->next;
|
||||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));
|
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %u ... ", (unsigned int)pcb->snd_queuelen));
|
||||||
pcb->snd_queuelen -= pbuf_clen(next->p);
|
pcb->snd_queuelen -= pbuf_clen(next->p);
|
||||||
tcp_seg_free(next);
|
tcp_seg_free(next);
|
||||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unsent)\n", (unsigned int)pcb->snd_queuelen));
|
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%u (after freeing unsent)\n", (unsigned int)pcb->snd_queuelen));
|
||||||
if (pcb->snd_queuelen != 0) {
|
if (pcb->snd_queuelen != 0) {
|
||||||
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
|
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
|
||||||
pcb->unsent != NULL);
|
pcb->unsent != NULL);
|
||||||
}
|
|
||||||
|
|
||||||
if (pcb->unsent != NULL) {
|
|
||||||
pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pcb->unsent != NULL) {
|
||||||
|
pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/* End of ACK for new data processing. */
|
/* End of ACK for new data processing. */
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %u rtseq %lu ackno %lu\n",
|
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %u rtseq %lu ackno %lu\n",
|
||||||
pcb->rttest, pcb->rtseq, ackno));
|
pcb->rttest, pcb->rtseq, ackno));
|
||||||
|
|
||||||
/* RTT estimation calculations. This is done by checking if the
|
/* RTT estimation calculations. This is done by checking if the
|
||||||
incoming segment acknowledges the segment we use to take a
|
incoming segment acknowledges the segment we use to take a
|
||||||
@ -845,20 +855,20 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
m = tcp_ticks - pcb->rttest;
|
m = tcp_ticks - pcb->rttest;
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %u ticks (%u msec).\n",
|
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %u ticks (%u msec).\n",
|
||||||
m, m * TCP_SLOW_INTERVAL));
|
m, m * TCP_SLOW_INTERVAL));
|
||||||
|
|
||||||
/* This is taken directly from VJs original code in his paper */
|
/* This is taken directly from VJs original code in his paper */
|
||||||
m = m - (pcb->sa >> 3);
|
m = m - (pcb->sa >> 3);
|
||||||
pcb->sa += m;
|
pcb->sa += m;
|
||||||
if (m < 0) {
|
if (m < 0) {
|
||||||
m = -m;
|
m = -m;
|
||||||
}
|
}
|
||||||
m = m - (pcb->sv >> 2);
|
m = m - (pcb->sv >> 2);
|
||||||
pcb->sv += m;
|
pcb->sv += m;
|
||||||
pcb->rto = (pcb->sa >> 3) + pcb->sv;
|
pcb->rto = (pcb->sa >> 3) + pcb->sv;
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %u (%u miliseconds)\n",
|
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %u (%u miliseconds)\n",
|
||||||
pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
|
pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));
|
||||||
|
|
||||||
pcb->rttest = 0;
|
pcb->rttest = 0;
|
||||||
}
|
}
|
||||||
@ -869,26 +879,26 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
if (tcplen > 0) {
|
if (tcplen > 0) {
|
||||||
/* This code basically does three things:
|
/* This code basically does three things:
|
||||||
|
|
||||||
+) If the incoming segment contains data that is the next
|
+) If the incoming segment contains data that is the next
|
||||||
in-sequence data, this data is passed to the application. This
|
in-sequence data, this data is passed to the application. This
|
||||||
might involve trimming the first edge of the data. The rcv_nxt
|
might involve trimming the first edge of the data. The rcv_nxt
|
||||||
variable and the advertised window are adjusted.
|
variable and the advertised window are adjusted.
|
||||||
|
|
||||||
+) If the incoming segment has data that is above the next
|
+) If the incoming segment has data that is above the next
|
||||||
sequence number expected (->rcv_nxt), the segment is placed on
|
sequence number expected (->rcv_nxt), the segment is placed on
|
||||||
the ->ooseq queue. This is done by finding the appropriate
|
the ->ooseq queue. This is done by finding the appropriate
|
||||||
place in the ->ooseq queue (which is ordered by sequence
|
place in the ->ooseq queue (which is ordered by sequence
|
||||||
number) and trim the segment in both ends if needed. An
|
number) and trim the segment in both ends if needed. An
|
||||||
immediate ACK is sent to indicate that we received an
|
immediate ACK is sent to indicate that we received an
|
||||||
out-of-sequence segment.
|
out-of-sequence segment.
|
||||||
|
|
||||||
+) Finally, we check if the first segment on the ->ooseq queue
|
+) Finally, we check if the first segment on the ->ooseq queue
|
||||||
now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
|
now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If
|
||||||
rcv_nxt > ooseq->seqno, we must trim the first edge of the
|
rcv_nxt > ooseq->seqno, we must trim the first edge of the
|
||||||
segment on ->ooseq before we adjust rcv_nxt. The data in the
|
segment on ->ooseq before we adjust rcv_nxt. The data in the
|
||||||
segments that are now on sequence are chained onto the
|
segments that are now on sequence are chained onto the
|
||||||
incoming segment so that we only need to call the application
|
incoming segment so that we only need to call the application
|
||||||
once.
|
once.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* First, we check if we must trim the first edge. We have to do
|
/* First, we check if we must trim the first edge. We have to do
|
||||||
@ -897,25 +907,25 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
segment is larger than rcv_nxt. */
|
segment is larger than rcv_nxt. */
|
||||||
if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
|
if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){
|
||||||
if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {
|
if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {
|
||||||
/* Trimming the first edge is done by pushing the payload
|
/* Trimming the first edge is done by pushing the payload
|
||||||
pointer in the pbuf downwards. This is somewhat tricky since
|
pointer in the pbuf downwards. This is somewhat tricky since
|
||||||
we do not want to discard the full contents of the pbuf up to
|
we do not want to discard the full contents of the pbuf up to
|
||||||
the new starting point of the data since we have to keep the
|
the new starting point of the data since we have to keep the
|
||||||
TCP header which is present in the first pbuf in the chain.
|
TCP header which is present in the first pbuf in the chain.
|
||||||
|
|
||||||
What is done is really quite a nasty hack: the first pbuf in
|
What is done is really quite a nasty hack: the first pbuf in
|
||||||
the pbuf chain is pointed to by inseg.p. Since we need to be
|
the pbuf chain is pointed to by inseg.p. Since we need to be
|
||||||
able to deallocate the whole pbuf, we cannot change this
|
able to deallocate the whole pbuf, we cannot change this
|
||||||
inseg.p pointer to point to any of the later pbufs in the
|
inseg.p pointer to point to any of the later pbufs in the
|
||||||
chain. Instead, we point the ->payload pointer in the first
|
chain. Instead, we point the ->payload pointer in the first
|
||||||
pbuf to data in one of the later pbufs. We also set the
|
pbuf to data in one of the later pbufs. We also set the
|
||||||
inseg.data pointer to point to the right place. This way, the
|
inseg.data pointer to point to the right place. This way, the
|
||||||
->p pointer will still point to the first pbuf, but the
|
->p pointer will still point to the first pbuf, but the
|
||||||
->p->payload pointer will point to data in another pbuf.
|
->p->payload pointer will point to data in another pbuf.
|
||||||
|
|
||||||
After we are done with adjusting the pbuf pointers we must
|
After we are done with adjusting the pbuf pointers we must
|
||||||
adjust the ->data pointer in the seg and the segment
|
adjust the ->data pointer in the seg and the segment
|
||||||
length.*/
|
length.*/
|
||||||
|
|
||||||
off = pcb->rcv_nxt - seqno;
|
off = pcb->rcv_nxt - seqno;
|
||||||
p = inseg.p;
|
p = inseg.p;
|
||||||
@ -941,11 +951,11 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
|
inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
/* the whole segment is < rcv_nxt */
|
/* the whole segment is < rcv_nxt */
|
||||||
/* must be a duplicate of a packet that has already been correctly handled */
|
/* must be a duplicate of a packet that has already been correctly handled */
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %lu\n", seqno));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %lu\n", seqno));
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,204 +963,204 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
and below rcv_nxt + rcv_wnd) in order to be further
|
and below rcv_nxt + rcv_wnd) in order to be further
|
||||||
processed. */
|
processed. */
|
||||||
if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
|
if (TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&
|
||||||
TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
|
TCP_SEQ_LT(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
|
||||||
if (pcb->rcv_nxt == seqno) {
|
if (pcb->rcv_nxt == seqno) {
|
||||||
/* The incoming segment is the next in sequence. We check if
|
/* The incoming segment is the next in sequence. We check if
|
||||||
we have to trim the end of the segment and update rcv_nxt
|
we have to trim the end of the segment and update rcv_nxt
|
||||||
and pass the data to the application. */
|
and pass the data to the application. */
|
||||||
#if TCP_QUEUE_OOSEQ
|
#if TCP_QUEUE_OOSEQ
|
||||||
if (pcb->ooseq != NULL &&
|
if (pcb->ooseq != NULL &&
|
||||||
TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
|
TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {
|
||||||
/* We have to trim the second edge of the incoming
|
/* We have to trim the second edge of the incoming
|
||||||
segment. */
|
segment. */
|
||||||
inseg.len = pcb->ooseq->tcphdr->seqno - seqno;
|
inseg.len = pcb->ooseq->tcphdr->seqno - seqno;
|
||||||
pbuf_realloc(inseg.p, inseg.len);
|
pbuf_realloc(inseg.p, inseg.len);
|
||||||
}
|
}
|
||||||
#endif /* TCP_QUEUE_OOSEQ */
|
#endif /* TCP_QUEUE_OOSEQ */
|
||||||
|
|
||||||
tcplen = TCP_TCPLEN(&inseg);
|
tcplen = TCP_TCPLEN(&inseg);
|
||||||
|
|
||||||
pcb->rcv_nxt += tcplen;
|
pcb->rcv_nxt += tcplen;
|
||||||
|
|
||||||
/* Update the receiver's (our) window. */
|
/* Update the receiver's (our) window. */
|
||||||
if (pcb->rcv_wnd < tcplen) {
|
if (pcb->rcv_wnd < tcplen) {
|
||||||
pcb->rcv_wnd = 0;
|
pcb->rcv_wnd = 0;
|
||||||
} else {
|
} else {
|
||||||
pcb->rcv_wnd -= tcplen;
|
pcb->rcv_wnd -= tcplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there is data in the segment, we make preparations to
|
/* If there is data in the segment, we make preparations to
|
||||||
pass this up to the application. The ->recv_data variable
|
pass this up to the application. The ->recv_data variable
|
||||||
is used for holding the pbuf that goes to the
|
is used for holding the pbuf that goes to the
|
||||||
application. The code for reassembling out-of-sequence data
|
application. The code for reassembling out-of-sequence data
|
||||||
chains its data on this pbuf as well.
|
chains its data on this pbuf as well.
|
||||||
|
|
||||||
If the segment was a FIN, we set the TF_GOT_FIN flag that will
|
If the segment was a FIN, we set the TF_GOT_FIN flag that will
|
||||||
be used to indicate to the application that the remote side has
|
be used to indicate to the application that the remote side has
|
||||||
closed its end of the connection. */
|
closed its end of the connection. */
|
||||||
if (inseg.p->tot_len > 0) {
|
if (inseg.p->tot_len > 0) {
|
||||||
recv_data = inseg.p;
|
recv_data = inseg.p;
|
||||||
/* Since this pbuf now is the responsibility of the
|
/* Since this pbuf now is the responsibility of the
|
||||||
application, we delete our reference to it so that we won't
|
application, we delete our reference to it so that we won't
|
||||||
(mistakingly) deallocate it. */
|
(mistakingly) deallocate it. */
|
||||||
inseg.p = NULL;
|
inseg.p = NULL;
|
||||||
}
|
}
|
||||||
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));
|
||||||
recv_flags = TF_GOT_FIN;
|
recv_flags = TF_GOT_FIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TCP_QUEUE_OOSEQ
|
#if TCP_QUEUE_OOSEQ
|
||||||
/* We now check if we have segments on the ->ooseq queue that
|
/* We now check if we have segments on the ->ooseq queue that
|
||||||
is now in sequence. */
|
is now in sequence. */
|
||||||
while (pcb->ooseq != NULL &&
|
while (pcb->ooseq != NULL &&
|
||||||
pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
|
pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {
|
||||||
|
|
||||||
cseg = pcb->ooseq;
|
cseg = pcb->ooseq;
|
||||||
seqno = pcb->ooseq->tcphdr->seqno;
|
seqno = pcb->ooseq->tcphdr->seqno;
|
||||||
|
|
||||||
pcb->rcv_nxt += TCP_TCPLEN(cseg);
|
pcb->rcv_nxt += TCP_TCPLEN(cseg);
|
||||||
if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
|
if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {
|
||||||
pcb->rcv_wnd = 0;
|
pcb->rcv_wnd = 0;
|
||||||
} else {
|
} else {
|
||||||
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
|
pcb->rcv_wnd -= TCP_TCPLEN(cseg);
|
||||||
}
|
}
|
||||||
if (cseg->p->tot_len > 0) {
|
if (cseg->p->tot_len > 0) {
|
||||||
/* Chain this pbuf onto the pbuf that we will pass to
|
/* Chain this pbuf onto the pbuf that we will pass to
|
||||||
the application. */
|
the application. */
|
||||||
if (recv_data) {
|
if (recv_data) {
|
||||||
pbuf_cat(recv_data, cseg->p);
|
pbuf_cat(recv_data, cseg->p);
|
||||||
} else {
|
} else {
|
||||||
recv_data = cseg->p;
|
recv_data = cseg->p;
|
||||||
}
|
}
|
||||||
cseg->p = NULL;
|
cseg->p = NULL;
|
||||||
}
|
}
|
||||||
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
|
if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));
|
||||||
recv_flags = TF_GOT_FIN;
|
recv_flags = TF_GOT_FIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pcb->ooseq = cseg->next;
|
pcb->ooseq = cseg->next;
|
||||||
tcp_seg_free(cseg);
|
tcp_seg_free(cseg);
|
||||||
}
|
}
|
||||||
#endif /* TCP_QUEUE_OOSEQ */
|
#endif /* TCP_QUEUE_OOSEQ */
|
||||||
|
|
||||||
|
|
||||||
/* Acknowledge the segment(s). */
|
/* Acknowledge the segment(s). */
|
||||||
tcp_ack(pcb);
|
tcp_ack(pcb);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
/* We get here if the incoming segment is out-of-sequence. */
|
/* We get here if the incoming segment is out-of-sequence. */
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
#if TCP_QUEUE_OOSEQ
|
#if TCP_QUEUE_OOSEQ
|
||||||
/* We queue the segment on the ->ooseq queue. */
|
/* We queue the segment on the ->ooseq queue. */
|
||||||
if (pcb->ooseq == NULL) {
|
if (pcb->ooseq == NULL) {
|
||||||
pcb->ooseq = tcp_seg_copy(&inseg);
|
pcb->ooseq = tcp_seg_copy(&inseg);
|
||||||
} else {
|
} else {
|
||||||
/* If the queue is not empty, we walk through the queue and
|
/* If the queue is not empty, we walk through the queue and
|
||||||
try to find a place where the sequence number of the
|
try to find a place where the sequence number of the
|
||||||
incoming segment is between the sequence numbers of the
|
incoming segment is between the sequence numbers of the
|
||||||
previous and the next segment on the ->ooseq queue. That is
|
previous and the next segment on the ->ooseq queue. That is
|
||||||
the place where we put the incoming segment. If needed, we
|
the place where we put the incoming segment. If needed, we
|
||||||
trim the second edges of the previous and the incoming
|
trim the second edges of the previous and the incoming
|
||||||
segment so that it will fit into the sequence.
|
segment so that it will fit into the sequence.
|
||||||
|
|
||||||
If the incoming segment has the same sequence number as a
|
If the incoming segment has the same sequence number as a
|
||||||
segment on the ->ooseq queue, we discard the segment that
|
segment on the ->ooseq queue, we discard the segment that
|
||||||
contains less data. */
|
contains less data. */
|
||||||
|
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
for(next = pcb->ooseq; next != NULL; next = next->next) {
|
for(next = pcb->ooseq; next != NULL; next = next->next) {
|
||||||
if (seqno == next->tcphdr->seqno) {
|
if (seqno == next->tcphdr->seqno) {
|
||||||
/* The sequence number of the incoming segment is the
|
/* The sequence number of the incoming segment is the
|
||||||
same as the sequence number of the segment on
|
same as the sequence number of the segment on
|
||||||
->ooseq. We check the lengths to see which one to
|
->ooseq. We check the lengths to see which one to
|
||||||
discard. */
|
discard. */
|
||||||
if (inseg.len > next->len) {
|
if (inseg.len > next->len) {
|
||||||
/* The incoming segment is larger than the old
|
/* The incoming segment is larger than the old
|
||||||
segment. We replace the old segment with the new
|
segment. We replace the old segment with the new
|
||||||
one. */
|
one. */
|
||||||
cseg = tcp_seg_copy(&inseg);
|
cseg = tcp_seg_copy(&inseg);
|
||||||
if (cseg != NULL) {
|
if (cseg != NULL) {
|
||||||
cseg->next = next->next;
|
cseg->next = next->next;
|
||||||
if (prev != NULL) {
|
if (prev != NULL) {
|
||||||
prev->next = cseg;
|
prev->next = cseg;
|
||||||
} else {
|
} else {
|
||||||
pcb->ooseq = cseg;
|
pcb->ooseq = cseg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
/* Either the lenghts are the same or the incoming
|
/* Either the lenghts are the same or the incoming
|
||||||
segment was smaller than the old one; in either
|
segment was smaller than the old one; in either
|
||||||
case, we ditch the incoming segment. */
|
case, we ditch the incoming segment. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (prev == NULL) {
|
if (prev == NULL) {
|
||||||
if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
|
if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
|
||||||
/* The sequence number of the incoming segment is lower
|
/* The sequence number of the incoming segment is lower
|
||||||
than the sequence number of the first segment on the
|
than the sequence number of the first segment on the
|
||||||
queue. We put the incoming segment first on the
|
queue. We put the incoming segment first on the
|
||||||
queue. */
|
queue. */
|
||||||
|
|
||||||
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
||||||
/* We need to trim the incoming segment. */
|
/* We need to trim the incoming segment. */
|
||||||
inseg.len = next->tcphdr->seqno - seqno;
|
inseg.len = next->tcphdr->seqno - seqno;
|
||||||
pbuf_realloc(inseg.p, inseg.len);
|
pbuf_realloc(inseg.p, inseg.len);
|
||||||
}
|
}
|
||||||
cseg = tcp_seg_copy(&inseg);
|
cseg = tcp_seg_copy(&inseg);
|
||||||
if (cseg != NULL) {
|
if (cseg != NULL) {
|
||||||
cseg->next = next;
|
cseg->next = next;
|
||||||
pcb->ooseq = cseg;
|
pcb->ooseq = cseg;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
|
} else if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&
|
||||||
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
|
TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {
|
||||||
/* The sequence number of the incoming segment is in
|
/* The sequence number of the incoming segment is in
|
||||||
between the sequence numbers of the previous and
|
between the sequence numbers of the previous and
|
||||||
the next segment on ->ooseq. We trim and insert the
|
the next segment on ->ooseq. We trim and insert the
|
||||||
incoming segment and trim the previous segment, if
|
incoming segment and trim the previous segment, if
|
||||||
needed. */
|
needed. */
|
||||||
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {
|
||||||
/* We need to trim the incoming segment. */
|
/* We need to trim the incoming segment. */
|
||||||
inseg.len = next->tcphdr->seqno - seqno;
|
inseg.len = next->tcphdr->seqno - seqno;
|
||||||
pbuf_realloc(inseg.p, inseg.len);
|
pbuf_realloc(inseg.p, inseg.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
cseg = tcp_seg_copy(&inseg);
|
cseg = tcp_seg_copy(&inseg);
|
||||||
if (cseg != NULL) {
|
if (cseg != NULL) {
|
||||||
cseg->next = next;
|
cseg->next = next;
|
||||||
prev->next = cseg;
|
prev->next = cseg;
|
||||||
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
|
if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {
|
||||||
/* We need to trim the prev segment. */
|
/* We need to trim the prev segment. */
|
||||||
prev->len = seqno - prev->tcphdr->seqno;
|
prev->len = seqno - prev->tcphdr->seqno;
|
||||||
pbuf_realloc(prev->p, prev->len);
|
pbuf_realloc(prev->p, prev->len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* If the "next" segment is the last segment on the
|
/* If the "next" segment is the last segment on the
|
||||||
ooseq queue, we add the incoming segment to the end
|
ooseq queue, we add the incoming segment to the end
|
||||||
of the list. */
|
of the list. */
|
||||||
if (next->next == NULL &&
|
if (next->next == NULL &&
|
||||||
TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
|
TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {
|
||||||
next->next = tcp_seg_copy(&inseg);
|
next->next = tcp_seg_copy(&inseg);
|
||||||
if (next->next != NULL) {
|
if (next->next != NULL) {
|
||||||
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
|
if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {
|
||||||
/* We need to trim the last segment. */
|
/* We need to trim the last segment. */
|
||||||
next->len = seqno - next->tcphdr->seqno;
|
next->len = seqno - next->tcphdr->seqno;
|
||||||
pbuf_realloc(next->p, next->len);
|
pbuf_realloc(next->p, next->len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
prev = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* TCP_QUEUE_OOSEQ */
|
#endif /* TCP_QUEUE_OOSEQ */
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1159,7 +1169,7 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
/* Segments with length 0 is taken care of here. Segments that
|
/* Segments with length 0 is taken care of here. Segments that
|
||||||
fall out of the window are ACKed. */
|
fall out of the window are ACKed. */
|
||||||
if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
|
if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||
|
||||||
TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
|
TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {
|
||||||
tcp_ack_now(pcb);
|
tcp_ack_now(pcb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user