mirror of
https://git.savannah.nongnu.org/git/lwip.git
synced 2026-08-10 01:23:48 +08:00
Another fix to window scaling: support queueing more than 64 KByte in ooseq data
This commit is contained in:
@@ -952,6 +952,56 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
|
||||
return copied_total;
|
||||
}
|
||||
|
||||
#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
/**
|
||||
* This method modifies a 'pbuf chain', so that its total length is
|
||||
* smaller than 64K. The remainder of the original pbuf chain is stored
|
||||
* in *rest.
|
||||
* This function never creates new pbufs, but splits an existing chain
|
||||
* in two parts. The tot_len of the modified packet queue will likely be
|
||||
* smaller than 64K.
|
||||
* 'packet queues' are not supported by this function.
|
||||
*
|
||||
* @param p the pbuf queue to be splitted
|
||||
* @param rest pointer to store the remainder (after the first 64K)
|
||||
*/
|
||||
void pbuf_split_64k(struct pbuf *p, struct pbuf **rest)
|
||||
{
|
||||
*rest = NULL;
|
||||
if ((p != NULL) && (p->next != NULL)) {
|
||||
u16_t tot_len_front = p->len;
|
||||
struct pbuf *i = p;
|
||||
struct pbuf *r = p->next;
|
||||
|
||||
/* continue until the total length (summed up as u16_t) overflows */
|
||||
while ((r != NULL) && ((u16_t)(tot_len_front + r->len) > tot_len_front)) {
|
||||
tot_len_front += r->len;
|
||||
i = r;
|
||||
r = r->next;
|
||||
}
|
||||
/* i now points to last packet of the first segment. Set next
|
||||
pointer to NULL */
|
||||
i->next = NULL;
|
||||
|
||||
if (r != NULL) {
|
||||
/* Update the tot_len field in the first part */
|
||||
for (i = p; i != NULL; i = i->next) {
|
||||
i->tot_len -= r->tot_len;
|
||||
LWIP_ASSERT("tot_len/len mismatch in last pbuf",
|
||||
(i->next != NULL) || (i->tot_len == i->len));
|
||||
}
|
||||
if (p->flags & PBUF_FLAG_TCP_FIN) {
|
||||
r->flags |= PBUF_FLAG_TCP_FIN;
|
||||
}
|
||||
|
||||
/* tot_len field in rest does not need modifications */
|
||||
/* reference counters do not need modifications */
|
||||
*rest = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
|
||||
/**
|
||||
* Copy application supplied data into a pbuf.
|
||||
* This function can only be used to copy the equivalent of buf->tot_len data.
|
||||
|
||||
@@ -1124,37 +1124,58 @@ tcp_fasttmr_start:
|
||||
err_t
|
||||
tcp_process_refused_data(struct tcp_pcb *pcb)
|
||||
{
|
||||
err_t err;
|
||||
u8_t refused_flags = pcb->refused_data->flags;
|
||||
/* set pcb->refused_data to NULL in case the callback frees it and then
|
||||
closes the pcb */
|
||||
struct pbuf *refused_data = pcb->refused_data;
|
||||
pcb->refused_data = NULL;
|
||||
/* Notify again application with data previously received. */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
|
||||
TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err);
|
||||
if (err == ERR_OK) {
|
||||
/* did refused_data include a FIN? */
|
||||
if (refused_flags & PBUF_FLAG_TCP_FIN) {
|
||||
/* correct rcv_wnd as the application won't call tcp_recved()
|
||||
for the FIN's seqno */
|
||||
if (pcb->rcv_wnd != TCP_WND) {
|
||||
pcb->rcv_wnd++;
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
struct pbuf *rest;
|
||||
while (pcb->refused_data != NULL)
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
{
|
||||
err_t err;
|
||||
u8_t refused_flags = pcb->refused_data->flags;
|
||||
/* set pcb->refused_data to NULL in case the callback frees it and then
|
||||
closes the pcb */
|
||||
struct pbuf *refused_data = pcb->refused_data;
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
pbuf_split_64k(refused_data, &rest);
|
||||
pcb->refused_data = rest;
|
||||
#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
pcb->refused_data = NULL;
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
/* Notify again application with data previously received. */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));
|
||||
TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err);
|
||||
if (err == ERR_OK) {
|
||||
/* did refused_data include a FIN? */
|
||||
if (refused_flags & PBUF_FLAG_TCP_FIN
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
&& (rest == NULL)
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
) {
|
||||
/* correct rcv_wnd as the application won't call tcp_recved()
|
||||
for the FIN's seqno */
|
||||
if (pcb->rcv_wnd != TCP_WND) {
|
||||
pcb->rcv_wnd++;
|
||||
}
|
||||
TCP_EVENT_CLOSED(pcb, err);
|
||||
if (err == ERR_ABRT) {
|
||||
return ERR_ABRT;
|
||||
}
|
||||
}
|
||||
TCP_EVENT_CLOSED(pcb, err);
|
||||
if (err == ERR_ABRT) {
|
||||
return ERR_ABRT;
|
||||
} else if (err == ERR_ABRT) {
|
||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||
/* Drop incoming packets because pcb is "full" (only if the incoming
|
||||
segment contains data). */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
|
||||
return ERR_ABRT;
|
||||
} else {
|
||||
/* data is still refused, pbuf is still valid (go on for ACK-only packets) */
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
if (rest != NULL) {
|
||||
pbuf_cat(refused_data, rest);
|
||||
}
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
pcb->refused_data = refused_data;
|
||||
return ERR_INPROGRESS;
|
||||
}
|
||||
} else if (err == ERR_ABRT) {
|
||||
/* if err == ERR_ABRT, 'pcb' is already deallocated */
|
||||
/* Drop incoming packets because pcb is "full" (only if the incoming
|
||||
segment contains data). */
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));
|
||||
return ERR_ABRT;
|
||||
} else {
|
||||
/* data is still refused, pbuf is still valid (go on for ACK-only packets) */
|
||||
pcb->refused_data = refused_data;
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -364,12 +364,24 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
}
|
||||
}
|
||||
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
while (recv_data != NULL) {
|
||||
struct pbuf *rest = NULL;
|
||||
pbuf_split_64k(recv_data, &rest);
|
||||
#else /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
if (recv_data != NULL) {
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
|
||||
LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL);
|
||||
if (pcb->flags & TF_RXCLOSED) {
|
||||
/* received data although already closed -> abort (send RST) to
|
||||
notify the remote host that not all data has been processed */
|
||||
pbuf_free(recv_data);
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
if (rest != NULL) {
|
||||
pbuf_free(rest);
|
||||
}
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
tcp_abort(pcb);
|
||||
goto aborted;
|
||||
}
|
||||
@@ -377,13 +389,29 @@ tcp_input(struct pbuf *p, struct netif *inp)
|
||||
/* Notify application that data has been received. */
|
||||
TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
|
||||
if (err == ERR_ABRT) {
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
if (rest != NULL) {
|
||||
pbuf_free(rest);
|
||||
}
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
goto aborted;
|
||||
}
|
||||
|
||||
/* If the upper layer can't receive this data, store it */
|
||||
if (err != ERR_OK) {
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
if (rest != NULL) {
|
||||
pbuf_cat(recv_data, rest);
|
||||
}
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
pcb->refused_data = recv_data;
|
||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));
|
||||
#if TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
break;
|
||||
} else {
|
||||
/* Upper layer received the data, go on with the rest if > 64K */
|
||||
recv_data = rest;
|
||||
#endif /* TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1382,6 +1410,9 @@ tcp_receive(struct tcp_pcb *pcb)
|
||||
if (cseg->p->tot_len > 0) {
|
||||
/* Chain this pbuf onto the pbuf that we will pass to
|
||||
the application. */
|
||||
/* With window scaling, this can overflow recv_data->tot_len, but
|
||||
that's not a problem since we explicitly fix that before passing
|
||||
recv_data to the application. */
|
||||
if (recv_data) {
|
||||
pbuf_cat(recv_data, cseg->p);
|
||||
} else {
|
||||
|
||||
@@ -172,6 +172,9 @@ struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
|
||||
err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
|
||||
u16_t len, u16_t *chksum);
|
||||
#endif /* LWIP_CHECKSUM_ON_COPY */
|
||||
#if LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE
|
||||
void pbuf_split_64k(struct pbuf *p, struct pbuf **rest);
|
||||
#endif /* LWIP_TCP && TCP_QUEUE_OOSEQ && LWIP_WND_SCALE */
|
||||
|
||||
u8_t pbuf_get_at(struct pbuf* p, u16_t offset);
|
||||
u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n);
|
||||
|
||||
Reference in New Issue
Block a user