From 46796a2d95bfaa280da7940cf7d02eaa0c90ede7 Mon Sep 17 00:00:00 2001
From: Joel Cunningham <joel.cunningham@me.com>
Date: Mon, 6 Mar 2017 23:28:18 -0600
Subject: [PATCH] Add ABC support

---
 src/core/tcp.c         |  3 +++
 src/core/tcp_in.c      | 37 ++++++++++++++++++++++++++++++++++---
 src/include/lwip/opt.h | 16 ++++++++++++++++
 src/include/lwip/tcp.h |  3 +++
 4 files changed, 56 insertions(+), 3 deletions(-)

diff --git a/src/core/tcp.c b/src/core/tcp.c
index f073a61..935d6c6 100644
--- a/src/core/tcp.c
+++ b/src/core/tcp.c
@@ -1097,6 +1097,9 @@ tcp_slowtmr_start:
             pcb->ssthresh = (pcb->mss << 1);
           }
           pcb->cwnd = pcb->mss;
+#if TCP_ABC
+          pcb->bytes_acked = 0;
+#endif /* TCP_ABC */
           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"TCPWNDSIZE_F
                                        " ssthresh %"TCPWNDSIZE_F"\n",
                                        pcb->cwnd, pcb->ssthresh));
diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c
index 324fa48..cd63208 100644
--- a/src/core/tcp_in.c
+++ b/src/core/tcp_in.c
@@ -1111,6 +1111,9 @@ tcp_receive(struct tcp_pcb *pcb)
       }
     } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
       /* We come here when the ACK acknowledges new data. */
+#if TCP_ABC
+      tcpwnd_size_t acked;
+#endif /* TCP_ABC */
 
       /* Reset the "IN Fast Retransmit" flag, since we are no longer
          in fast retransmit. Also reset the congestion window to the
@@ -1118,6 +1121,9 @@ tcp_receive(struct tcp_pcb *pcb)
       if (pcb->flags & TF_INFR) {
         pcb->flags &= ~TF_INFR;
         pcb->cwnd = pcb->ssthresh;
+#if TCP_ABC
+        pcb->bytes_acked = 0;
+#endif /* TCP_ABC */
       }
 
       /* Reset the number of retransmissions. */
@@ -1126,6 +1132,11 @@ tcp_receive(struct tcp_pcb *pcb)
       /* Reset the retransmission time-out. */
       pcb->rto = (pcb->sa >> 3) + pcb->sv;
 
+#if TCP_ABC
+      /* Record how much data this ACK acks */
+      acked = (tcpwnd_size_t)(ackno - pcb->lastack);
+#endif /* TCP_ABC */
+
       /* Reset the fast retransmit variables. */
       pcb->dupacks = 0;
       pcb->lastack = ackno;
@@ -1134,12 +1145,32 @@ tcp_receive(struct tcp_pcb *pcb)
          ssthresh). */
       if (pcb->state >= ESTABLISHED) {
         if (pcb->cwnd < pcb->ssthresh) {
-          if ((tcpwnd_size_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
-            pcb->cwnd += pcb->mss;
+          tcpwnd_size_t increase;
+#if TCP_ABC
+          /* RFC 3465, section 2.2 Slow Start */
+          increase = LWIP_MIN(acked, TCP_ABC_LIMIT * (tcpwnd_size_t)pcb->mss);
+#else /* TCP_ABC */
+          increase = pcb->mss;
+#endif /* TCP_ABC */
+          if (pcb->cwnd + increase > pcb->cwnd) {
+            pcb->cwnd += increase;
           }
           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"TCPWNDSIZE_F"\n", pcb->cwnd));
         } else {
-          tcpwnd_size_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
+          tcpwnd_size_t new_cwnd;
+#if TCP_ABC
+          /* RFC 3465, section 2.1 Congestion Avoidance */
+          new_cwnd = pcb->cwnd;
+          if (pcb->bytes_acked + acked > pcb->bytes_acked) {
+            pcb->bytes_acked += acked;
+            if (pcb->bytes_acked >= pcb->cwnd) {
+              pcb->bytes_acked -= pcb->cwnd;
+              new_cwnd = pcb->cwnd + pcb->mss;
+            }
+          }
+#else /* TCP_ABC */
+          new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
+#endif /* TCP_ABC */
           if (new_cwnd > pcb->cwnd) {
             pcb->cwnd = new_cwnd;
           }
diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h
index 3815edb..3b0a60c 100644
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -1352,6 +1352,22 @@
 #define LWIP_WND_SCALE                  0
 #define TCP_RCV_SCALE                   0
 #endif
+
+/**
+ * TCP_ABC: set to 1 to enable Appropriate Byte Counting (ABC) from RFC 3465.
+ */
+#if !defined TCP_ABC || defined __DOXYGEN__
+#define TCP_ABC                         0
+#endif
+
+/**
+ * TCP_ABC_LIMIT: upper bound on the number of sender maximum sized segments
+ * to increase the congestion window during slow start as per RFC 3465. See
+ * section 2.3 'Choosing the Limit' for guidance on this limit
+ */
+#if !defined TCP_ABC_LIMIT || defined __DOXYGEN__
+#define TCP_ABC_LIMIT                   1
+#endif
 /**
  * @}
  */
diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h
index 34d1c10..097c54c 100644
--- a/src/include/lwip/tcp.h
+++ b/src/include/lwip/tcp.h
@@ -259,6 +259,9 @@ struct tcp_pcb {
   /* congestion avoidance/control variables */
   tcpwnd_size_t cwnd;
   tcpwnd_size_t ssthresh;
+#if TCP_ABC
+  tcpwnd_size_t bytes_acked;
+#endif /* TCP_ABC */
 
   /* sender variables */
   u32_t snd_nxt;   /* next new seqno to be sent */
-- 
1.9.5.msysgit.0

