Patch is based on lwip patch of issue 7858 and is adjusted to a current lwip
master branch.

Issue 7858: https://savannah.nongnu.org/patch/index.php?7858).
Original patch file: https://savannah.nongnu.org/patch/download.php?file_id=26702

diff --git a/src/core/init.c b/src/core/init.c
index c24c027..65b991d 100644
--- a/src/core/init.c
+++ b/src/core/init.c
@@ -115,12 +115,21 @@
   #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"
 #endif
 #endif /* !MEMP_MEM_MALLOC */
+#if LWIP_WND_SCALE
+#if (LWIP_TCP && (TCP_WND > 0xffffffff))
+  #error "If you want to use TCP, TCP_WND must fit in an u32_t, so, you have to reduce it in your lwipopts.h"
+#endif
+#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffffffff))
+  #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u32_t, so, you have to reduce it in your lwipopts.h"
+#endif
+#else
 #if (LWIP_TCP && (TCP_WND > 0xffff))
   #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
 #endif
 #if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))
   #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h"
 #endif
+#endif /* LWIP_WND_SCALE */
 #if (LWIP_TCP && (TCP_SND_QUEUELEN < 2))
   #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work"
 #endif
diff --git a/src/core/memp.c b/src/core/memp.c
index 1323463..9306283 100644
--- a/src/core/memp.c
+++ b/src/core/memp.c
@@ -129,18 +129,32 @@ static struct memp *memp_tab[MEMP_MAX];
 #if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
 static
 #endif
+#if LWIP_WND_SCALE
+const u32_t memp_sizes[MEMP_MAX] = {
+#define LWIP_MEMPOOL(name,num,size,desc)  LWIP_MEM_ALIGN_SIZE(size),
+#include "lwip/memp_std.h"
+};
+#else
 const u16_t memp_sizes[MEMP_MAX] = {
 #define LWIP_MEMPOOL(name,num,size,desc)  LWIP_MEM_ALIGN_SIZE(size),
 #include "lwip/memp_std.h"
 };
+#endif
 
 #if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
 
 /** This array holds the number of elements in each pool. */
+#if LWIP_WND_SCALE
+static const u32_t memp_num[MEMP_MAX] = {
+#define LWIP_MEMPOOL(name,num,size,desc)  (num),
+#include "lwip/memp_std.h"
+};
+#else
 static const u16_t memp_num[MEMP_MAX] = {
 #define LWIP_MEMPOOL(name,num,size,desc)  (num),
 #include "lwip/memp_std.h"
 };
+#endif
 
 /** This array holds a textual description of each pool. */
 #ifdef LWIP_DEBUG
@@ -353,7 +367,11 @@ void
 memp_init(void)
 {
   struct memp *memp;
-  u16_t i, j;
+#if LWIP_WND_SCALE
+  u32_t i, j;
+#else
+  u16_t i,j;
+#endif
 
   for (i = 0; i < MEMP_MAX; ++i) {
     MEMP_STATS_AVAIL(used, i, 0);
diff --git a/src/core/tcp.c b/src/core/tcp.c
index a0cbb15..6e1046e 100644
--- a/src/core/tcp.c
+++ b/src/core/tcp.c
@@ -625,8 +625,12 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb)
     } else {
       /* keep the right edge of window constant */
       u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt;
+#if LWIP_WND_SCALE
+      pcb->rcv_ann_wnd = new_rcv_ann_wnd;
+#else
       LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff);
       pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd;
+#endif
     }
     return 0;
   }
@@ -648,8 +652,13 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len)
   /* pcb->state LISTEN not allowed here */
   LWIP_ASSERT("don't call tcp_recved for listen-pcbs",
     pcb->state != LISTEN);
+#if LWIP_WND_SCALE
+  LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
+              len <= 0xffffffffU - pcb->rcv_wnd );
+#else
   LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n",
               len <= 0xffff - pcb->rcv_wnd );
+#endif
 
   pcb->rcv_wnd += len;
   if (pcb->rcv_wnd > TCP_WND) {
@@ -824,7 +833,11 @@ void
 tcp_slowtmr(void)
 {
   struct tcp_pcb *pcb, *prev;
+#if LWIP_WND_SCALE
+  u32_t eff_wnd;
+#else
   u16_t eff_wnd;
+#endif
   u8_t pcb_remove;      /* flag if a PCB should be removed */
   u8_t pcb_reset;       /* flag if a RST should be sent when removing */
   err_t err;
@@ -903,9 +916,15 @@ tcp_slowtmr_start:
             pcb->ssthresh = (pcb->mss << 1);
           }
           pcb->cwnd = pcb->mss;
+#if LWIP_WND_SCALE	  
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U32_F
+                                       " ssthresh %"U32_F"\n",
+                                       pcb->cwnd, pcb->ssthresh));
+#else
           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
                                        " ssthresh %"U16_F"\n",
                                        pcb->cwnd, pcb->ssthresh));
+#endif
  
           /* The following needs to be called AFTER cwnd is set to one
              mss - STJ */
@@ -1346,6 +1365,10 @@ tcp_alloc(u8_t prio)
     pcb->snd_queuelen = 0;
     pcb->rcv_wnd = TCP_WND;
     pcb->rcv_ann_wnd = TCP_WND;
+#if LWIP_WND_SCALE
+    pcb->snd_scale = 0;
+    pcb->rcv_scale = 0;
+#endif    
     pcb->tos = 0;
     pcb->ttl = TCP_TTL;
     /* As initial send MSS, we use TCP_MSS but limit it to 536.
diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c
index dacf5cf..7ca09ef 100644
--- a/src/core/tcp_in.c
+++ b/src/core/tcp_in.c
@@ -500,9 +500,6 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
     npcb->state = SYN_RCVD;
     npcb->rcv_nxt = seqno + 1;
     npcb->rcv_ann_right_edge = npcb->rcv_nxt;
-    npcb->snd_wnd = tcphdr->wnd;
-    npcb->snd_wnd_max = tcphdr->wnd;
-    npcb->ssthresh = npcb->snd_wnd;
     npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
     npcb->callback_arg = pcb->callback_arg;
 #if LWIP_CALLBACK_API
@@ -516,6 +513,10 @@ tcp_listen_input(struct tcp_pcb_listen *pcb)
 
     /* Parse any options in the SYN. */
     tcp_parseopt(npcb);
+    npcb->snd_wnd = SND_WND_SCALE(npcb, tcphdr->wnd);
+    npcb->snd_wnd_max = SND_WND_SCALE(npcb, tcphdr->wnd);
+    npcb->ssthresh = npcb->snd_wnd;
+    
 #if TCP_CALCULATE_EFF_SEND_MSS
     npcb->mss = tcp_eff_send_mss(npcb->mss, &npcb->local_ip,
       &npcb->remote_ip, PCB_ISIPV6(npcb));
@@ -653,8 +654,8 @@ tcp_process(struct tcp_pcb *pcb)
       pcb->rcv_nxt = seqno + 1;
       pcb->rcv_ann_right_edge = pcb->rcv_nxt;
       pcb->lastack = ackno;
-      pcb->snd_wnd = tcphdr->wnd;
-      pcb->snd_wnd_max = tcphdr->wnd;
+      pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd);
+      pcb->snd_wnd_max = SND_WND_SCALE(pcb, tcphdr->wnd);
       pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
       pcb->state = ESTABLISHED;
 
@@ -670,7 +671,11 @@ tcp_process(struct tcp_pcb *pcb)
       pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
       LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
       --pcb->snd_queuelen;
+#ifdef LWIP_WND_SCALE
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U32_F"\n", (u32_t)pcb->snd_queuelen));
+#else
       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
+#endif      
       rseg = pcb->unacked;
       pcb->unacked = rseg->next;
       tcp_seg_free(rseg);
@@ -703,7 +708,11 @@ tcp_process(struct tcp_pcb *pcb)
     if (flags & TCP_ACK) {
       /* expected ACK number? */
       if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
-        u16_t old_cwnd;
+#if LWIP_WND_SCALE
+        u32_t old_cwnd;
+#else
+	u16_t old_cwnd;	  
+#endif
         pcb->state = ESTABLISHED;
         LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
 #if LWIP_CALLBACK_API
@@ -889,11 +898,11 @@ tcp_receive(struct tcp_pcb *pcb)
     if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||
        (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||
        (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {
-      pcb->snd_wnd = tcphdr->wnd;
+      pcb->snd_wnd = SND_WND_SCALE(pcb, tcphdr->wnd); 
       /* keep track of the biggest window announced by the remote host to calculate
          the maximum segment size */
       if (pcb->snd_wnd_max < tcphdr->wnd) {
-        pcb->snd_wnd_max = tcphdr->wnd;
+        pcb->snd_wnd_max = SND_WND_SCALE(pcb, tcphdr->wnd); 
       }
       pcb->snd_wl1 = seqno;
       pcb->snd_wl2 = ackno;
@@ -957,9 +966,15 @@ tcp_receive(struct tcp_pcb *pcb)
               if (pcb->dupacks > 3) {
                 /* Inflate the congestion window, but not if it means that
                    the value overflows. */
+#if LWIP_WND_SCALE
+                if ((u32_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
+                  pcb->cwnd += pcb->mss;
+                }
+#else
                 if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
                   pcb->cwnd += pcb->mss;
                 }
+#endif
               } else if (pcb->dupacks == 3) {
                 /* Do fast retransmit */
                 tcp_rexmit_fast(pcb);
@@ -1003,18 +1018,37 @@ tcp_receive(struct tcp_pcb *pcb)
          ssthresh). */
       if (pcb->state >= ESTABLISHED) {
         if (pcb->cwnd < pcb->ssthresh) {
+#if LWIP_WND_SCALE
+          if ((u32_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
+            pcb->cwnd += pcb->mss;
+          }
+#else
           if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {
             pcb->cwnd += pcb->mss;
           }
-          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));
+#endif
+#if LWIP_WND_SCALE	  
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U32_F"\n", pcb->cwnd));
+#else
+	  LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));	  
+#endif
         } else {
+#if LWIP_WND_SCALE	    
+          u32_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
+          if (new_cwnd > pcb->cwnd) {
+            pcb->cwnd = new_cwnd;
+          }
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U32_F"\n", pcb->cwnd));
+#else
           u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);
           if (new_cwnd > pcb->cwnd) {
             pcb->cwnd = new_cwnd;
           }
           LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));
+#endif
         }
-      }
+      }	    
+
       LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",
                                     ackno,
                                     pcb->unacked != NULL?
@@ -1034,9 +1068,13 @@ tcp_receive(struct tcp_pcb *pcb)
 
         next = pcb->unacked;
         pcb->unacked = pcb->unacked->next;
-
+#if LWIP_WND_SCALE
+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U32_F" ... ", (u32_t)pcb->snd_queuelen));
+        LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
+#else
         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
         LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
+#endif
         /* Prevent ACK for FIN to generate a sent event */
         if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
           pcb->acked--;
@@ -1045,7 +1083,11 @@ tcp_receive(struct tcp_pcb *pcb)
         pcb->snd_queuelen -= pbuf_clen(next->p);
         tcp_seg_free(next);
 
+#if LWIP_WND_SCALE
+	LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U32_F" (after freeing unacked)\n", (u32_t)pcb->snd_queuelen));
+#else
         LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));
+#endif	
         if (pcb->snd_queuelen != 0) {
           LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
                       pcb->unsent != NULL);
@@ -1092,7 +1134,11 @@ tcp_receive(struct tcp_pcb *pcb)
         pcb->unsent_oversize = 0;
       }
 #endif /* TCP_OVERSIZE */ 
+#if LWIP_WND_SCALE
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U32_F" ... ", (u32_t)pcb->snd_queuelen));
+#else      
       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));
+#endif
       LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
       /* Prevent ACK for FIN to generate a sent event */
       if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) {
@@ -1100,7 +1146,11 @@ tcp_receive(struct tcp_pcb *pcb)
       }
       pcb->snd_queuelen -= pbuf_clen(next->p);
       tcp_seg_free(next);
+#if LWIP_WND_SCALE
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U32_F" (after freeing unsent)\n", (u32_t)pcb->snd_queuelen));
+#else     
       LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));
+#endif
       if (pcb->snd_queuelen != 0) {
         LWIP_ASSERT("tcp_receive: valid queue length",
           pcb->unacked != NULL || pcb->unsent != NULL);
@@ -1580,7 +1630,7 @@ tcp_parseopt(struct tcp_pcb *pcb)
 #if LWIP_TCP_TIMESTAMPS
   u32_t tsval;
 #endif
-
+  
   opts = (u8_t *)tcphdr + TCP_HLEN;
 
   /* Parse the TCP MSS option, if present. */
@@ -1612,6 +1662,26 @@ tcp_parseopt(struct tcp_pcb *pcb)
         /* Advance to next option */
         c += 0x04;
         break;
+#if LWIP_WND_SCALE
+    case 0x03:
+	LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: WND_SCALE\n"));
+        if (opts[c + 1] != 0x03 || c + 0x03 > max_c) {
+          /* Bad length */
+          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n"));
+          return;
+        }
+	/* An WND_SCALE option with the right option length. */
+	pcb->snd_scale = opts[c + 2];
+	pcb->rcv_scale = TCP_RCV_SCALE;
+	/* If syn was received with wnd scale option,
+	   activate wnd scale opt */
+	if( flags & TCP_SYN ) {
+	    pcb->flags |= TF_WND_SCALE;
+	}
+	/* Advance to next option */
+	c += 0x03;
+	break;
+#endif
 #if LWIP_TCP_TIMESTAMPS
       case 0x08:
         LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n"));
diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c
index b9fc339..d6473c2 100644
--- a/src/core/tcp_out.c
+++ b/src/core/tcp_out.c
@@ -108,7 +108,7 @@ tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen,
     tcphdr->seqno = seqno_be;
     tcphdr->ackno = htonl(pcb->rcv_nxt);
     TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK);
-    tcphdr->wnd = htons(pcb->rcv_ann_wnd);
+    tcphdr->wnd = htons(RCV_WND_SCALE(pcb,pcb->rcv_ann_wnd));
     tcphdr->chksum = 0;
     tcphdr->urgp = 0;
 
@@ -314,15 +314,23 @@ tcp_write_checks(struct tcp_pcb *pcb, u16_t len)
     pcb->flags |= TF_NAGLEMEMERR;
     return ERR_MEM;
   }
-
+#ifdef LWIP_WND_SCALE
+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U32_F"\n", (u32_t)pcb->snd_queuelen));
+#else
   LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));
+#endif
 
   /* If total number of pbufs on the unsent/unacked queues exceeds the
    * configured maximum, return an error */
   /* check for configured max queuelen and possible overflow */
   if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
+#ifdef LWIP_WND_SCALE
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U32_F" (max %"U32_F")\n",
+      pcb->snd_queuelen, TCP_SND_QUEUELEN));      
+#else
     LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n",
       pcb->snd_queuelen, TCP_SND_QUEUELEN));
+#endif
     TCP_STATS_INC(tcp.memerr);
     pcb->flags |= TF_NAGLEMEMERR;
     return ERR_MEM;
@@ -359,12 +367,16 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
   struct pbuf *concat_p = NULL;
   struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL;
   u16_t pos = 0; /* position in 'arg' data */
+#if LWIP_WND_SCALE
+  u32_t queuelen;
+#else
   u16_t queuelen;
+#endif
   u8_t optlen = 0;
   u8_t optflags = 0;
 #if TCP_OVERSIZE
   u16_t oversize = 0;
-  u16_t oversize_used = 0;
+  u16_t oversize_used = 0;  
 #endif /* TCP_OVERSIZE */
 #if TCP_CHECKSUM_ON_COPY
   u16_t concat_chksum = 0;
@@ -394,10 +406,10 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
 #if LWIP_TCP_TIMESTAMPS
   if ((pcb->flags & TF_TIMESTAMP)) {
     optflags = TF_SEG_OPTS_TS;
-    optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
   }
 #endif /* LWIP_TCP_TIMESTAMPS */
 
+  optlen = LWIP_TCP_OPT_LENGTH( optflags );
 
   /*
    * TCP segmentation is done in three phases with increasing complexity:
@@ -581,7 +593,11 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
      * length of the queue exceeds the configured maximum or
      * overflows. */
     if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {
+#ifdef LWIP_WND_SCALE
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U32_F" (%"U32_F")\n", queuelen, TCP_SND_QUEUELEN));	
+#else
       LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));
+#endif      
       pbuf_free(p);
       goto memerr;
     }
@@ -751,6 +767,12 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
     optflags |= TF_SEG_OPTS_TS;
   }
 #endif /* LWIP_TCP_TIMESTAMPS */
+#if LWIP_WND_SCALE
+  if ((pcb->flags & TF_WND_SCALE) && ( flags & TCP_SYN ) ) {
+    optflags |= TF_SEG_OPTS_WND_SCALE;
+  }
+#endif /* LWIP_TCP_TIMESTAMPS */
+  
   optlen = LWIP_TCP_OPT_LENGTH(optflags);
 
   /* tcp_enqueue_flags is always called with either SYN or FIN in flags.
@@ -787,6 +809,7 @@ tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags)
                ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
                (u16_t)flags));
 
+
   /* Now append seg to pcb->unsent queue */
   if (pcb->unsent == NULL) {
     pcb->unsent = seg;
@@ -837,6 +860,25 @@ tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts)
 }
 #endif
 
+#if LWIP_WND_SCALE
+/* Build a window scale option (3 bytes long) at the specified options pointer)
+ *
+ * @param pcb tcp_pcb
+ * @param opts option pointer where to store the window scale option
+ */
+static void
+tcp_build_wnd_scale_option(struct tcp_pcb *pcb, u32_t *opts)
+{
+  /* Pad with one NOP option to make everything nicely aligned */
+    unsigned char* optdata = (unsigned char*) opts;
+    optdata[0] = 1; /*NOP */
+    optdata[1] = 3; /*Window Scale option code*/
+    optdata[2] = 3; /*option length*/
+    optdata[3] = TCP_RCV_SCALE; /* window scale value*/
+}
+#endif
+
+
 /** Send an ACK without data.
  *
  * @param pcb Protocol control block for the TCP connection to send the ACK
@@ -851,6 +893,7 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
 #endif /* LWIP_TCP_TIMESTAMPS || CHECKSUM_GEN_TCP */
 
 #if LWIP_TCP_TIMESTAMPS
+  u32_t *opts;
   if (pcb->flags & TF_TIMESTAMP) {
     optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS);
   }
@@ -869,12 +912,15 @@ tcp_send_empty_ack(struct tcp_pcb *pcb)
   /* remove ACK flags from the PCB, as we send an empty ACK now */
   pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);
 
-  /* NB. MSS option is only sent on SYNs, so ignore it here */
 #if LWIP_TCP_TIMESTAMPS
+  opts = (u32_t *)(void *)(tcphdr + 1);
+
+  /* NB. MSS option is only sent on SYNs, so ignore it here */
   pcb->ts_lastacksent = pcb->rcv_nxt;
 
   if (pcb->flags & TF_TIMESTAMP) {
-    tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1));
+    tcp_build_timestamp_option(pcb, opts );
+    opts += 3;
   }
 #endif 
 
@@ -924,6 +970,9 @@ tcp_output(struct tcp_pcb *pcb)
 
   wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);
 
+  LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U32_F
+	  ", wnd %"U32_F"\n",pcb->snd_wnd, pcb->cwnd, wnd ));
+
   seg = pcb->unsent;
 
   /* If the TF_ACK_NOW flag is set and no data will be sent (either
@@ -952,13 +1001,13 @@ tcp_output(struct tcp_pcb *pcb)
 #endif /* TCP_OUTPUT_DEBUG */
 #if TCP_CWND_DEBUG
   if (seg == NULL) {
-    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
-                                 ", cwnd %"U16_F", wnd %"U32_F
+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F
+                                 ", cwnd %"U32_F", wnd %"U32_F
                                  ", seg == NULL, ack %"U32_F"\n",
                                  pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
   } else {
     LWIP_DEBUGF(TCP_CWND_DEBUG, 
-                ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
+                ("tcp_output: snd_wnd %"U32_F", cwnd %"U32_F", wnd %"U32_F
                  ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
                  pcb->snd_wnd, pcb->cwnd, wnd,
                  ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
@@ -982,7 +1031,7 @@ tcp_output(struct tcp_pcb *pcb)
       break;
     }
 #if TCP_CWND_DEBUG
-    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U32_F", cwnd %"U32_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
                             pcb->snd_wnd, pcb->cwnd, wnd,
                             ntohl(seg->tcphdr->seqno) + seg->len -
                             pcb->lastack,
@@ -1069,7 +1118,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
   seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
 
   /* advertise our receive window size in this TCP segment */
-  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
+  seg->tcphdr->wnd = htons(RCV_WND_SCALE(pcb,pcb->rcv_ann_wnd));
 
   pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
 
@@ -1094,7 +1143,13 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
     opts += 3;
   }
 #endif
-
+#if LWIP_WND_SCALE
+  if ( seg->flags & TF_SEG_OPTS_WND_SCALE ) {
+    tcp_build_wnd_scale_option(pcb, opts);
+    opts += 1;
+  }
+#endif
+  
   /* Set retransmission timer running if it is not currently enabled 
      This must be set before checking the route. */
   if (pcb->rtime == -1) {
@@ -1224,7 +1279,11 @@ tcp_rst_impl(u32_t seqno, u32_t ackno,
   tcphdr->seqno = htonl(seqno);
   tcphdr->ackno = htonl(ackno);
   TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK);
-  tcphdr->wnd = PP_HTONS(TCP_WND);
+#if LWIP_WND_SCALE
+  tcphdr->wnd = PP_HTONS( ( ( TCP_WND >> TCP_RCV_SCALE ) & 0xFFFF ) );
+#else
+  tcphdr->wnd = PP_HTONS( TCP_WND );
+#endif
   tcphdr->chksum = 0;
   tcphdr->urgp = 0;
 
diff --git a/src/include/lwip/memp.h b/src/include/lwip/memp.h
index f0d0739..899a9cc 100644
--- a/src/include/lwip/memp.h
+++ b/src/include/lwip/memp.h
@@ -76,7 +76,11 @@ typedef enum {
 #endif /* MEM_USE_POOLS */
 
 #if MEMP_MEM_MALLOC || MEM_USE_POOLS
+#if LWIP_WND_SCALE
+extern const u32_t memp_sizes[MEMP_MAX];
+#else
 extern const u16_t memp_sizes[MEMP_MAX];
+#endif
 #endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
 
 #if MEMP_MEM_MALLOC
diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h
index e51f8e5..fdfd60c 100644
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -1080,6 +1080,11 @@
 #define LWIP_CALLBACK_API               1
 #endif
 
+#ifndef LWIP_WND_SCALE
+#define LWIP_WND_SCALE			0
+#define TCP_RCV_SCALE			0
+#endif
+
 
 /*
    ----------------------------------
diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h
index add77e8..f02f18a 100644
--- a/src/include/lwip/tcp.h
+++ b/src/include/lwip/tcp.h
@@ -125,6 +125,14 @@ typedef void  (*tcp_err_fn)(void *arg, err_t err);
  */
 typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err);
 
+#if LWIP_WND_SCALE
+#define RCV_WND_SCALE(pcb, wnd) (((wnd) >> (pcb)->rcv_scale))
+#define SND_WND_SCALE(pcb, wnd) (((wnd) << (pcb)->snd_scale))
+#else
+#define RCV_WND_SCALE(pcb, wnd) (wnd)
+#define SND_WND_SCALE(pcb, wnd) (wnd)
+#endif 
+
 enum tcp_state {
   CLOSED      = 0,
   LISTEN      = 1,
@@ -176,15 +184,16 @@ struct tcp_pcb {
   /* ports are in host byte order */
   u16_t remote_port;
   
-  u8_t flags;
-#define TF_ACK_DELAY   ((u8_t)0x01U)   /* Delayed ACK. */
-#define TF_ACK_NOW     ((u8_t)0x02U)   /* Immediate ACK. */
-#define TF_INFR        ((u8_t)0x04U)   /* In fast recovery. */
-#define TF_TIMESTAMP   ((u8_t)0x08U)   /* Timestamp option enabled */
-#define TF_RXCLOSED    ((u8_t)0x10U)   /* rx closed by tcp_shutdown */
-#define TF_FIN         ((u8_t)0x20U)   /* Connection was closed locally (FIN segment enqueued). */
-#define TF_NODELAY     ((u8_t)0x40U)   /* Disable Nagle algorithm */
-#define TF_NAGLEMEMERR ((u8_t)0x80U)   /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
+  u16_t flags;
+#define TF_ACK_DELAY   ((u16_t)0x0001U)   /* Delayed ACK. */
+#define TF_ACK_NOW     ((u16_t)0x0002U)   /* Immediate ACK. */
+#define TF_INFR        ((u16_t)0x0004U)   /* In fast recovery. */
+#define TF_TIMESTAMP   ((u16_t)0x0008U)   /* Timestamp option enabled */
+#define TF_RXCLOSED    ((u16_t)0x0010U)   /* rx closed by tcp_shutdown */
+#define TF_FIN         ((u16_t)0x0020U)   /* Connection was closed locally (FIN segment enqueued). */
+#define TF_NODELAY     ((u16_t)0x0040U)   /* Disable Nagle algorithm */
+#define TF_NAGLEMEMERR ((u16_t)0x0080U)   /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */
+#define TF_WND_SCALE   ((u16_t)0x0100U)   /* Window Scale option enabled */
 
   /* the rest of the fields are in host byte order
      as we have to do some math with them */
@@ -196,8 +205,13 @@ struct tcp_pcb {
 
   /* receiver variables */
   u32_t rcv_nxt;   /* next seqno expected */
+#if LWIP_WND_SCALE
+  u32_t rcv_wnd;   /* receiver window available */
+  u32_t rcv_ann_wnd; /* receiver window to announce */
+#else
   u16_t rcv_wnd;   /* receiver window available */
   u16_t rcv_ann_wnd; /* receiver window to announce */
+#endif
   u32_t rcv_ann_right_edge; /* announced right edge of window */
 
   /* Retransmission timer. */
@@ -218,26 +232,49 @@ struct tcp_pcb {
   u32_t lastack; /* Highest acknowledged seqno. */
 
   /* congestion avoidance/control variables */
+#if LWIP_WND_SCALE // Luis: en el parche original no se tocan
+  u32_t cwnd;  
+  u32_t ssthresh;
+#else
   u16_t cwnd;
   u16_t ssthresh;
+#endif
 
   /* sender variables */
   u32_t snd_nxt;   /* next new seqno to be sent */
   u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last
                              window update. */
   u32_t snd_lbb;       /* Sequence number of next byte to be buffered. */
+#if LWIP_WND_SCALE  
+  u32_t snd_wnd;   /* sender window */
+  u32_t snd_wnd_max; /* the maximum sender window announced by the remote host */
+#else
   u16_t snd_wnd;   /* sender window */
   u16_t snd_wnd_max; /* the maximum sender window announced by the remote host */
+#endif
 
   u16_t acked;
 
+#if LWIP_WND_SCALE
+  u32_t snd_buf;   /* Available buffer space for sending (in bytes). */
+#else
   u16_t snd_buf;   /* Available buffer space for sending (in bytes). */
-#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
+#endif
+#if LWIP_WND_SCALE
+  #define TCP_SNDQUEUELEN_OVERFLOW (0x03ffffffU-3)
+  u32_t snd_queuelen; /* Available buffer space for sending (in pbufs). */
+#else
+  #define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3)
   u16_t snd_queuelen; /* Available buffer space for sending (in pbufs). */
+#endif
 
 #if TCP_OVERSIZE
   /* Extra bytes available at the end of the last pbuf in unsent. */
+  #if LWIP_WND_SCALE
+  u32_t unsent_oversize;
+  #else
   u16_t unsent_oversize;
+  #endif /* LWIP_WND_SCALE */
 #endif /* TCP_OVERSIZE */ 
 
   /* These are ordered by sequence number: */
@@ -281,6 +318,11 @@ struct tcp_pcb {
 
   /* KEEPALIVE counter */
   u8_t keep_cnt_sent;
+
+#if LWIP_WND_SCALE
+  u8_t snd_scale;
+  u8_t rcv_scale;
+#endif  
 };
 
 struct tcp_pcb_listen {
diff --git a/src/include/lwip/tcp_impl.h b/src/include/lwip/tcp_impl.h
index 2afc20d..8578ff7 100644
--- a/src/include/lwip/tcp_impl.h
+++ b/src/include/lwip/tcp_impl.h
@@ -294,12 +294,14 @@ struct tcp_seg {
 #define TF_SEG_OPTS_TS          (u8_t)0x02U /* Include timestamp option. */
 #define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is
                                                checksummed into 'chksum' */
+#define TF_SEG_OPTS_WND_SCALE 	(u8_t)0x08U /* Include WND SCALE option */
   struct tcp_hdr *tcphdr;  /* the TCP header */
 };
 
 #define LWIP_TCP_OPT_LENGTH(flags)              \
-  (flags & TF_SEG_OPTS_MSS ? 4  : 0) +          \
-  (flags & TF_SEG_OPTS_TS  ? 12 : 0)
+  (flags & TF_SEG_OPTS_MSS 	 ? 4  : 0) +    \
+  (flags & TF_SEG_OPTS_TS  	 ? 12 : 0) +    \
+  (flags & TF_SEG_OPTS_WND_SCALE ? 4  : 0)
 
 /** This returns a TCP header option for MSS in an u32_t */
 #define TCP_BUILD_MSS_OPTION(mss) htonl(0x02040000 | ((mss) & 0xFFFF))
