// File: /workspace/github_c_makefile_star2_O1/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 0x142cf(%rip), %ebp     # 0x1d94c
testb $0x4, %bpl
jne 0x96f4
testb $0x2, %bpl
je 0x9698
movl 0x48(%rbx), %eax
andl $-0x2, %eax
cmpl $0x2, %eax
jne 0x973f
testb $0x10, 0x52(%rbx)
jne 0x96aa
leaq 0x14277(%rip), %rax     # 0x1d91c
movl (%rax), %eax
movl %eax, 0x58(%rbx)
movw $0x0, 0xfe(%rbx)
movq %rbx, %rdi
callq 0x9ce0
movl 0x48(%rbx), %eax
addl $-0x2, %eax
cmpl $0x7, %eax
ja 0x9743
leaq 0xcd47(%rip), %rcx      # 0x16414
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %rbx, %rdi
callq 0x9e5d
testb $0x20, 0x14293(%rip)    # 0x1d978
je 0x9743
orb $0x2, 0x52(%rbx)
movl $0x7, 0x48(%rbx)
jmp 0x9743
movl 0x48(%rbx), %eax
cmpl $0x2, %eax
jne 0x970c
movl 0x14246(%rip), %ecx     # 0x1d948
cmpl 0x88(%rbx), %ecx
je 0x9719
jmp 0x9743
movl 0x14232(%rip), %ecx     # 0x1d944
movl 0x5c(%rbx), %edx
cmpl %edx, %ecx
jne 0x9731
testl %eax, %eax
je 0x9c0d
orb $0x8, 0x14250(%rip)     # 0x1d978
andb $-0x2, 0x52(%rbx)
movb $-0xe, %bpl
jmp 0x9745
js 0x9743
movzwl 0x60(%rbx), %eax
addl %eax, %edx
subl %edx, %ecx
testl %ecx, %ecx
jg 0x9743
orb $0x2, 0x52(%rbx)
xorl %ebp, %ebp
movl %ebp, %eax
addq $0x10, %rsp
popq %rbx
popq %r14
popq %rbp
retq
movq %rbx, %rdi
callq 0x9e5d
testb $0x20, 0x14219(%rip)    # 0x1d978
movb 0x141e7(%rip), %al      # 0x1d94c
jne 0x99ce
testb $0x10, %al
je 0x9743
movl 0x141d3(%rip), %eax     # 0x1d948
cmpl 0x88(%rbx), %eax
jne 0x9743
cmpq $0x0, 0xa8(%rbx)
jne 0x9743
movl $0x6, 0x48(%rbx)
jmp 0x9743
movl %ebp, %eax
notl %eax
testb $0x12, %al
jne 0x996b
movl 0x141a6(%rip), %eax     # 0x1d948
movl 0x7c(%rbx), %ecx
incl %ecx
cmpl %ecx, %eax
jne 0x996b
movl 0x1418f(%rip), %ecx     # 0x1d944
leal 0x1(%rcx), %edx
movl %edx, 0x5c(%rbx)
movl %edx, 0x64(%rbx)
movl %eax, 0x7c(%rbx)
movq 0x14160(%rip), %rax     # 0x1d928
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 0x9a54
movq %rbx, %rdi
movq %r14, %rsi
callq 0xfae4
jmp 0x9a5c
testb $0x10, %bpl
jne 0x99fe
testb $0x2, %bpl
je 0x9743
movl 0x5c(%rbx), %eax
decl %eax
cmpl %eax, 0x1411a(%rip)     # 0x1d944
jne 0x9743
movq %rbx, %rdi
callq 0xc863
jmp 0x9743
movq %rbx, %rdi
callq 0x9e5d
testb $0x10, 0x14100(%rip)    # 0x1d94c
je 0x9743
movl 0x140f0(%rip), %eax     # 0x1d948
cmpl 0x88(%rbx), %eax
jne 0x9743
cmpq $0x0, 0xa8(%rbx)
jne 0x9743
orb $0x10, 0x140ff(%rip)    # 0x1d978
jmp 0x9743
movq %rbx, %rdi
callq 0x9e5d
testb $0x20, 0x140eb(%rip)    # 0x1d978
je 0x9743
orb $0x2, 0x52(%rbx)
movq %rbx, %rdi
callq 0x7fc6
leaq 0x14062(%rip), %rax     # 0x1d908
movq (%rax), %rcx
cmpq %rbx, %rcx
je 0x98c6
testq %rcx, %rcx
je 0x98cd
movq %rcx, %rax
movq 0x38(%rcx), %rcx
cmpq %rbx, %rcx
jne 0x98ae
addq $0x38, %rax
movq %rbx, %rcx
movq 0x38(%rcx), %rcx
movq %rcx, (%rax)
movq $0x0, 0x38(%rbx)
leaq 0x1403d(%rip), %rax     # 0x1d919
movb $0x1, (%rax)
movl $0xa, 0x48(%rbx)
leaq 0x14023(%rip), %rax     # 0x1d910
movq (%rax), %rcx
movq %rcx, 0x38(%rbx)
movq %rbx, (%rax)
callq 0xce20
jmp 0x9743
movq %rbx, %rdi
callq 0x9e5d
testb $0x10, 0x1403c(%rip)    # 0x1d94c
je 0x9743
movl 0x1402c(%rip), %eax     # 0x1d948
cmpl 0x88(%rbx), %eax
jne 0x9743
cmpq $0x0, 0xa8(%rbx)
jne 0x9743
movq %rbx, %rdi
callq 0x7fc6
leaq 0x13fc3(%rip), %rax     # 0x1d908
movq (%rax), %rcx
cmpq %rbx, %rcx
je 0x98c6
testq %rcx, %rcx
je 0x98cd
movq %rcx, %rax
movq 0x38(%rcx), %rcx
cmpq %rbx, %rcx
jne 0x9951
jmp 0x98bf
testb $0x10, %bpl
je 0x9743
movzwl 0x13fd2(%rip), %edx     # 0x1d94e
addl 0x13fc2(%rip), %edx     # 0x1d944
movl 0x13fc0(%rip), %esi     # 0x1d948
movq 0x13f99(%rip), %rax     # 0x1d928
movzwl 0x2(%rax), %r9d
movzwl (%rax), %eax
movl %eax, (%rsp)
leaq 0x13dcf(%rip), %r8      # 0x1d770
leaq 0x3c(%r8), %rcx
addq $0x24, %r8
movq %rbx, %rdi
callq 0xc9d6
cmpb $0x5, 0x7a(%rbx)
ja 0x9743
movw $0x0, 0x68(%rbx)
movq %rbx, %rdi
callq 0xc80d
jmp 0x9743
testb $0x10, %al
je 0x99ee
movl 0x13f70(%rip), %eax     # 0x1d948
cmpl 0x88(%rbx), %eax
jne 0x99ee
cmpq $0x0, 0xa8(%rbx)
je 0x9b69
orb $0x2, 0x52(%rbx)
movl $0x8, 0x48(%rbx)
jmp 0x9743
movl 0x13f44(%rip), %esi     # 0x1d948
cmpl %esi, 0x7c(%rbx)
jns 0x9a19
movl %esi, %eax
subl 0x88(%rbx), %eax
testl %eax, %eax
jle 0x9b39
movzwl 0x13f2e(%rip), %edx     # 0x1d94e
addl 0x13f1e(%rip), %edx     # 0x1d944
movq 0x13efb(%rip), %rax     # 0x1d928
movzwl 0x2(%rax), %r9d
movzwl (%rax), %eax
movl %eax, (%rsp)
leaq 0x13d31(%rip), %r8      # 0x1d770
leaq 0x3c(%r8), %rcx
addq $0x24, %r8
movq %rbx, %rdi
callq 0xc9d6
jmp 0x9743
movq %r14, %rdi
callq 0xe3b4
movzwl %bp, %edi
movq %rax, %rsi
movq %r14, %rdx
callq 0x7f01
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 0x9c3a
decl %eax
movw %ax, 0x9e(%rbx)
movq 0xb0(%rbx), %rdi
testq %rdi, %rdi
je 0x9ad0
leaq 0xb0(%rbx), %rax
jmp 0x9ae7
movq 0xa8(%rbx), %rdi
testq %rdi, %rdi
je 0x9c56
leaq 0xa8(%rbx), %rax
movq (%rdi), %rcx
movq %rcx, (%rax)
callq 0x828a
cmpq $0x0, 0xb0(%rbx)
je 0x9b08
movw $0x0, 0x68(%rbx)
movb $0x0, 0x7a(%rbx)
jmp 0x9b0e
movw $0xffff, 0x68(%rbx)     # imm = 0xFFFF
movq 0xe0(%rbx), %rax
testq %rax, %rax
je 0x973f
movq 0x40(%rbx), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq *%rax
movb $-0xd, %bpl
cmpb $-0xd, %al
jne 0x973f
jmp 0x9745
movl $0x4, 0x48(%rbx)
movq 0xc8(%rbx), %rax
testq %rax, %rax
je 0x9ba2
movq 0x50(%rax), %rax
testq %rax, %rax
je 0x9c72
movq 0x40(%rbx), %rdi
movq %rbx, %rsi
xorl %edx, %edx
callq *%rax
movsbl %al, %eax
jmp 0x9ba7
orb $0x2, 0x52(%rbx)
movq %rbx, %rdi
callq 0x7fc6
leaq 0x13d8c(%rip), %rax     # 0x1d908
movq (%rax), %rcx
cmpq %rbx, %rcx
je 0x98c6
testq %rcx, %rcx
je 0x98cd
movq %rcx, %rax
movq 0x38(%rcx), %rcx
cmpq %rbx, %rcx
jne 0x9b88
jmp 0x98bf
movl $0xfffffffa, %eax       # imm = 0xFFFFFFFA
movb $-0xd, %bpl
cmpl $-0xd, %eax
je 0x9745
testl %eax, %eax
jne 0x9c00
movq %rbx, %rdi
callq 0x9e5d
movzwl 0x13db4(%rip), %eax     # 0x1d97a
testw %ax, %ax
je 0x9bd4
decl %eax
movw %ax, 0x13da6(%rip)      # 0x1d97a
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 0x96de
movq %rbx, %rdi
callq 0x759e
jmp 0x9745
leaq 0xb6b8(%rip), %rdi      # 0x152cc
leaq 0xc9b8(%rip), %rsi      # 0x165d3
leaq 0xc82a(%rip), %rcx      # 0x1644c
movl $0x348, %edx            # imm = 0x348
xorl %eax, %eax
callq 0x20d0
xorl %edi, %edi
callq 0x21b0
callq 0x2050
leaq 0xb68b(%rip), %rdi      # 0x152cc
leaq 0xc9ab(%rip), %rsi      # 0x165f3
leaq 0xc7fd(%rip), %rcx      # 0x1644c
movl $0x37c, %edx            # imm = 0x37C
jmp 0x9c27
leaq 0xb66f(%rip), %rdi      # 0x152cc
leaq 0xc9a5(%rip), %rsi      # 0x16609
leaq 0xc7e1(%rip), %rcx      # 0x1644c
movl $0x384, %edx            # imm = 0x384
jmp 0x9c27
leaq 0xb653(%rip), %rdi      # 0x152cc
leaq 0xc99c(%rip), %rsi      # 0x1661c
leaq 0xc7c5(%rip), %rcx      # 0x1644c
movl $0x3b8, %edx            # imm = 0x3B8
jmp 0x9c27