From be56e9eed8acf82a862d19ef4f890f309018ddde Mon Sep 17 00:00:00 2001
From: jiangheng <jiangheng14@huawei.com>
Date: Sat, 28 Oct 2023 17:21:46 +0800
Subject: [PATCH] adapt read/write for rtc mode

---
 src/api/api_msg.c      |  14 ++--
 src/api/sockets.c      |  21 ++---
 src/core/init.c        |   2 +-
 src/core/pbuf.c        |   7 ++
 src/core/tcp_out.c     | 171 +++++++++++++++++++++++++++++++++--------
 src/core/udp.c         |   2 +-
 src/include/lwip/tcp.h |   4 +
 src/include/lwipopts.h |   6 +-
 8 files changed, 174 insertions(+), 53 deletions(-)

diff --git a/src/api/api_msg.c b/src/api/api_msg.c
index 0f26119..2556901 100644
--- a/src/api/api_msg.c
+++ b/src/api/api_msg.c
@@ -1754,11 +1754,15 @@ lwip_netconn_do_writemore(struct netconn *conn  WRITE_DELAYED_PARAM)
         write_more = 0;
       }
 #if GAZELLE_ENABLE
-      /* vector->ptr is private arg sock */
-      LWIP_UNUSED_ARG(dataptr);
-      write_more = 0;
-      err = tcp_write(conn->pcb.tcp, conn->current_msg->msg.w.vector->ptr, len, apiflags);
-      conn->current_msg->msg.w.len = len;
+      if (netif_is_rtc_mode(netif_default)) {
+        err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
+      } else {
+        /* vector->ptr is private arg sock */
+        LWIP_UNUSED_ARG(dataptr);
+        write_more = 0;
+        err = tcp_write_from_stack(conn->pcb.tcp, conn->current_msg->msg.w.vector->ptr, len, apiflags);
+        conn->current_msg->msg.w.len = len;
+      }
       conn->pcb.tcp->need_tso_send = 1;
 #else
       err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
diff --git a/src/api/sockets.c b/src/api/sockets.c
index 833b27f..a07fb59 100644
--- a/src/api/sockets.c
+++ b/src/api/sockets.c
@@ -1124,7 +1124,15 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags)
     apiflags |= NETCONN_DONTBLOCK;
   }
 
-#if !GAZELLE_ENABLE
+#if GAZELLE_ENABLE
+  if (!netif_is_rtc_mode(netif_default)) {
+    LWIP_UNUSED_ARG(recv_left);
+    recvd = do_lwip_read_from_lwip(sock, flags, apiflags);
+    if (recvd <= 0) {
+      return recvd;
+    }
+  } else {
+#endif
   do {
     struct pbuf *p;
     err_t err;
@@ -1203,14 +1211,10 @@ lwip_recv_tcp(struct lwip_sock *sock, void *mem, size_t len, int flags)
     apiflags |= NETCONN_DONTBLOCK | NETCONN_NOFIN;
     /* @todo: do we need to support peeking more than one pbuf? */
   } while ((recv_left > 0) && !(flags & MSG_PEEK));
-lwip_recv_tcp_done:
-#else /* GAZELLE_ENABLE */
-  LWIP_UNUSED_ARG(recv_left);
-  recvd = do_lwip_read_from_lwip(sock, flags, apiflags);
-  if (recvd <= 0) {
-    return recvd;
+#if GAZELLE_ENABLE
   }
 #endif /* GAZELLE_ENABLE */
+lwip_recv_tcp_done:
   if (apiflags & NETCONN_NOAUTORCVD) {
     if ((recvd > 0) && !(flags & MSG_PEEK)) {
       /* ensure window update after copying all data */
diff --git a/src/core/init.c b/src/core/init.c
index 6841857..5b60ed8 100644
--- a/src/core/init.c
+++ b/src/core/init.c
@@ -312,7 +312,7 @@ PACK_STRUCT_END
 #if TCP_MSS >= ((16 * 1024) - 1)
 #error "lwip_sanity_check: WARNING: TCP_MSS must be <= 16382 to prevent u16_t underflow in TCP_SNDLOWAT calculation!"
 #endif
-#if TCP_SNDLOWAT >= (0xFFFFFFFF - (4 * TCP_MSS))
+#if TCP_SNDLOWAT >= (0xFFFF - (4 * TCP_MSS))
 #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must at least be 4*MSS below u16_t overflow!"
 #endif
 #if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN
diff --git a/src/core/pbuf.c b/src/core/pbuf.c
index 3c04281..8386c90 100644
--- a/src/core/pbuf.c
+++ b/src/core/pbuf.c
@@ -117,6 +117,7 @@ pbuf_skip_const(const struct pbuf *in, u16_t in_offset, u16_t *out_offset);
 volatile u8_t pbuf_free_ooseq_pending;
 #define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
 
+#if !GAZELLE_ENABLE
 /**
  * Attempt to reclaim some memory from queued out-of-sequence TCP segments
  * if we run out of pool pbufs. It's better to give priority to new packets
@@ -176,6 +177,7 @@ pbuf_pool_is_empty(void)
   }
 #endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */
 }
+#endif /* GAZELLE_ENABLE */
 #endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */
 
 /* Initialize members of struct pbuf after allocation */
@@ -238,6 +240,10 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
       p = pbuf_alloc_reference(NULL, length, type);
       break;
     case PBUF_POOL: {
+#if GAZELLE_ENABLE
+      // alloc from pktmbuf pool, one pbuf is enough
+      p = do_lwip_alloc_pbuf(layer, length, type);
+#else
       struct pbuf *q, *last;
       u16_t rem_len; /* remaining length */
       p = NULL;
@@ -273,6 +279,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
         rem_len = (u16_t)(rem_len - qlen);
         offset = 0;
       } while (rem_len > 0);
+#endif /* GAZELLE_ENABLE */
       break;
     }
     case PBUF_RAM: {
diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c
index 4bf3bfd..4e7aac0 100644
--- a/src/core/tcp_out.c
+++ b/src/core/tcp_out.c
@@ -518,15 +518,18 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
    * pos records progress as data is segmented.
    */
 
-#if !GAZELLE_ENABLE
   /* Find the tail of the unsent queue. */
   if (pcb->unsent != NULL) {
     u16_t space;
     u16_t unsent_optlen;
 
+#if GAZELLE_ENABLE
+    last_unsent = pcb->last_unsent;
+#else
     /* @todo: this could be sped up by keeping last_unsent in the pcb */
     for (last_unsent = pcb->unsent; last_unsent->next != NULL;
          last_unsent = last_unsent->next);
+#endif
 
     /* Usable space at the end of the last unsent segment */
     unsent_optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(last_unsent->flags, pcb);
@@ -634,9 +637,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
                 pcb->unsent_oversize == 0);
 #endif /* TCP_OVERSIZE */
   }
-#else /* GAZELLE_ENABLE */
-  last_unsent = pcb->last_unsent;
-#endif /* GAZELLE_ENABLE */
 
   /*
    * Phase 3: Create new segments.
@@ -654,7 +654,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
     u8_t chksum_swapped = 0;
 #endif /* TCP_CHECKSUM_ON_COPY */
 
-#if !GAZELLE_ENABLE
     if (apiflags & TCP_WRITE_FLAG_COPY) {
       /* If copy is set, memory should be allocated and data copied
        * into pbuf */
@@ -701,13 +700,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
       /* Concatenate the headers and data pbufs together. */
       pbuf_cat(p/*header*/, p2/*data*/);
     }
-#else  /* GAZELLE_ENABLE */
-    p = do_lwip_get_from_sendring((struct lwip_sock *)arg, len - pos, &apiflags);
-    if (p == NULL) {
-      break;
-    }
-    seglen = p->tot_len;
-#endif  /* GAZELLE_ENABLE */
 
     queuelen += pbuf_clen(p);
 
@@ -717,14 +709,7 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
     if (queuelen > LWIP_MIN(TCP_SND_QUEUELEN, TCP_SNDQUEUELEN_OVERFLOW)) {
       LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n",
                   queuelen, (int)TCP_SND_QUEUELEN));
-#if GAZELLE_ENABLE
-      if (pos > 0) {
-        queuelen -= pbuf_clen(p);
-        break;
-      }
-#else
       pbuf_free(p);
-#endif
       goto memerr;
     }
 
@@ -733,12 +718,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
 #endif
 
     if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
-#if GAZELLE_ENABLE
-      if (pos > 0) {
-        queuelen -= pbuf_clen(p);
-        break;
-      }
-#endif
       goto memerr;
     }
 #if TCP_OVERSIZE_DBGCHECK
@@ -766,9 +745,6 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
                 lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
 
     pos += seglen;
-#if GAZELLE_ENABLE
-    do_lwip_get_from_sendring_over((struct lwip_sock*)arg);
-#endif
   }
 
   /*
@@ -858,12 +834,9 @@ tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
   if (queue) {
     pcb->last_unsent = prev_seg;
   }
-  pcb->snd_lbb += pos;
-  pcb->snd_buf -= pos;
-#else
+#endif
   pcb->snd_lbb += len;
   pcb->snd_buf -= len;
-#endif
   pcb->snd_queuelen = queuelen;
 
   LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n",
@@ -883,14 +856,12 @@ memerr:
   tcp_set_flags(pcb, TF_NAGLEMEMERR);
   TCP_STATS_INC(tcp.memerr);
 
-#if !GAZELLE_ENABLE
   if (concat_p != NULL) {
     pbuf_free(concat_p);
   }
   if (queue != NULL) {
     tcp_segs_free(queue);
   }
-#endif
   if (pcb->snd_queuelen != 0) {
     LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL ||
                 pcb->unsent != NULL);
@@ -899,6 +870,137 @@ memerr:
   return ERR_MEM;
 }
 
+#if GAZELLE_ENABLE
+err_t
+tcp_write_from_stack(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags)
+{
+  struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL;
+  u16_t pos = 0; /* position in 'arg' data */
+  u16_t queuelen;
+  u8_t optlen;
+  u8_t optflags = 0;
+  err_t err;
+  u16_t mss_local;
+
+  /* don't allocate segments bigger than half the maximum window we ever received */
+  mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max / 2));
+  mss_local = mss_local ? mss_local : pcb->mss;
+
+  err = tcp_write_checks(pcb, len);
+  if (err != ERR_OK) {
+    return err;
+  }
+  queuelen = pcb->snd_queuelen;
+
+  optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb);
+
+  last_unsent = pcb->last_unsent;
+
+  /*
+   * get pbuf from sendring and create new segments.
+   */
+  while (pos < len) {
+    struct pbuf *p;
+    u16_t left = len - pos;
+    u16_t max_len = mss_local - optlen;
+    u16_t seglen = LWIP_MIN(left, max_len);
+
+    p = do_lwip_get_from_sendring((struct lwip_sock *)arg, len - pos, &apiflags);
+    if (p == NULL) {
+      break;
+    }
+    seglen = p->tot_len;
+
+    queuelen += pbuf_clen(p);
+
+    /* Now that there are more segments queued, we check again if the
+     * length of the queue exceeds the configured maximum or
+     * overflows. */
+    if (queuelen > LWIP_MIN(TCP_SND_QUEUELEN, TCP_SNDQUEUELEN_OVERFLOW)) {
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_write: queue too long %"U16_F" (%d)\n",
+                  queuelen, (int)TCP_SND_QUEUELEN));
+      if (pos > 0) {
+        queuelen -= pbuf_clen(p);
+        break;
+      }
+      goto memerr;
+    }
+
+    lstack_calculate_aggregate(2, p->tot_len);
+
+    if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) {
+      if (pos > 0) {
+        queuelen -= pbuf_clen(p);
+        break;
+      }
+      goto memerr;
+    }
+
+    /* first segment of to-be-queued data? */
+    if (queue == NULL) {
+      queue = seg;
+    } else {
+      /* Attach the segment to the end of the queued segments */
+      LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL);
+      prev_seg->next = seg;
+    }
+    /* remember last segment of to-be-queued data for next iteration */
+    prev_seg = seg;
+
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n",
+                lwip_ntohl(seg->tcphdr->seqno),
+                lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg)));
+
+    pos += seglen;
+    do_lwip_get_from_sendring_over((struct lwip_sock*)arg);
+  }
+
+  /*
+   * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that
+   * is harmless
+   */
+  if (last_unsent == NULL) {
+    pcb->unsent = queue;
+  } else {
+    last_unsent->next = queue;
+  }
+
+  /*
+   * Finally update the pcb state.
+   */
+  if (queue) {
+    pcb->last_unsent = prev_seg;
+  }
+  pcb->snd_lbb += pos;
+  pcb->snd_buf -= pos;
+  pcb->snd_queuelen = queuelen;
+
+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n",
+                               pcb->snd_queuelen));
+  if (pcb->snd_queuelen != 0) {
+    LWIP_ASSERT("tcp_write: valid queue length",
+                pcb->unacked != NULL || pcb->unsent != NULL);
+  }
+
+  /* Set the PSH flag in the last segment that we enqueued. */
+  if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE) == 0)) {
+    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);
+  }
+
+  return ERR_OK;
+memerr:
+  tcp_set_flags(pcb, TF_NAGLEMEMERR);
+  TCP_STATS_INC(tcp.memerr);
+
+  if (pcb->snd_queuelen != 0) {
+    LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL ||
+                pcb->unsent != NULL);
+  }
+  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen));
+  return ERR_MEM;
+}
+#endif
+
 /**
  * Split segment on the head of the unsent queue.  If return is not
  * ERR_OK, existing head remains intact
@@ -2098,6 +2200,7 @@ tcp_rexmit(struct tcp_pcb *pcb)
 
   /* Don't take any rtt measurements after retransmitting. */
   pcb->rttest = 0;
+  pcb->need_tso_send = 1;
 
   /* Do the actual retransmission. */
   MIB2_STATS_INC(mib2.tcpretranssegs);
diff --git a/src/core/udp.c b/src/core/udp.c
index ff20ced..f38619b 100644
--- a/src/core/udp.c
+++ b/src/core/udp.c
@@ -414,7 +414,7 @@ udp_input(struct pbuf *p, struct netif *inp)
         if (udphdr->chksum != 0) {
 #if CHECKSUM_CHECK_UDP_HW
           u64_t ret = 0;
-          if (netif_get_txol_flags(inp) & DEV_RX_OFFLOAD_UDP_CKSUM) {
+          if (netif_get_rxol_flags(inp) & DEV_RX_OFFLOAD_UDP_CKSUM) {
             ret = is_cksum_bad(p);
           } else {
             ret = ip_chksum_pseudo(p, IP_PROTO_UDP, p->tot_len,
diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h
index f968441..460df21 100644
--- a/src/include/lwip/tcp.h
+++ b/src/include/lwip/tcp.h
@@ -566,6 +566,10 @@ err_t            tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx);
 
 err_t            tcp_write   (struct tcp_pcb *pcb, const void *dataptr, u16_t len,
                               u8_t apiflags);
+#if GAZELLE_ENABLE
+err_t            tcp_write_from_stack (struct tcp_pcb *pcb, const void *dataptr, u16_t len,
+                                       u8_t apiflags);
+#endif
 
 void             tcp_setprio (struct tcp_pcb *pcb, u8_t prio);
 
diff --git a/src/include/lwipopts.h b/src/include/lwipopts.h
index fbdcbf4..4ae37f5 100644
--- a/src/include/lwipopts.h
+++ b/src/include/lwipopts.h
@@ -201,8 +201,8 @@
 #define TCP_LISTEN_BACKLOG 1
 #define TCP_DEFAULT_LISTEN_BACKLOG 0xff
 
-#define TCP_OVERSIZE 0
-#define LWIP_NETIF_TX_SINGLE_PBUF 0
+#define TCP_OVERSIZE TCP_MSS
+#define LWIP_NETIF_TX_SINGLE_PBUF 1
 
 #define TCP_MSS (FRAME_MTU - IP_HLEN - TCP_HLEN)
 
@@ -212,7 +212,7 @@
 
 #define TCP_SND_QUEUELEN (8191)
 
-#define TCP_SNDLOWAT (TCP_SND_BUF / 5)
+#define TCP_SNDLOWAT (32768)
 
 #define TCP_SNDQUEUELOWAT (TCP_SND_QUEUELEN / 5)
 
-- 
2.27.0

