// File: /workspace/github_c_makefile_star2_O3/FH0[P]tun_direct/lwip-2.1.2/src/core/tcp_in.c
// Function: tcp_process
static err_t
tcp_process(struct tcp_pcb *pcb)
{
  struct tcp_seg *rseg;
  u8_t acceptable = 0;
  err_t err;

  err = ERR_OK;

  LWIP_ASSERT("tcp_process: invalid pcb", pcb != NULL);

  /* Process incoming RST segments. */
  if (flags & TCP_RST) {
    /* First, determine if the reset is acceptable. */
    if (pcb->state == SYN_SENT) {
      /* "In the SYN-SENT state (a RST received in response to an initial SYN),
          the RST is acceptable if the ACK field acknowledges the SYN." */
      if (ackno == pcb->snd_nxt) {
        acceptable = 1;
      }
    } else {
      /* "In all states except SYN-SENT, all reset (RST) segments are validated
          by checking their SEQ-fields." */
      if (seqno == pcb->rcv_nxt) {
        acceptable = 1;
      } else  if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
                                  pcb->rcv_nxt + pcb->rcv_wnd)) {
        /* If the sequence number is inside the window, we send a challenge ACK
           and wait for a re-send with matching sequence number.
           This follows RFC 5961 section 3.2 and addresses CVE-2004-0230
           (RST spoofing attack), which is present in RFC 793 RST handling. */
        tcp_ack_now(pcb);
      }
    }

    if (acceptable) {
      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
      recv_flags |= TF_RESET;
      tcp_clear_flags(pcb, TF_ACK_DELAY);
      return ERR_RST;
    } else {
      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
                                    seqno, pcb->rcv_nxt));
      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
                              seqno, pcb->rcv_nxt));
      return ERR_OK;
    }
  }

  if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
    /* Cope with new connection attempt after remote end crashed */
    tcp_ack_now(pcb);
    return ERR_OK;
  }

  if ((pcb->flags & TF_RXCLOSED) == 0) {
    /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
    pcb->tmr = tcp_ticks;
  }
  pcb->keep_cnt_sent = 0;
  pcb->persist_probe = 0;

  tcp_parseopt(pcb);

  /* Do different things depending on the TCP state. */
  switch (pcb->state) {
    case SYN_SENT:
      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
                                    pcb->snd_nxt, lwip_ntohl(pcb->unacked->tcphdr->seqno)));
      /* received SYN ACK with expected sequence number? */
      if ((flags & TCP_ACK) && (flags & TCP_SYN)
          && (ackno == pcb->lastack + 1)) {
        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 = pcb->snd_wnd;
        pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
        pcb->state = ESTABLISHED;

#if TCP_CALCULATE_EFF_SEND_MSS
        pcb->mss = tcp_eff_send_mss(pcb->mss, &pcb->local_ip, &pcb->remote_ip);
#endif /* TCP_CALCULATE_EFF_SEND_MSS */

        pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss);
        LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SENT): cwnd %"TCPWNDSIZE_F
                                     " ssthresh %"TCPWNDSIZE_F"\n",
                                     pcb->cwnd, pcb->ssthresh));
        LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
        --pcb->snd_queuelen;
        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"TCPWNDSIZE_F"\n", (tcpwnd_size_t)pcb->snd_queuelen));
        rseg = pcb->unacked;
        if (rseg == NULL) {
          /* might happen if tcp_output fails in tcp_rexmit_rto()
             in which case the segment is on the unsent list */
          rseg = pcb->unsent;
          LWIP_ASSERT("no segment to free", rseg != NULL);
          pcb->unsent = rseg->next;
        } else {
          pcb->unacked = rseg->next;
        }
        tcp_seg_free(rseg);

        /* If there's nothing left to acknowledge, stop the retransmit
           timer, otherwise reset it to start again */
        if (pcb->unacked == NULL) {
          pcb->rtime = -1;
        } else {
          pcb->rtime = 0;
          pcb->nrtx = 0;
        }

        /* Call the user specified function to call when successfully
         * connected. */
        TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
        if (err == ERR_ABRT) {
          return ERR_ABRT;
        }
        tcp_ack_now(pcb);
      }
      /* received ACK? possibly a half-open connection */
      else if (flags & TCP_ACK) {
        /* send a RST to bring the other side in a non-synchronized state. */
        tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(),
                ip_current_src_addr(), tcphdr->dest, tcphdr->src);
        /* Resend SYN immediately (don't wait for rto timeout) to establish
          connection faster, but do not send more SYNs than we otherwise would
          have, or we might get caught in a loop on loopback interfaces. */
        if (pcb->nrtx < TCP_SYNMAXRTX) {
          pcb->rtime = 0;
          tcp_rexmit_rto(pcb);
        }
      }
      break;
    case SYN_RCVD:
      if (flags & TCP_ACK) {
        /* expected ACK number? */
        if (TCP_SEQ_BETWEEN(ackno, pcb->lastack + 1, pcb->snd_nxt)) {
          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 || TCP_LISTEN_BACKLOG
          if (pcb->listener == NULL) {
            /* listen pcb might be closed by now */
            err = ERR_VAL;
          } else
#endif /* LWIP_CALLBACK_API || TCP_LISTEN_BACKLOG */
          {
#if LWIP_CALLBACK_API
            LWIP_ASSERT("pcb->listener->accept != NULL", pcb->listener->accept != NULL);
#endif
            tcp_backlog_accepted(pcb);
            /* Call the accept function. */
            TCP_EVENT_ACCEPT(pcb->listener, pcb, pcb->callback_arg, ERR_OK, err);
          }
          if (err != ERR_OK) {
            /* If the accept function returns with an error, we abort
             * the connection. */
            /* Already aborted? */
            if (err != ERR_ABRT) {
              tcp_abort(pcb);
            }
            return ERR_ABRT;
          }
          /* If there was any data contained within this ACK,
           * we'd better pass it on to the application as well. */
          tcp_receive(pcb);

          /* Prevent ACK for SYN to generate a sent event */
          if (recv_acked != 0) {
            recv_acked--;
          }

          pcb->cwnd = LWIP_TCP_CALC_INITIAL_CWND(pcb->mss);
          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_process (SYN_RCVD): cwnd %"TCPWNDSIZE_F
                                       " ssthresh %"TCPWNDSIZE_F"\n",
                                       pcb->cwnd, pcb->ssthresh));

          if (recv_flags & TF_GOT_FIN) {
            tcp_ack_now(pcb);
            pcb->state = CLOSE_WAIT;
          }
        } else {
          /* incorrect ACK number, send RST */
          tcp_rst(pcb, ackno, seqno + tcplen, ip_current_dest_addr(),
                  ip_current_src_addr(), tcphdr->dest, tcphdr->src);
        }
      } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
        /* Looks like another copy of the SYN - retransmit our SYN-ACK */
        tcp_rexmit(pcb);
      }
      break;
    case CLOSE_WAIT:
    /* FALLTHROUGH */
    case ESTABLISHED:
      tcp_receive(pcb);
      if (recv_flags & TF_GOT_FIN) { /* passive close */
        tcp_ack_now(pcb);
        pcb->state = CLOSE_WAIT;
      }
      break;
    case FIN_WAIT_1:
      tcp_receive(pcb);
      if (recv_flags & TF_GOT_FIN) {
        if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) &&
            pcb->unsent == NULL) {
          LWIP_DEBUGF(TCP_DEBUG,
                      ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
          tcp_ack_now(pcb);
          tcp_pcb_purge(pcb);
          TCP_RMV_ACTIVE(pcb);
          pcb->state = TIME_WAIT;
          TCP_REG(&tcp_tw_pcbs, pcb);
        } else {
          tcp_ack_now(pcb);
          pcb->state = CLOSING;
        }
      } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt) &&
                 pcb->unsent == NULL) {
        pcb->state = FIN_WAIT_2;
      }
      break;
    case FIN_WAIT_2:
      tcp_receive(pcb);
      if (recv_flags & TF_GOT_FIN) {
        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
        tcp_ack_now(pcb);
        tcp_pcb_purge(pcb);
        TCP_RMV_ACTIVE(pcb);
        pcb->state = TIME_WAIT;
        TCP_REG(&tcp_tw_pcbs, pcb);
      }
      break;
    case CLOSING:
      tcp_receive(pcb);
      if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) {
        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
        tcp_pcb_purge(pcb);
        TCP_RMV_ACTIVE(pcb);
        pcb->state = TIME_WAIT;
        TCP_REG(&tcp_tw_pcbs, pcb);
      }
      break;
    case LAST_ACK:
      tcp_receive(pcb);
      if ((flags & TCP_ACK) && ackno == pcb->snd_nxt && pcb->unsent == NULL) {
        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
        /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
        recv_flags |= TF_CLOSED;
      }
      break;
    default:
      break;
  }
  return ERR_OK;
}

// Assembly:
pushq %rbp
pushq %r14
pushq %rbx
subq $0x10, %rsp
movq %rdi, %rbx
movzbl 0x13431(%rip), %ebp     # 0x1c94c
testb $0x4, %bpl
jne 0x9592
testb $0x2, %bpl
je 0x9536
movl 0x48(%rbx), %eax
andl $-0x2, %eax
cmpl $0x2, %eax
jne 0x95dc
testb $0x10, 0x52(%rbx)
jne 0x9548
leaq 0x133d9(%rip), %rax     # 0x1c91c
movl (%rax), %eax
movl %eax, 0x58(%rbx)
movw $0x0, 0xfe(%rbx)
movq %rbx, %rdi
callq 0x9b63
movl 0x48(%rbx), %eax
addl $-0x2, %eax
cmpl $0x7, %eax
ja 0x95e0
leaq 0xbe91(%rip), %rcx      # 0x153fc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %rbx, %rdi
callq 0x9ce2
testb $0x20, 0x133f5(%rip)    # 0x1c978
je 0x95e0
orb $0x2, 0x52(%rbx)
movl $0x7, 0x48(%rbx)
jmp 0x95e0
movl 0x48(%rbx), %ecx
cmpl $0x2, %ecx
jne 0x95aa
movl 0x133a8(%rip), %eax     # 0x1c948
cmpl 0x88(%rbx), %eax
je 0x95bf
jmp 0x95e0
movl 0x13394(%rip), %eax     # 0x1c944
movl 0x5c(%rbx), %edx
cmpl %edx, %eax
jne 0x95ce
testl %ecx, %ecx
je 0x9a90
orb $0x8, 0x133b2(%rip)     # 0x1c978
andb $-0x2, 0x52(%rbx)
movb $-0xe, %al
jmp 0x95e2
js 0x95e0
movzwl 0x60(%rbx), %ecx
addl %ecx, %edx
subl %edx, %eax
testl %eax, %eax
jg 0x95e0
orb $0x2, 0x52(%rbx)
xorl %eax, %eax
addq $0x10, %rsp
popq %rbx
popq %r14
popq %rbp
retq
movq %rbx, %rdi
callq 0x9ce2
testb $0x20, 0x1337e(%rip)    # 0x1c978
movb 0x1334c(%rip), %al      # 0x1c94c
jne 0x9859
testb $0x10, %al
je 0x95e0
movl 0x13338(%rip), %eax     # 0x1c948
cmpl 0x88(%rbx), %eax
jne 0x95e0
cmpq $0x0, 0xa8(%rbx)
jne 0x95e0
movl $0x6, 0x48(%rbx)
jmp 0x95e0
movl %ebp, %eax
notl %eax
testb $0x12, %al
jne 0x97f6
movl 0x1330b(%rip), %eax     # 0x1c948
movl 0x7c(%rbx), %ecx
incl %ecx
cmpl %ecx, %eax
jne 0x97f6
movl 0x132f4(%rip), %ecx     # 0x1c944
leal 0x1(%rcx), %edx
movl %edx, 0x5c(%rbx)
movl %edx, 0x64(%rbx)
movl %eax, 0x7c(%rbx)
movq 0x132c5(%rip), %rax     # 0x1c928
movzwl 0xe(%rax), %eax
movw %ax, 0x98(%rbx)
movw %ax, 0x9a(%rbx)
decl %ecx
movl %ecx, 0x8c(%rbx)
movl $0x4, 0x48(%rbx)
movzwl 0x6a(%rbx), %ebp
leaq 0x18(%rbx), %r14
cmpb $0x6, 0x2c(%rbx)
jne 0x98df
movq %rbx, %rdi
movq %r14, %rsi
callq 0xf744
jmp 0x98e7
testb $0x10, %bpl
jne 0x9889
testb $0x2, %bpl
je 0x95e0
movl 0x5c(%rbx), %eax
decl %eax
cmpl %eax, 0x1327f(%rip)     # 0x1c944
jne 0x95e0
movq %rbx, %rdi
callq 0xc5d6
jmp 0x95e0
movq %rbx, %rdi
callq 0x9ce2
testb $0x10, 0x13265(%rip)    # 0x1c94c
je 0x95e0
movl 0x13255(%rip), %eax     # 0x1c948
cmpl 0x88(%rbx), %eax
jne 0x95e0
cmpq $0x0, 0xa8(%rbx)
jne 0x95e0
orb $0x10, 0x13264(%rip)    # 0x1c978
jmp 0x95e0
movq %rbx, %rdi
callq 0x9ce2
testb $0x20, 0x13250(%rip)    # 0x1c978
je 0x95e0
orb $0x2, 0x52(%rbx)
movq %rbx, %rdi
callq 0x7eb3
leaq 0x131c7(%rip), %rax     # 0x1c908
movq (%rax), %rcx
cmpq %rbx, %rcx
je 0x9761
testq %rcx, %rcx
je 0x9768
movq %rcx, %rax
movq 0x38(%rcx), %rcx
cmpq %rbx, %rcx
jne 0x9749
addq $0x38, %rax
movq %rbx, %rcx
movq 0x38(%rcx), %rcx
movq %rcx, (%rax)
leaq 0x131aa(%rip), %rax     # 0x1c919
movb $0x1, (%rax)
movl $0xa, 0x48(%rbx)
leaq 0x13190(%rip), %rax     # 0x1c910
movq (%rax), %rcx
movq %rcx, 0x38(%rbx)
movq %rbx, (%rax)
callq 0xcba0
jmp 0x95e0
movq %rbx, %rdi
callq 0x9ce2
testb $0x10, 0x131a9(%rip)    # 0x1c94c
je 0x95e0
movl 0x13199(%rip), %eax     # 0x1c948
cmpl 0x88(%rbx), %eax
jne 0x95e0
cmpq $0x0, 0xa8(%rbx)
jne 0x95e0
movq %rbx, %rdi
callq 0x7eb3
leaq 0x13130(%rip), %rax     # 0x1c908
movq (%rax), %rcx
cmpq %rbx, %rcx
je 0x9761
testq %rcx, %rcx
je 0x9768
movq %rcx, %rax
movq 0x38(%rcx), %rcx
cmpq %rbx, %rcx
jne 0x97e0
jmp 0x975a
testb $0x10, %bpl
je 0x95e0
movzwl 0x13147(%rip), %edx     # 0x1c94e
addl 0x13137(%rip), %edx     # 0x1c944
movl 0x13135(%rip), %esi     # 0x1c948
movq 0x1310e(%rip), %rax     # 0x1c928
movzwl 0x2(%rax), %r9d
movzwl (%rax), %eax
movl %eax, (%rsp)
leaq 0x12f44(%rip), %r8      # 0x1c770
leaq 0x3c(%r8), %rcx
addq $0x24, %r8
movq %rbx, %rdi
callq 0xc757
cmpb $0x5, 0x7a(%rbx)
ja 0x95e0
movw $0x0, 0x68(%rbx)
movq %rbx, %rdi
callq 0xc580
jmp 0x95e0
testb $0x10, %al
je 0x9879
movl 0x130e5(%rip), %eax     # 0x1c948
cmpl 0x88(%rbx), %eax
jne 0x9879
cmpq $0x0, 0xa8(%rbx)
je 0x9a0e
orb $0x2, 0x52(%rbx)
movl $0x8, 0x48(%rbx)
jmp 0x95e0
movl 0x130b9(%rip), %esi     # 0x1c948
cmpl %esi, 0x7c(%rbx)
jns 0x98a4
movl %esi, %eax
subl 0x88(%rbx), %eax
testl %eax, %eax
jle 0x99c1
movzwl 0x130a3(%rip), %edx     # 0x1c94e
addl 0x13093(%rip), %edx     # 0x1c944
movq 0x13070(%rip), %rax     # 0x1c928
movzwl 0x2(%rax), %r9d
movzwl (%rax), %eax
movl %eax, (%rsp)
leaq 0x12ea6(%rip), %r8      # 0x1c770
leaq 0x3c(%r8), %rcx
addq $0x24, %r8
movq %rbx, %rdi
callq 0xc757
jmp 0x95e0
movq %r14, %rdi
callq 0xe120
movzwl %bp, %edi
movq %rax, %rsi
movq %r14, %rdx
callq 0x7dee
movzwl %ax, %ecx
leal (,%rcx,4), %edx
leal (%rcx,%rcx), %esi
leal (%rax,%rax), %edi
cmpl $0x88f, %ecx            # imm = 0x88F
movl $0x111c, %ecx           # imm = 0x111C
cmovbl %ecx, %esi
cmovbl %ecx, %edi
leal (,%rax,4), %ecx
cmpl %esi, %edx
cmovbl %ecx, %edi
movw %ax, 0x6a(%rbx)
movw %di, 0x80(%rbx)
movzwl 0x9e(%rbx), %eax
testw %ax, %ax
je 0x9abd
decl %eax
movw %ax, 0x9e(%rbx)
leaq 0xb0(%rbx), %r14
movq 0xb0(%rbx), %rdi
movq %r14, %rax
testq %rdi, %rdi
jne 0x9973
movq 0xa8(%rbx), %rdi
testq %rdi, %rdi
je 0x9ad9
leaq 0xa8(%rbx), %rax
movq (%rdi), %rcx
movq %rcx, (%rax)
callq 0x817c
cmpq $0x0, (%r14)
je 0x998c
movb $0x0, 0x7a(%rbx)
xorl %eax, %eax
jmp 0x9990
movw $0xffff, %ax            # imm = 0xFFFF
movw %ax, 0x68(%rbx)
movq 0xe0(%rbx), %rax
testq %rax, %rax
je 0x95dc
movq 0x40(%rbx), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq *%rax
movl %eax, %ecx
movb $-0xd, %al
cmpb $-0xd, %cl
jne 0x95dc
jmp 0x95e2
movl $0x4, 0x48(%rbx)
movq 0xc8(%rbx), %rax
testq %rax, %rax
je 0x99ff
movq 0x50(%rax), %rax
testq %rax, %rax
je 0x9af5
movq 0x40(%rbx), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq *%rax
testb %al, %al
je 0x9a47
movzbl %al, %ecx
cmpl $0xf3, %ecx
je 0x95e2
movq %rbx, %rdi
callq 0x7490
movb $-0xd, %al
jmp 0x95e2
orb $0x2, 0x52(%rbx)
movq %rbx, %rdi
callq 0x7eb3
leaq 0x12ee7(%rip), %rax     # 0x1c908
movq (%rax), %rcx
cmpq %rbx, %rcx
je 0x9761
testq %rcx, %rcx
je 0x9768
movq %rcx, %rax
movq 0x38(%rcx), %rcx
cmpq %rbx, %rcx
jne 0x9a2d
jmp 0x975a
movq %rbx, %rdi
callq 0x9ce2
movzwl 0x12f24(%rip), %eax     # 0x1c97a
testw %ax, %ax
je 0x9a64
decl %eax
movw %ax, 0x12f16(%rip)      # 0x1c97a
movzwl 0x6a(%rbx), %eax
leal (%rax,%rax), %ecx
cmpl $0x88f, %eax            # imm = 0x88F
movl $0x111c, %edx           # imm = 0x111C
cmovael %ecx, %edx
leal (,%rax,4), %eax
cmpl %edx, %eax
cmovbl %eax, %edx
movw %dx, 0x80(%rbx)
jmp 0x957c
leaq 0xa835(%rip), %rdi      # 0x142cc
leaq 0xbb1d(%rip), %rsi      # 0x155bb
leaq 0xb98f(%rip), %rcx      # 0x15434
movl $0x348, %edx            # imm = 0x348
xorl %eax, %eax
callq 0x20d0
xorl %edi, %edi
callq 0x21b0
callq 0x2050
leaq 0xa808(%rip), %rdi      # 0x142cc
leaq 0xbb10(%rip), %rsi      # 0x155db
leaq 0xb962(%rip), %rcx      # 0x15434
movl $0x37c, %edx            # imm = 0x37C
jmp 0x9aaa
leaq 0xa7ec(%rip), %rdi      # 0x142cc
leaq 0xbb0a(%rip), %rsi      # 0x155f1
leaq 0xb946(%rip), %rcx      # 0x15434
movl $0x384, %edx            # imm = 0x384
jmp 0x9aaa
leaq 0xa7d0(%rip), %rdi      # 0x142cc
leaq 0xbb01(%rip), %rsi      # 0x15604
leaq 0xb92a(%rip), %rcx      # 0x15434
movl $0x3b8, %edx            # imm = 0x3B8
jmp 0x9aaa