// File: /workspace/github_c_makefile_star2_O1/FH0[P]tun_direct/lwip-2.1.2/src/core/tcp_out.c
// Function: tcp_output
err_t
tcp_output(struct tcp_pcb *pcb)
{
  struct tcp_seg *seg, *useg;
  u32_t wnd, snd_nxt;
  err_t err;
  struct netif *netif;
#if TCP_CWND_DEBUG
  s16_t i = 0;
#endif /* TCP_CWND_DEBUG */

  LWIP_ASSERT_CORE_LOCKED();

  LWIP_ASSERT("tcp_output: invalid pcb", pcb != NULL);
  /* pcb->state LISTEN not allowed here */
  LWIP_ASSERT("don't call tcp_output for listen-pcbs",
              pcb->state != LISTEN);

  /* First, check if we are invoked by the TCP input processing
     code. If so, we do not output anything. Instead, we rely on the
     input processing code to call us when input processing is done
     with. */
  if (tcp_input_pcb == pcb) {
    return ERR_OK;
  }

  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);

  seg = pcb->unsent;

  if (seg == NULL) {
    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
                                   (void *)pcb->unsent));
    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F
                                 ", cwnd %"TCPWNDSIZE_F", wnd %"U32_F
                                 ", seg == NULL, ack %"U32_F"\n",
                                 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));

    /* If the TF_ACK_NOW flag is set and the ->unsent queue is empty, construct
     * an empty ACK segment and send it. */
    if (pcb->flags & TF_ACK_NOW) {
      return tcp_send_empty_ack(pcb);
    }
    /* nothing to send: shortcut out of here */
    goto output_done;
  } else {
    LWIP_DEBUGF(TCP_CWND_DEBUG,
                ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F
                 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
                 pcb->snd_wnd, pcb->cwnd, wnd,
                 lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
                 lwip_ntohl(seg->tcphdr->seqno), pcb->lastack));
  }

  netif = tcp_route(pcb, &pcb->local_ip, &pcb->remote_ip);
  if (netif == NULL) {
    return ERR_RTE;
  }

  /* If we don't have a local IP address, we get one from netif */
  if (ip_addr_isany(&pcb->local_ip)) {
    const ip_addr_t *local_ip = ip_netif_get_local_ip(netif, &pcb->remote_ip);
    if (local_ip == NULL) {
      return ERR_RTE;
    }
    ip_addr_copy(pcb->local_ip, *local_ip);
  }

  /* Handle the current segment not fitting within the window */
  if (lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd) {
    /* We need to start the persistent timer when the next unsent segment does not fit
     * within the remaining (could be 0) send window and RTO timer is not running (we
     * have no in-flight data). If window is still too small after persist timer fires,
     * then we split the segment. We don't consider the congestion window since a cwnd
     * smaller than 1 SMSS implies in-flight data
     */
    if (wnd == pcb->snd_wnd && pcb->unacked == NULL && pcb->persist_backoff == 0) {
      pcb->persist_cnt = 0;
      pcb->persist_backoff = 1;
      pcb->persist_probe = 0;
    }
    /* We need an ACK, but can't send data now, so send an empty ACK */
    if (pcb->flags & TF_ACK_NOW) {
      return tcp_send_empty_ack(pcb);
    }
    goto output_done;
  }
  /* Stop persist timer, above conditions are not active */
  pcb->persist_backoff = 0;

  /* useg should point to last segment on unacked queue */
  useg = pcb->unacked;
  if (useg != NULL) {
    for (; useg->next != NULL; useg = useg->next);
  }
  /* data available and window allows it to be sent? */
  while (seg != NULL &&
         lwip_ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
    LWIP_ASSERT("RST not expected here!",
                (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
    /* Stop sending if the nagle algorithm would prevent it
     * Don't stop:
     * - if tcp_write had a memory error before (prevent delayed ACK timeout) or
     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -
     *   either seg->next != NULL or pcb->unacked == NULL;
     *   RST is no sent using tcp_write/tcp_output.
     */
    if ((tcp_do_output_nagle(pcb) == 0) &&
        ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)) {
      break;
    }
#if TCP_CWND_DEBUG
    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"TCPWNDSIZE_F", cwnd %"TCPWNDSIZE_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n",
                                 pcb->snd_wnd, pcb->cwnd, wnd,
                                 lwip_ntohl(seg->tcphdr->seqno) + seg->len -
                                 pcb->lastack,
                                 lwip_ntohl(seg->tcphdr->seqno), pcb->lastack, i));
    ++i;
#endif /* TCP_CWND_DEBUG */

    if (pcb->state != SYN_SENT) {
      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);
    }

    err = tcp_output_segment(seg, pcb, netif);
    if (err != ERR_OK) {
      /* segment could not be sent, for whatever reason */
      tcp_set_flags(pcb, TF_NAGLEMEMERR);
      return err;
    }
#if TCP_OVERSIZE_DBGCHECK
    seg->oversize_left = 0;
#endif /* TCP_OVERSIZE_DBGCHECK */
    pcb->unsent = seg->next;
    if (pcb->state != SYN_SENT) {
      tcp_clear_flags(pcb, TF_ACK_DELAY | TF_ACK_NOW);
    }
    snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);
    if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
      pcb->snd_nxt = snd_nxt;
    }
    /* put segment on unacknowledged list if length > 0 */
    if (TCP_TCPLEN(seg) > 0) {
      seg->next = NULL;
      /* unacked list is empty? */
      if (pcb->unacked == NULL) {
        pcb->unacked = seg;
        useg = seg;
        /* unacked list is not empty? */
      } else {
        /* In the case of fast retransmit, the packet should not go to the tail
         * of the unacked queue, but rather somewhere before it. We need to check for
         * this case. -STJ Jul 27, 2004 */
        if (TCP_SEQ_LT(lwip_ntohl(seg->tcphdr->seqno), lwip_ntohl(useg->tcphdr->seqno))) {
          /* add segment to before tail of unacked list, keeping the list sorted */
          struct tcp_seg **cur_seg = &(pcb->unacked);
          while (*cur_seg &&
                 TCP_SEQ_LT(lwip_ntohl((*cur_seg)->tcphdr->seqno), lwip_ntohl(seg->tcphdr->seqno))) {
            cur_seg = &((*cur_seg)->next );
          }
          seg->next = (*cur_seg);
          (*cur_seg) = seg;
        } else {
          /* add segment to tail of unacked list */
          useg->next = seg;
          useg = useg->next;
        }
      }
      /* do not queue empty segments on the unacked list */
    } else {
      tcp_seg_free(seg);
    }
    seg = pcb->unsent;
  }
#if TCP_OVERSIZE
  if (pcb->unsent == NULL) {
    /* last unsent has been removed, reset unsent_oversize */
    pcb->unsent_oversize = 0;
  }
#endif /* TCP_OVERSIZE */

output_done:
  tcp_clear_flags(pcb, TF_NAGLEMEMERR);
  return ERR_OK;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
testq %rdi, %rdi
je 0xc55c
movq %rdi, %rbx
cmpl $0x1, 0x48(%rdi)
je 0xc578
leaq 0x119aa(%rip), %rax     # 0x1d980
cmpq %rbx, (%rax)
je 0xc4dd
movl 0x80(%rbx), %r14d
movl 0x98(%rbx), %eax
cmpw %r14w, %ax
cmovbl %eax, %r14d
movq 0xa8(%rbx), %r12
testq %r12, %r12
je 0xc0a5
leaq 0x18(%rbx), %rdx
movq %rbx, %rdi
movq %rbx, %rsi
movq %rdx, 0x18(%rsp)
callq 0xc662
movb $-0x4, %bpl
movq %rax, 0x10(%rsp)
testq %rax, %rax
je 0xc4df
cmpb $0x6, 0x14(%rbx)
movl (%rbx), %eax
jne 0xc04c
testl %eax, %eax
jne 0xc054
cmpl $0x0, 0x4(%rbx)
jne 0xc054
cmpl $0x0, 0x8(%rbx)
jne 0xc054
cmpl $0x0, 0xc(%rbx)
jne 0xc054
jmp 0xc0e5
testl %eax, %eax
je 0xc0e5
movzwl %r14w, %ebp
movq 0x18(%r12), %rax
movl 0x4(%rax), %edi
callq 0x13c57
subl 0x7c(%rbx), %eax
movzwl 0x10(%r12), %ecx
addl %eax, %ecx
movl %ebp, 0x24(%rsp)
cmpl %ebp, %ecx
jbe 0xc0c5
cmpw 0x98(%rbx), %r14w
jne 0xc0a5
cmpq $0x0, 0xb0(%rbx)
jne 0xc0a5
cmpb $0x0, 0xfd(%rbx)
jne 0xc0a5
movw $0x100, 0xfc(%rbx)      # imm = 0x100
movb $0x0, 0xfe(%rbx)
testb $0x2, 0x52(%rbx)
je 0xc4d9
movq %rbx, %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xc5dd
movb $0x0, 0xfd(%rbx)
movq 0xb0(%rbx), %rax
testq %rax, %rax
je 0xc103
movq %rax, %r14
movq (%rax), %rax
testq %rax, %rax
jne 0xc0d8
jmp 0xc106
cmpb $0x6, 0x2c(%rbx)
jne 0xc4f6
movq 0x10(%rsp), %rdi
movq 0x18(%rsp), %rsi
callq 0xfaef
jmp 0xc4ff
xorl %r14d, %r14d
leaq 0xb0(%rbx), %r15
movq 0x18(%r12), %rax
movl 0x4(%rax), %edi
callq 0x13c57
subl 0x7c(%rbx), %eax
movzwl 0x10(%r12), %ecx
addl %eax, %ecx
cmpl 0x24(%rsp), %ecx
ja 0xc4c6
movq 0x18(%r12), %rax
movzwl 0xc(%rax), %edi
callq 0x13c50
testb $0x4, %al
jne 0xc540
cmpq $0x0, (%r15)
je 0xc153
movzwl 0x52(%rbx), %eax
testb $0x44, %al
je 0xc1c6
cmpl $0x2, 0x48(%rbx)
je 0xc178
movq 0x18(%r12), %rax
movzwl 0xc(%rax), %ebp
movl $0x10, %edi
callq 0x13c50
orw %bp, %ax
movq 0x18(%r12), %rcx
movw %ax, 0xc(%rcx)
movq %r12, %rdi
callq 0xc784
testl %eax, %eax
je 0xc18b
xorl %ebp, %ebp
jmp 0xc3a5
movl 0x5c(%rbx), %edi
callq 0x13c57
movq 0x18(%r12), %rcx
movl %eax, 0x8(%rcx)
movzwl 0x62(%rbx), %edi
callq 0x13c50
movq 0x18(%r12), %r13
movw %ax, 0xe(%r13)
movzwl 0x62(%rbx), %eax
addl 0x5c(%rbx), %eax
movl %eax, 0x64(%rbx)
testb $0x1, 0x17(%r12)
jne 0xc213
addq $0x14, %r13
jmp 0xc23d
movq 0xa8(%rbx), %rcx
testq %rcx, %rcx
je 0xc1ea
cmpq $0x0, (%rcx)
jne 0xc153
movzwl 0x10(%rcx), %ecx
cmpw 0x6a(%rbx), %cx
jae 0xc153
cmpw $0x0, 0x9c(%rbx)
je 0xc153
testb $-0x60, %al
jne 0xc153
cmpw $0x5a, 0x9e(%rbx)
jae 0xc153
jmp 0xc4c6
movl $0x5b4, %edi            # imm = 0x5B4
movq 0x10(%rsp), %rsi
movq 0x18(%rsp), %rdx
callq 0x7f01
movzwl %ax, %edi
orl $0x2040000, %edi        # imm = 0x2040000
callq 0x13c57
movl %eax, 0x14(%r13)
addq $0x18, %r13
cmpw $0x0, 0x68(%rbx)
jns 0xc24a
movw $0x0, 0x68(%rbx)
cmpl $0x0, 0x6c(%rbx)
jne 0xc26c
leaq 0x116c5(%rip), %rax     # 0x1d91c
movl (%rax), %eax
movl %eax, 0x6c(%rbx)
movq 0x18(%r12), %rax
movl 0x4(%rax), %edi
callq 0x13c57
movl %eax, 0x70(%rbx)
movq 0x8(%r12), %rcx
movq 0x18(%r12), %rax
movl 0x8(%rcx), %edx
movl %eax, %esi
subl %edx, %esi
subw %si, 0x12(%rcx)
movl 0x10(%rcx), %ebp
subl %esi, %ebp
movw %bp, 0x10(%rcx)
movq %rax, 0x8(%rcx)
movw $0x0, 0x10(%rax)
movzbl 0x17(%r12), %ecx
movl %ecx, %edx
andl $0x1, %edx
leaq (%rax,%rdx,4), %rdx
addq $0x14, %rdx
cmpq %rdx, %r13
jne 0xc594
testb $0x4, %cl
jne 0xc2cd
movzwl 0xc(%rax), %edi
callq 0x13c50
shrl $0xa, %eax
andl $0x3c, %eax
cmpw %ax, %bp
jne 0xc5b0
movq 0x8(%r12), %r13
movq 0x18(%r12), %rax
movzwl 0x10(%r13), %ebp
movzwl 0xc(%rax), %edi
callq 0x13c50
shrl $0xa, %eax
andl $0x3c, %eax
movq %r13, %rdi
movl $0x6, %esi
movl %ebp, %edx
movl %eax, %ecx
movq %rbx, %r8
movq 0x18(%rsp), %r9
callq 0x14236
movb 0x16(%r12), %r13b
testb %r13b, %r13b
je 0xc31b
rolw $0x8, 0x14(%r12)
movb $0x0, 0x16(%r12)
notl %eax
movzwl %ax, %eax
movzwl 0x14(%r12), %ecx
addl %eax, %ecx
movl %ecx, %eax
shrl $0x10, %eax
addl %ecx, %eax
notl %eax
movq 0x18(%r12), %rcx
movw %ax, 0x10(%rcx)
cmpb $0x6, 0x2c(%rbx)
movq 0x8(%r12), %rdi
jne 0xc36c
movzbl 0x33(%rbx), %ecx
movzbl 0x32(%rbx), %r8d
movq 0x10(%rsp), %rax
movq %rax, (%rsp)
movq %rbx, %rsi
movq 0x18(%rsp), %rdx
movl $0x6, %r9d
callq 0x103a0
jmp 0xc391
movzbl 0x33(%rbx), %ecx
movzbl 0x32(%rbx), %r8d
movq 0x10(%rsp), %rax
movq %rax, (%rsp)
movq %rbx, %rsi
movq 0x18(%rsp), %rdx
movl $0x6, %r9d
callq 0xe5cf
movl %eax, %ebp
testb %r13b, %r13b
je 0xc3a5
rolw $0x8, 0x14(%r12)
movb $0x1, 0x16(%r12)
testb %bpl, %bpl
jne 0xc4f0
movw $0x0, 0x12(%r12)
movq (%r12), %rax
movq %rax, 0xa8(%rbx)
cmpl $0x2, 0x48(%rbx)
je 0xc3cb
andb $-0x4, 0x52(%rbx)
movq 0x18(%r12), %rax
movl 0x4(%rax), %edi
callq 0x13c57
movl %eax, %ebp
movzwl 0x10(%r12), %r13d
movq 0x18(%r12), %rax
movzwl 0xc(%rax), %edi
callq 0x13c50
andl $0x3, %eax
addl %ebp, %r13d
cmpw $0x1, %ax
sbbl $-0x1, %r13d
cmpl %r13d, 0x88(%rbx)
jns 0xc40c
movl %r13d, 0x88(%rbx)
movzwl 0x10(%r12), %ebp
movq 0x18(%r12), %rax
movzwl 0xc(%rax), %edi
callq 0x13c50
xorl %ecx, %ecx
testb $0x3, %al
setne %cl
orw %bp, %cx
je 0xc45e
movq $0x0, (%r12)
cmpq $0x0, (%r15)
je 0xc468
movq 0x18(%r12), %rax
movl 0x4(%rax), %edi
callq 0x13c57
movl %eax, %ebp
movq 0x18(%r14), %rax
movl 0x4(%rax), %edi
callq 0x13c57
cmpl %eax, %ebp
js 0xc470
movq %r12, (%r14)
jmp 0xc46b
movq %r12, %rdi
callq 0x828a
jmp 0xc4b6
movq %r12, (%r15)
movq %r12, %r14
jmp 0xc4b6
movq (%r15), %rax
movq %r15, %r13
testq %rax, %rax
je 0xc4aa
movq %r15, %r13
movq 0x18(%rax), %rax
movl 0x4(%rax), %edi
callq 0x13c57
movl %eax, %ebp
movq 0x18(%r12), %rax
movl 0x4(%rax), %edi
callq 0x13c57
cmpl %eax, %ebp
jns 0xc4aa
movq (%r13), %r13
movq (%r13), %rax
testq %rax, %rax
jne 0xc47e
movq (%r13), %rax
movq %rax, (%r12)
movq %r12, (%r13)
movq 0xa8(%rbx), %r12
testq %r12, %r12
jne 0xc10d
cmpq $0x0, 0xa8(%rbx)
jne 0xc4d9
movw $0x0, 0xa0(%rbx)
andb $0x7f, 0x52(%rbx)
xorl %ebp, %ebp
movl %ebp, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
orb $-0x80, 0x52(%rbx)
jmp 0xc4df
movq 0x10(%rsp), %rax
addq $0x8, %rax
testq %rax, %rax
je 0xc4df
movb 0x14(%rax), %cl
movb %cl, 0x14(%rbx)
cmpb $0x6, 0x14(%rax)
movl (%rax), %ecx
movl %ecx, (%rbx)
jne 0xc531
movl 0x4(%rax), %ecx
movl %ecx, 0x4(%rbx)
movl 0x8(%rax), %ecx
movl %ecx, 0x8(%rbx)
movl 0xc(%rax), %ecx
movl %ecx, 0xc(%rbx)
movb 0x10(%rax), %al
movb %al, 0x10(%rbx)
jmp 0xc054
xorl %eax, %eax
movq %rax, 0x9(%rbx)
movq %rax, 0x4(%rbx)
jmp 0xc054
leaq 0x8d85(%rip), %rdi      # 0x152cc
leaq 0xa67f(%rip), %rsi      # 0x16bcd
leaq 0xa242(%rip), %rcx      # 0x16797
movl $0x537, %edx            # imm = 0x537
jmp 0xc5ca
leaq 0x8d69(%rip), %rdi      # 0x152cc
leaq 0xa625(%rip), %rsi      # 0x16b8f
leaq 0xa226(%rip), %rcx      # 0x16797
movl $0x4e1, %edx            # imm = 0x4E1
jmp 0xc5ca
leaq 0x8d4d(%rip), %rdi      # 0x152cc
leaq 0xa621(%rip), %rsi      # 0x16ba7
leaq 0xa20a(%rip), %rcx      # 0x16797
movl $0x4e4, %edx            # imm = 0x4E4
jmp 0xc5ca
leaq 0x8d31(%rip), %rdi      # 0x152cc
leaq 0xa878(%rip), %rsi      # 0x16e1a
leaq 0xa1ee(%rip), %rcx      # 0x16797
movl $0x61c, %edx            # imm = 0x61C
jmp 0xc5ca
leaq 0x8d15(%rip), %rdi      # 0x152cc
leaq 0xa86f(%rip), %rsi      # 0x16e2d
leaq 0xa1d2(%rip), %rcx      # 0x16797
movl $0x628, %edx            # imm = 0x628
xorl %eax, %eax
callq 0x20d0
xorl %edi, %edi
callq 0x21b0
callq 0x2050