// File: /workspace/github_c_makefile_star2_O0/FH0[P]tun_direct/lwip-2.1.2/src/core/tcp_out.c
// Function: tcp_zero_window_probe
err_t
tcp_zero_window_probe(struct tcp_pcb *pcb)
{
  err_t err;
  struct pbuf *p;
  struct tcp_hdr *tcphdr;
  struct tcp_seg *seg;
  u16_t len;
  u8_t is_fin;
  u32_t snd_nxt;
  u8_t optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(0, pcb);

  LWIP_ASSERT("tcp_zero_window_probe: invalid pcb", pcb != NULL);

  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to "));
  ip_addr_debug_print_val(TCP_DEBUG, pcb->remote_ip);
  LWIP_DEBUGF(TCP_DEBUG, ("\n"));

  LWIP_DEBUGF(TCP_DEBUG,
              ("tcp_zero_window_probe: tcp_ticks %"U32_F
               "   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
               tcp_ticks, pcb->tmr, (u16_t)pcb->keep_cnt_sent));

  /* Only consider unsent, persist timer should be off when there is data in-flight */
  seg = pcb->unsent;
  if (seg == NULL) {
    /* Not expected, persist timer should be off when the send buffer is empty */
    return ERR_OK;
  }

  /* increment probe count. NOTE: we record probe even if it fails
     to actually transmit due to an error. This ensures memory exhaustion/
     routing problem doesn't leave a zero-window pcb as an indefinite zombie.
     RTO mechanism has similar behavior, see pcb->nrtx */
  if (pcb->persist_probe < 0xFF) {
    ++pcb->persist_probe;
  }

  is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0);
  /* we want to send one seqno: either FIN or data (no options) */
  len = is_fin ? 0 : 1;

  p = tcp_output_alloc_header(pcb, optlen, len, seg->tcphdr->seqno);
  if (p == NULL) {
    LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
    return ERR_MEM;
  }
  tcphdr = (struct tcp_hdr *)p->payload;

  if (is_fin) {
    /* FIN segment, no data */
    TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN);
  } else {
    /* Data segment, copy in one byte from the head of the unacked queue */
    char *d = ((char *)p->payload + TCP_HLEN);
    /* Depending on whether the segment has already been sent (unacked) or not
       (unsent), seg->p->payload points to the IP header or TCP header.
       Ensure we copy the first TCP data byte: */
    pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len);
  }

  /* The byte may be acknowledged without the window being opened. */
  snd_nxt = lwip_ntohl(seg->tcphdr->seqno) + 1;
  if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) {
    pcb->snd_nxt = snd_nxt;
  }
  tcp_output_fill_options(pcb, p, 0, optlen);

  err = tcp_output_control_segment(pcb, p, &pcb->local_ip, &pcb->remote_ip);

  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
                          " ackno %"U32_F" err %d.\n",
                          pcb->snd_nxt - 1, pcb->rcv_nxt, (int)err));
  return err;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x50, %rsp
movq %rdi, -0x10(%rbp)
movb $0x0, -0x39(%rbp)
cmpq $0x0, -0x10(%rbp)
jne 0x16888
jmp 0x16859
leaq 0x10a6c(%rip), %rdi     # 0x272cc
leaq 0x126f2(%rip), %rsi     # 0x28f59
movl $0x84f, %edx            # imm = 0x84F
leaq 0x1215f(%rip), %rcx     # 0x289d2
movb $0x0, %al
callq 0x20d0
xorl %eax, %eax
movl %eax, %edi
callq 0x21b0
callq 0x2040
jmp 0x1688a
jmp 0x1688c
jmp 0x1688e
jmp 0x16890
movq -0x10(%rbp), %rax
movzbl 0x2c(%rax), %eax
cmpl $0x6, %eax
jne 0x168a3
jmp 0x1689f
jmp 0x168a1
jmp 0x168a9
jmp 0x168a5
jmp 0x168a7
jmp 0x168a9
jmp 0x168ab
jmp 0x168ad
jmp 0x168af
jmp 0x168b1
jmp 0x168b3
movq -0x10(%rbp), %rax
movq 0xa8(%rax), %rax
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
jne 0x168d2
movb $0x0, -0x1(%rbp)
jmp 0x16a7b
movq -0x10(%rbp), %rax
movzbl 0xfe(%rax), %eax
cmpl $0xff, %eax
jge 0x168f7
movq -0x10(%rbp), %rax
movb 0xfe(%rax), %cl
addb $0x1, %cl
movb %cl, 0xfe(%rax)
movq -0x30(%rbp), %rax
movq 0x18(%rax), %rax
movzwl 0xc(%rax), %edi
callq 0x251c0
movzwl %ax, %eax
andl $0x3f, %eax
movzbl %al, %ecx
andl $0x1, %ecx
xorl %eax, %eax
cmpl $0x0, %ecx
movb %al, -0x49(%rbp)
je 0x1692f
movq -0x30(%rbp), %rax
movzwl 0x10(%rax), %eax
cmpl $0x0, %eax
sete %al
movb %al, -0x49(%rbp)
movb -0x49(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
movb %al, -0x33(%rbp)
movzbl -0x33(%rbp), %edx
movl $0x1, %eax
xorl %ecx, %ecx
cmpl $0x0, %edx
cmovnel %ecx, %eax
movw %ax, -0x32(%rbp)
movq -0x10(%rbp), %rdi
movzbl -0x39(%rbp), %eax
movw %ax, %dx
movw -0x32(%rbp), %ax
movq -0x30(%rbp), %rcx
movq 0x18(%rcx), %rcx
movl 0x4(%rcx), %ecx
movzwl %dx, %esi
movzwl %ax, %edx
callq 0x16670
movq %rax, -0x20(%rbp)
cmpq $0x0, -0x20(%rbp)
jne 0x1698c
jmp 0x16981
jmp 0x16983
movb $-0x1, -0x1(%rbp)
jmp 0x16a7b
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x28(%rbp)
cmpb $0x0, -0x33(%rbp)
je 0x169d0
movq -0x28(%rbp), %rax
movzwl 0xc(%rax), %eax
andl $0xc0ff, %eax           # imm = 0xC0FF
movl %eax, -0x50(%rbp)
movl $0x11, %edi
callq 0x251c0
movw %ax, %cx
movl -0x50(%rbp), %eax
movzwl %cx, %ecx
orl %ecx, %eax
movw %ax, %cx
movq -0x28(%rbp), %rax
movw %cx, 0xc(%rax)
jmp 0x16a0f
movq -0x20(%rbp), %rax
movq 0x8(%rax), %rax
addq $0x14, %rax
movq %rax, -0x48(%rbp)
movq -0x30(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x48(%rbp), %rsi
movq -0x30(%rbp), %rax
movq 0x8(%rax), %rax
movzwl 0x10(%rax), %eax
movq -0x30(%rbp), %rcx
movzwl 0x10(%rcx), %ecx
subl %ecx, %eax
movl $0x1, %edx
movzwl %ax, %ecx
callq 0x8250
movq -0x30(%rbp), %rax
movq 0x18(%rax), %rax
movl 0x4(%rax), %edi
callq 0x251f0
addl $0x1, %eax
movl %eax, -0x38(%rbp)
movq -0x10(%rbp), %rax
movl 0x88(%rax), %eax
subl -0x38(%rbp), %eax
cmpl $0x0, %eax
jge 0x16a44
movl -0x38(%rbp), %ecx
movq -0x10(%rbp), %rax
movl %ecx, 0x88(%rax)
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
xorl %edx, %edx
movzbl -0x39(%rbp), %ecx
callq 0x163d0
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
movq -0x10(%rbp), %rdx
movq -0x10(%rbp), %rcx
addq $0x18, %rcx
callq 0x16500
movb %al, -0x11(%rbp)
jmp 0x16a75
movb -0x11(%rbp), %al
movb %al, -0x1(%rbp)
movb -0x1(%rbp), %al
addq $0x50, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)
nop