diff --git a/src/core/tcp.c b/src/core/tcp.c index a3b02a3a..7ba5c396 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -1181,7 +1181,7 @@ tcp_slowtmr_start: LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); #if LWIP_TCP_SACK_OUT memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); -#endif +#endif /* LWIP_TCP_SACK_OUT */ } #endif /* TCP_QUEUE_OOSEQ */ @@ -1893,7 +1893,7 @@ tcp_pcb_purge(struct tcp_pcb *pcb) pcb->ooseq = NULL; #if LWIP_TCP_SACK_OUT memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); -#endif +#endif /* LWIP_TCP_SACK_OUT */ #endif /* TCP_QUEUE_OOSEQ */ /* Stop the retransmission timer as it will expect data on unacked diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 11eb11a1..2e688a25 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -59,6 +59,8 @@ #include "lwip/nd6.h" #endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */ +#include + /** Initial CWND calculation as defined RFC 2581 */ #define LWIP_TCP_CALC_INITIAL_CWND(mss) LWIP_MIN((4U * (mss)), LWIP_MAX((2U * (mss)), 4380U)); @@ -92,8 +94,10 @@ static void tcp_timewait_input(struct tcp_pcb *pcb); #if LWIP_TCP_SACK_OUT static void tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right); static void tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq); +#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS static void tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq); -#endif +#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ +#endif /* LWIP_TCP_SACK_OUT */ /** * The initial input processing of TCP. It verifies the TCP header, demultiplexes @@ -1503,7 +1507,7 @@ tcp_receive(struct tcp_pcb *pcb) memset(pcb->rcv_sacks, 0, sizeof(pcb->rcv_sacks)); } } -#endif +#endif /* LWIP_TCP_SACK_OUT */ } #endif /* TCP_QUEUE_OOSEQ */ @@ -1583,14 +1587,14 @@ tcp_receive(struct tcp_pcb *pcb) tcp_ack(pcb); #if LWIP_TCP_SACK_OUT - if (pcb->rcv_sacks[0].left != pcb->rcv_sacks[0].right) { + if (!LWIP_TCP_SACK_VALID(pcb, 0)) { /* Normally the ACK for the data received could be piggy-backed on a data packet, but lwIP currently does not support including SACKs in data packets. So we force it to respond with an empty ACK packet (only if there is at least one SACK to be sent). NOTE: tcp_send_empty_ack() on success clears the ACK flags (set by tcp_ack()) */ tcp_send_empty_ack(pcb); } -#endif +#endif /* LWIP_TCP_SACK_OUT */ #if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS if (ip_current_is_v6()) { @@ -1612,7 +1616,7 @@ tcp_receive(struct tcp_pcb *pcb) pcb->rcv_sacks[0].left = seqno; pcb->rcv_sacks[0].right = seqno + inseg.len; } -#endif +#endif /* LWIP_TCP_SACK_OUT */ } else { /* If the queue is not empty, we walk through the queue and try to find a place where the sequence number of the @@ -1628,9 +1632,9 @@ tcp_receive(struct tcp_pcb *pcb) #if LWIP_TCP_SACK_OUT /* This is the left edge of the lowest possible SACK range. - It may start before the newly received segment. */ + It may start before the newly received segment (possibly adjusted below). */ u32_t sackbeg = TCP_SEQ_LT(seqno, pcb->ooseq->tcphdr->seqno) ? seqno : pcb->ooseq->tcphdr->seqno; -#endif +#endif /* LWIP_TCP_SACK_OUT */ prev = NULL; for (next = pcb->ooseq; next != NULL; next = next->next) { if (seqno == next->tcphdr->seqno) { @@ -1701,7 +1705,7 @@ tcp_receive(struct tcp_pcb *pcb) if (prev != NULL && prev->tcphdr->seqno + prev->len != next->tcphdr->seqno) { sackbeg = next->tcphdr->seqno; } -#endif +#endif /* LWIP_TCP_SACK_OUT */ /* We don't use 'prev' below, so let's set it to current 'next'. This way even if we break the loop below, 'prev' will be pointing @@ -1789,9 +1793,10 @@ tcp_receive(struct tcp_pcb *pcb) #if LWIP_TCP_SACK_OUT if (pcb->flags & TF_SACK) { /* Let's remove all SACKs from next's seqno up. */ + /* @todo: is this really allowed??? */ tcp_remove_sacks_gt(pcb, next->tcphdr->seqno); } -#endif +#endif /* LWIP_TCP_SACK_OUT */ /* too much ooseq data, dump this and everything after it */ tcp_segs_free(next); if (prev == NULL) { @@ -1904,7 +1909,7 @@ tcp_parseopt(struct tcp_pcb *pcb) pcb->rcv_wnd = pcb->rcv_ann_wnd = TCP_WND; } break; -#endif +#endif /* LWIP_WND_SCALE */ #if LWIP_TCP_TIMESTAMPS case LWIP_TCP_OPT_TS: LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); @@ -1929,7 +1934,7 @@ tcp_parseopt(struct tcp_pcb *pcb) /* Advance to next option (6 bytes already read) */ tcp_optidx += LWIP_TCP_OPT_LEN_TS - 6; break; -#endif +#endif /* LWIP_TCP_TIMESTAMPS */ #if LWIP_TCP_SACK_OUT case LWIP_TCP_OPT_SACK_PERM: LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: SACK_PERM\n")); @@ -1944,7 +1949,7 @@ tcp_parseopt(struct tcp_pcb *pcb) pcb->flags |= TF_SACK; } break; -#endif +#endif /* LWIP_TCP_SACK_OUT */ default: LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); data = tcp_getoptbyte(); @@ -1994,7 +1999,7 @@ tcp_add_sack(struct tcp_pcb *pcb, u32_t left, u32_t right) while moving all other SACKs forward. We run this loop for all entries, until we find the first invalid one. There is no point checking after that. */ - for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && (pcb->rcv_sacks[i].left != pcb->rcv_sacks[i].right); ++i) { + for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { /* We only want to use SACK at [i] if it doesn't overlap with left:right range. It does not overlap if its right side is before the newly added SACK, or if its left side is after the newly added SACK. @@ -2048,7 +2053,7 @@ tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq) /* We run this loop for all entries, until we find the first invalid one. There is no point checking after that. */ - for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && (pcb->rcv_sacks[i].left != pcb->rcv_sacks[i].right); ++i) { + for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { /* We only want to use SACK at index [i] if its right side is > 'seq'. */ if (TCP_SEQ_GT(pcb->rcv_sacks[i].right, seq)) { if (unused_idx != i) { @@ -2069,6 +2074,7 @@ tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq) } } +#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS /** * Called to remove a range of SACKs. * @@ -2087,7 +2093,7 @@ tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq) /* We run this loop for all entries, until we find the first invalid one. There is no point checking after that. */ - for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && (pcb->rcv_sacks[i].left != pcb->rcv_sacks[i].right); ++i) { + for (i = unused_idx = 0; (i < LWIP_TCP_MAX_SACK_NUM) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { /* We only want to use SACK at index [i] if its left side is < 'seq'. */ if (TCP_SEQ_LT(pcb->rcv_sacks[i].left, seq)) { if (unused_idx != i) { @@ -2107,6 +2113,7 @@ tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq) pcb->rcv_sacks[i].left = pcb->rcv_sacks[i].right = 0; } } +#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ #endif /* LWIP_TCP_SACK_OUT */ diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 051cc108..452315d6 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -947,7 +947,7 @@ tcp_get_num_sacks(struct tcp_pcb *pcb, u8_t optlen) optlen += 12; /* Max options size = 40, number of SACK array entries = LWIP_TCP_MAX_SACK_NUM */ - for (i = 0; (i < LWIP_TCP_MAX_SACK_NUM) && (optlen <= 40) && (pcb->rcv_sacks[i].left != pcb->rcv_sacks[i].right); ++i) { + for (i = 0; (i < LWIP_TCP_MAX_SACK_NUM) && (optlen <= 40) && LWIP_TCP_SACK_VALID(pcb, i); ++i) { ++num_sacks; optlen += 8; } diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index 8faea95d..2ae6d67c 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -1215,13 +1215,13 @@ * LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs). */ #if !defined LWIP_TCP_SACK_OUT || defined __DOXYGEN__ -#define LWIP_TCP_SACK_OUT 0 +#define LWIP_TCP_SACK_OUT 0 #endif /** - * LWIP_TCP_MAX_SACK_NUM: The maximum number of SACK values to include in TCP packets. + * LWIP_TCP_MAX_SACK_NUM: The maximum number of SACK values to include in TCP segments. * Must be at least 1, but is only used if LWIP_TCP_SACK_OUT is enabled. - * NOTE: Even though we never send more than 4 SACK ranges in a single packet + * NOTE: Even though we never send more than 3 or 4 SACK ranges in a single segment * (depending on other options), setting this option to values greater than 4 is not pointless. * This is basically the max number of SACK ranges we want to keep track of. * As new data is delivered, some of the SACK ranges may be removed or merged. @@ -1229,7 +1229,7 @@ * The amount of memory used to store SACK ranges is LWIP_TCP_MAX_SACK_NUM * 8 bytes for each TCP PCB. */ #if !defined LWIP_TCP_MAX_SACK_NUM || defined __DOXYGEN__ -#define LWIP_TCP_MAX_SACK_NUM 4 +#define LWIP_TCP_MAX_SACK_NUM 4 #endif /** diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index ccc1ab7d..89f9dd79 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -152,6 +152,17 @@ typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); } \ } while(0) +#if LWIP_TCP_SACK_OUT +/** SACK ranges to include in ACK packets. + * SACK entry is invalid if left==right. */ +struct tcp_sack_range { + /** Left edge of the SACK: the first acknowledged sequence number. */ + u32_t left; + /** Right edge of the SACK: the last acknowledged sequence number +1 (so first NOT acknowledged). */ + u32_t right; +}; +#endif /* LWIP_TCP_SACK_OUT */ + typedef u16_t tcpflags_t; /** @@ -232,18 +243,11 @@ struct tcp_pcb { tcpwnd_size_t rcv_ann_wnd; /* receiver window to announce */ u32_t rcv_ann_right_edge; /* announced right edge of window */ -#ifdef LWIP_TCP_SACK_OUT - /* SACK ranges to include in ACK packets. - SACK entry is invalid if left=right. */ - struct - { - /* Left edge of the SACK: the first acknowledged sequence number. */ - u32_t left; - - /* Right edge of the SACK: the last acknowledged sequence number +1 (so first NOT acknowledged). */ - u32_t right; - } rcv_sacks[LWIP_TCP_MAX_SACK_NUM]; -#endif +#if LWIP_TCP_SACK_OUT + /* SACK ranges to include in ACK packets (entry is invalid if left==right) */ + struct tcp_sack_range rcv_sacks[LWIP_TCP_MAX_SACK_NUM]; +#define LWIP_TCP_SACK_VALID(pcb, idx) ((pcb)->rcv_sacks[idx].left == (pcb)->rcv_sacks[idx].right) +#endif /* LWIP_TCP_SACK_OUT */ /* Retransmission timer. */ s16_t rtime;