// File: /workspace/github_c_makefile_star2_O1/FH0[P]tun_direct/lwip-2.1.2/src/core/tcp_out.c
// Function: tcp_split_unsent_seg
err_t
tcp_split_unsent_seg(struct tcp_pcb *pcb, u16_t split)
{
  struct tcp_seg *seg = NULL, *useg = NULL;
  struct pbuf *p = NULL;
  u8_t optlen;
  u8_t optflags;
  u8_t split_flags;
  u8_t remainder_flags;
  u16_t remainder;
  u16_t offset;
#if TCP_CHECKSUM_ON_COPY
  u16_t chksum = 0;
  u8_t chksum_swapped = 0;
  struct pbuf *q;
#endif /* TCP_CHECKSUM_ON_COPY */

  LWIP_ASSERT("tcp_split_unsent_seg: invalid pcb", pcb != NULL);

  useg = pcb->unsent;
  if (useg == NULL) {
    return ERR_MEM;
  }

  if (split == 0) {
    LWIP_ASSERT("Can't split segment into length 0", 0);
    return ERR_VAL;
  }

  if (useg->len <= split) {
    return ERR_OK;
  }

  LWIP_ASSERT("split <= mss", split <= pcb->mss);
  LWIP_ASSERT("useg->len > 0", useg->len > 0);

  /* We should check that we don't exceed TCP_SND_QUEUELEN but we need
   * to split this packet so we may actually exceed the max value by
   * one!
   */
  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: split_unsent_seg: %u\n", (unsigned int)pcb->snd_queuelen));

  optflags = useg->flags;
#if TCP_CHECKSUM_ON_COPY
  /* Remove since checksum is not stored until after tcp_create_segment() */
  optflags &= ~TF_SEG_DATA_CHECKSUMMED;
#endif /* TCP_CHECKSUM_ON_COPY */
  optlen = LWIP_TCP_OPT_LENGTH(optflags);
  remainder = useg->len - split;

  /* Create new pbuf for the remainder of the split */
  p = pbuf_alloc(PBUF_TRANSPORT, remainder + optlen, PBUF_RAM);
  if (p == NULL) {
    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                ("tcp_split_unsent_seg: could not allocate memory for pbuf remainder %u\n", remainder));
    goto memerr;
  }

  /* Offset into the original pbuf is past TCP/IP headers, options, and split amount */
  offset = useg->p->tot_len - useg->len + split;
  /* Copy remainder into new pbuf, headers and options will not be filled out */
  if (pbuf_copy_partial(useg->p, (u8_t *)p->payload + optlen, remainder, offset ) != remainder) {
    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                ("tcp_split_unsent_seg: could not copy pbuf remainder %u\n", remainder));
    goto memerr;
  }
#if TCP_CHECKSUM_ON_COPY
  /* calculate the checksum on remainder data */
  tcp_seg_add_chksum(~inet_chksum((const u8_t *)p->payload + optlen, remainder), remainder,
                     &chksum, &chksum_swapped);
#endif /* TCP_CHECKSUM_ON_COPY */

  /* Options are created when calling tcp_output() */

  /* Migrate flags from original segment */
  split_flags = TCPH_FLAGS(useg->tcphdr);
  remainder_flags = 0; /* ACK added in tcp_output() */

  if (split_flags & TCP_PSH) {
    split_flags &= ~TCP_PSH;
    remainder_flags |= TCP_PSH;
  }
  if (split_flags & TCP_FIN) {
    split_flags &= ~TCP_FIN;
    remainder_flags |= TCP_FIN;
  }
  /* SYN should be left on split, RST should not be present with data */

  seg = tcp_create_segment(pcb, p, remainder_flags, lwip_ntohl(useg->tcphdr->seqno) + split, optflags);
  if (seg == NULL) {
    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
                ("tcp_split_unsent_seg: could not create new TCP segment\n"));
    goto memerr;
  }

#if TCP_CHECKSUM_ON_COPY
  seg->chksum = chksum;
  seg->chksum_swapped = chksum_swapped;
  seg->flags |= TF_SEG_DATA_CHECKSUMMED;
#endif /* TCP_CHECKSUM_ON_COPY */

  /* Remove this segment from the queue since trimming it may free pbufs */
  pcb->snd_queuelen -= pbuf_clen(useg->p);

  /* Trim the original pbuf into our split size.  At this point our remainder segment must be setup
  successfully because we are modifying the original segment */
  pbuf_realloc(useg->p, useg->p->tot_len - remainder);
  useg->len -= remainder;
  TCPH_SET_FLAG(useg->tcphdr, split_flags);
#if TCP_OVERSIZE_DBGCHECK
  /* By trimming, realloc may have actually shrunk the pbuf, so clear oversize_left */
  useg->oversize_left = 0;
#endif /* TCP_OVERSIZE_DBGCHECK */

  /* Add back to the queue with new trimmed pbuf */
  pcb->snd_queuelen += pbuf_clen(useg->p);

#if TCP_CHECKSUM_ON_COPY
  /* The checksum on the split segment is now incorrect. We need to re-run it over the split */
  useg->chksum = 0;
  useg->chksum_swapped = 0;
  q = useg->p;
  offset = q->tot_len - useg->len; /* Offset due to exposed headers */

  /* Advance to the pbuf where the offset ends */
  while (q != NULL && offset > q->len) {
    offset -= q->len;
    q = q->next;
  }
  LWIP_ASSERT("Found start of payload pbuf", q != NULL);
  /* Checksum the first payload pbuf accounting for offset, then other pbufs are all payload */
  for (; q != NULL; offset = 0, q = q->next) {
    tcp_seg_add_chksum(~inet_chksum((const u8_t *)q->payload + offset, q->len - offset), q->len - offset,
                       &useg->chksum, &useg->chksum_swapped);
  }
#endif /* TCP_CHECKSUM_ON_COPY */

  /* Update number of segments on the queues. Note that length now may
   * exceed TCP_SND_QUEUELEN! We don't have to touch pcb->snd_buf
   * because the total amount of data is constant when packet is split */
  pcb->snd_queuelen += pbuf_clen(seg->p);

  /* Finally insert remainder into queue after split (which stays head) */
  seg->next = useg->next;
  useg->next = seg;

#if TCP_OVERSIZE
  /* If remainder is last segment on the unsent, ensure we clear the oversize amount
   * because the remainder is always sized to the exact remaining amount */
  if (seg->next == NULL) {
    pcb->unsent_oversize = 0;
  }
#endif /* TCP_OVERSIZE */

  return ERR_OK;
memerr:
  TCP_STATS_INC(tcp.memerr);

  LWIP_ASSERT("seg == NULL", seg == NULL);
  if (p != NULL) {
    pbuf_free(p);
  }

  return ERR_MEM;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
testq %rdi, %rdi
je 0xbd1c
movq %rdi, %r13
movq 0xa8(%rdi), %r15
movb $-0x1, %bpl
testq %r15, %r15
je 0xbd0b
movl %esi, %r14d
testw %r14w, %r14w
je 0xbd38
movzwl 0x10(%r15), %ebx
cmpw %r14w, %bx
jbe 0xbd09
cmpw %r14w, 0x6a(%r13)
jb 0xbd54
movzbl 0x17(%r15), %eax
movq %rax, (%rsp)
leal (,%rax,4), %r12d
andl $0x4, %r12d
subl %r14d, %ebx
leal (%rbx,%r12), %eax
movzwl %ax, %esi
movl $0x4a, %edi
movl $0x280, %edx            # imm = 0x280
callq 0x4e57
testq %rax, %rax
je 0xbd0b
movq %r13, 0x20(%rsp)
movq 0x8(%r15), %rdi
movzwl 0x10(%rdi), %ecx
addw %r14w, %cx
subw 0x10(%r15), %cx
movq %rax, 0x8(%rsp)
movq 0x8(%rax), %rsi
addq %r12, %rsi
movzwl %cx, %ecx
movzwl %bx, %r13d
movl %r13d, %edx
callq 0x575a
cmpw %r13w, %ax
jne 0xbc79
movzwl %r14w, %eax
movl %eax, 0x1c(%rsp)
movq (%rsp), %r14
andb $-0x5, %r14b
movq 0x8(%rsp), %rax
addq 0x8(%rax), %r12
movq %r12, %rdi
movl %r13d, %esi
callq 0x142a0
movl %eax, 0x18(%rsp)
movq 0x18(%r15), %rax
movzwl 0xc(%rax), %edi
callq 0x13c50
movl %eax, %r13d
andl $0x8, %r13d
movl %eax, 0x14(%rsp)
movl %eax, %r12d
andb $0x1, %r12b
leal (%r12,%r13), %eax
movl %eax, (%rsp)
movq 0x18(%r15), %rax
movl 0x4(%rax), %edi
callq 0x13c57
movl 0x1c(%rsp), %ecx
addl %eax, %ecx
movzbl (%rsp), %edx
movzbl %r14b, %r8d
movq 0x20(%rsp), %rdi
movq 0x8(%rsp), %rsi
callq 0xb8b3
testq %rax, %rax
je 0xbc79
movq %rax, %r14
testw %r13w, %r13w
sete %al
shlb $0x3, %al
orb $0x37, %al
andb 0x14(%rsp), %al
movzbl %al, %ecx
andb $0x3e, %al
testb %r12b, %r12b
movzbl %al, %ebp
cmovel %ecx, %ebp
movl %ebx, %eax
andl $0x1, %eax
movl 0x18(%rsp), %edx
notl %edx
movl %edx, %ecx
rolw $0x8, %cx
testl %eax, %eax
cmovel %edx, %ecx
movw %cx, 0x14(%r14)
movb %al, 0x16(%r14)
orb $0x4, 0x17(%r14)
movq 0x8(%r15), %rdi
callq 0x5425
movq 0x20(%rsp), %r13
subw %ax, 0x9e(%r13)
movq 0x8(%r15), %rdi
movl 0x10(%rdi), %eax
subl %ebx, %eax
movzwl %ax, %esi
callq 0x51ac
subw %bx, 0x10(%r15)
movq 0x18(%r15), %rax
movzwl 0xc(%rax), %ebx
movzbl %bpl, %edi
callq 0x13c50
orw %bx, %ax
movq 0x18(%r15), %rcx
movw %ax, 0xc(%rcx)
xorl %ebx, %ebx
movw %bx, 0x12(%r15)
movq 0x8(%r15), %rdi
callq 0x5425
addw %ax, 0x9e(%r13)
movw %bx, 0x14(%r15)
movb $0x0, 0x16(%r15)
movq 0x8(%r15), %rbx
testq %rbx, %rbx
je 0xbc5a
movzwl 0x10(%rbx), %r12d
subw 0x10(%r15), %r12w
movzwl 0x12(%rbx), %eax
cmpw %ax, %r12w
jbe 0xbc88
subl %eax, %r12d
movq (%rbx), %rbx
testq %rbx, %rbx
jne 0xbc45
leaq 0x966b(%rip), %rdi      # 0x152cc
leaq 0xadf2(%rip), %rsi      # 0x16a5a
leaq 0xab28(%rip), %rcx      # 0x16797
movl $0x3bb, %edx            # imm = 0x3BB
jmp 0xbd6e
movq 0x8(%rsp), %rdi
callq 0x5069
jmp 0xbd0b
movl $0xffff, %ebp           # imm = 0xFFFF
movzwl %r12w, %edi
addq 0x8(%rbx), %rdi
movzwl 0x12(%rbx), %esi
subl %r12d, %esi
andl %ebp, %esi
callq 0x142a0
notl %eax
movzwl 0x12(%rbx), %ecx
subl %r12d, %ecx
andl %ebp, %eax
movzwl 0x14(%r15), %edx
addl %eax, %edx
movl %edx, %eax
shrl $0x10, %eax
addl %edx, %eax
testb $0x1, %cl
je 0xbccf
movb $0x1, %cl
subb 0x16(%r15), %cl
movb %cl, 0x16(%r15)
rolw $0x8, %ax
movw %ax, 0x14(%r15)
movq (%rbx), %rbx
xorl %r12d, %r12d
testq %rbx, %rbx
jne 0xbc8d
movq 0x8(%r14), %rdi
callq 0x5425
addw %ax, 0x9e(%r13)
movq (%r15), %rax
movq %rax, (%r14)
movq %r14, (%r15)
cmpq $0x0, (%r14)
jne 0xbd09
movw $0x0, 0xa0(%r13)
xorl %ebp, %ebp
movl %ebp, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x95a9(%rip), %rdi      # 0x152cc
leaq 0xacdf(%rip), %rsi      # 0x16a09
leaq 0xaa66(%rip), %rcx      # 0x16797
movl $0x34b, %edx            # imm = 0x34B
jmp 0xbd6e
leaq 0x958d(%rip), %rdi      # 0x152cc
leaq 0xace5(%rip), %rsi      # 0x16a2b
leaq 0xaa4a(%rip), %rcx      # 0x16797
movl $0x353, %edx            # imm = 0x353
jmp 0xbd6e
leaq 0x9571(%rip), %rdi      # 0x152cc
leaq 0xaceb(%rip), %rsi      # 0x16a4d
leaq 0xaa2e(%rip), %rcx      # 0x16797
movl $0x35b, %edx            # imm = 0x35B
xorl %eax, %eax
callq 0x20d0
xorl %edi, %edi
callq 0x21b0
callq 0x2050