From 3af10e5ff1c784f940465657b9057feb6c8bb9fc Mon Sep 17 00:00:00 2001
From: Our Air Quality <info@ourairquality.org>
Date: Sun, 3 Sep 2017 19:02:43 +1000
Subject: [PATCH] Replace the OOSEQ max bytes and pbufs constants with
 functions.

Some systems need to take into account an RX buffer pool size when
advising an appropriate number of RX pbufs to queue on the ooseq
list. For some systems there is a practical hard limit beyond which
the rx pool becomes exhausted blocking reception of further buffers
until some are freed.

It also helps to be able to consider the available dynamic memory when
advising an appropriate maximum number of bytes to buffer on the ooseq
list.

These decisions can also benefit from knowing the number already
allocated on a particular pcb, so this is passed to these
functions. For example, if the system only wants to allow the total
number of rx pbufs queued on all the ooseq lists to grow by one and a
call is make indicating a pcb already has two then it can return three
for this call, but might return one for another call - supporting a
greedy allocation strategy.
---
 src/core/tcp_in.c      | 33 +++++++++++++++++++++------------
 src/include/lwip/opt.h | 18 ++++++++++--------
 2 files changed, 31 insertions(+), 20 deletions(-)

diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c
index c15a409..23f50be 100644
--- a/src/core/tcp_in.c
+++ b/src/core/tcp_in.c
@@ -94,7 +94,7 @@ 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
+#if defined(TCP_OOSEQ_MAX_BYTES) || defined(TCP_OOSEQ_MAX_PBUFS)
 static void tcp_remove_sacks_gt(struct tcp_pcb *pcb, u32_t seq);
 #endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
 #endif /* LWIP_TCP_SACK_OUT */
@@ -1077,19 +1077,17 @@ tcp_free_acked_segments(struct tcp_pcb *pcb, struct tcp_seg *seg_list, const cha
 static void
 tcp_receive(struct tcp_pcb *pcb)
 {
-#if TCP_QUEUE_OOSEQ || TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
-  struct tcp_seg *next;
-#endif
 #if TCP_QUEUE_OOSEQ
+  struct tcp_seg *next;
   struct tcp_seg *prev, *cseg;
+#if defined(TCP_OOSEQ_MAX_BYTES) || defined(TCP_OOSEQ_MAX_PBUFS)
+  u32_t ooseq_blen, ooseq_max_blen;
+  u16_t ooseq_qlen, ooseq_max_qlen;
+#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
 #endif /* TCP_QUEUE_OOSEQ */
   s16_t m;
   u32_t right_wnd_edge;
   int found_dupack = 0;
-#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
-  u32_t ooseq_blen;
-  u16_t ooseq_qlen;
-#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */
 
   LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED);
 
@@ -1763,18 +1761,29 @@ tcp_receive(struct tcp_pcb *pcb)
           }
 #endif /* LWIP_TCP_SACK_OUT */
         }
-#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
+#if defined(TCP_OOSEQ_MAX_BYTES) || defined(TCP_OOSEQ_MAX_PBUFS)
         /* Check that the data on ooseq doesn't exceed one of the limits
            and throw away everything above that limit. */
+
         ooseq_blen = 0;
         ooseq_qlen = 0;
+        for (next = pcb->ooseq; next != NULL; next = next->next) {
+          struct pbuf *p = next->p;
+          ooseq_blen += p->tot_len;
+          ooseq_qlen += pbuf_clen(p);
+        }
+        ooseq_max_blen = TCP_OOSEQ_MAX_BYTES(ooseq_blen);
+        ooseq_max_qlen = TCP_OOSEQ_MAX_PBUFS(ooseq_qlen);
+
         prev = NULL;
+        ooseq_blen = 0;
+        ooseq_qlen = 0;
         for (next = pcb->ooseq; next != NULL; prev = next, next = next->next) {
           struct pbuf *p = next->p;
           ooseq_blen += p->tot_len;
           ooseq_qlen += pbuf_clen(p);
-          if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) ||
-              (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) {
+          if ((ooseq_blen > ooseq_max_blen) ||
+              (ooseq_qlen > ooseq_max_qlen)) {
 #if LWIP_TCP_SACK_OUT
              if (pcb->flags & TF_SACK) {
                /* Let's remove all SACKs from next's seqno up. */
@@ -2059,7 +2068,7 @@ tcp_remove_sacks_lt(struct tcp_pcb *pcb, u32_t seq)
   }
 }
 
-#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS
+#if defined(TCP_OOSEQ_MAX_BYTES) || defined(TCP_OOSEQ_MAX_PBUFS)
 /**
  * Called to remove a range of SACKs.
  *
diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h
index 6813faa..bfe554b 100644
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -1291,19 +1291,21 @@
 #endif
 
 /**
- * TCP_OOSEQ_MAX_BYTES: The maximum number of bytes queued on ooseq per pcb.
- * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1.
+ * TCP_OOSEQ_MAX_BYTES(n):
+ * Return the maximum number of bytes to be queued on ooseq per pcb, given the
+ * current number queued on a pcb.  Only valid for TCP_QUEUE_OOSEQ==1.
  */
-#if !defined TCP_OOSEQ_MAX_BYTES || defined __DOXYGEN__
-#define TCP_OOSEQ_MAX_BYTES             0
+#ifdef __DOXYGEN__
+#define TCP_OOSEQ_MAX_BYTES(n)
 #endif
 
 /**
- * TCP_OOSEQ_MAX_PBUFS: The maximum number of pbufs queued on ooseq per pcb.
- * Default is 0 (no limit). Only valid for TCP_QUEUE_OOSEQ==1.
+ * TCP_OOSEQ_MAX_PBUFS(n):
+ * Return the maximum number of pbufs to be queued on ooseq per pcb, given the
+ * current number queued on a pcb.  Only valid for TCP_QUEUE_OOSEQ==1.
  */
-#if !defined TCP_OOSEQ_MAX_PBUFS || defined __DOXYGEN__
-#define TCP_OOSEQ_MAX_PBUFS             0
+#ifdef __DOXYGEN__
+#define TCP_OOSEQ_MAX_PBUFS(n)
 #endif
 
 /**
-- 
2.7.5

