// File: /workspace/github_c_makefile_star2_O2/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 0xb582
movq %rdi, %r13
movq 0xa8(%rdi), %rbx
movb $-0x1, %bpl
testq %rbx, %rbx
je 0xb555
movl %esi, %r14d
testw %r14w, %r14w
je 0xb59e
movzwl 0x10(%rbx), %r15d
cmpw %r14w, %r15w
jbe 0xb553
cmpw %r14w, 0x6a(%r13)
jb 0xb5ba
movzbl 0x17(%rbx), %eax
movq %rax, 0x8(%rsp)
leal (,%rax,4), %r12d
andl $0x4, %r12d
subl %r14d, %r15d
leal (%r15,%r12), %eax
movzwl %ax, %esi
pushq $0x4a
popq %rdi
movl $0x280, %edx            # imm = 0x280
callq 0x4c47
testq %rax, %rax
je 0xb555
movq %r13, 0x10(%rsp)
movq 0x8(%rbx), %rdi
movzwl 0x10(%rdi), %ecx
addw %r14w, %cx
subw 0x10(%rbx), %cx
movq %rax, (%rsp)
movq 0x8(%rax), %rsi
addq %r12, %rsi
movzwl %cx, %ecx
movzwl %r15w, %r13d
movl %r13d, %edx
callq 0x54e3
cmpw %r13w, %ax
jne 0xb4d3
movzwl %r14w, %eax
movl %eax, 0x24(%rsp)
movq 0x8(%rsp), %r14
andb $-0x5, %r14b
movq (%rsp), %rax
addq 0x8(%rax), %r12
movq %r12, %rdi
movl %r13d, %esi
callq 0x133e3
movl %eax, 0x20(%rsp)
movq 0x18(%rbx), %rax
movzwl 0xc(%rax), %edi
callq 0x12ed0
movl %eax, %r13d
andl $0x8, %r13d
movl %eax, 0x1c(%rsp)
movl %eax, %r12d
andb $0x1, %r12b
leal (%r12,%r13), %eax
movl %eax, 0x8(%rsp)
movq 0x18(%rbx), %rax
movl 0x4(%rax), %edi
callq 0x12ed7
movl 0x24(%rsp), %ecx
addl %eax, %ecx
movzbl 0x8(%rsp), %edx
movzbl %r14b, %r8d
movq 0x10(%rsp), %rdi
movq (%rsp), %rsi
callq 0xb12f
testq %rax, %rax
je 0xb4d3
testw %r13w, %r13w
sete %dl
shlb $0x3, %dl
orb $0x37, %dl
andb 0x1c(%rsp), %dl
movzbl %dl, %ecx
andb $0x3e, %dl
testb %r12b, %r12b
movzbl %dl, %ebp
cmovel %ecx, %ebp
movl %r15d, %edx
andl $0x1, %edx
movl 0x20(%rsp), %esi
notl %esi
movl %esi, %ecx
rolw $0x8, %cx
testl %edx, %edx
cmovel %esi, %ecx
movw %cx, 0x14(%rax)
movb %dl, 0x16(%rax)
movq %rax, (%rsp)
orb $0x4, 0x17(%rax)
movq 0x8(%rbx), %rdi
callq 0x51c5
movq 0x10(%rsp), %r12
subw %ax, 0x9e(%r12)
movq 0x8(%rbx), %rdi
movl 0x10(%rdi), %eax
subl %r15d, %eax
movzwl %ax, %esi
callq 0x4f62
subw %r15w, 0x10(%rbx)
movq 0x18(%rbx), %rax
movzwl 0xc(%rax), %r14d
movzbl %bpl, %edi
callq 0x12ed0
orw %r14w, %ax
movq 0x18(%rbx), %rcx
movw %ax, 0xc(%rcx)
andw $0x0, 0x12(%rbx)
movq 0x8(%rbx), %rdi
callq 0x51c5
addw %ax, 0x9e(%r12)
andw $0x0, 0x14(%rbx)
leaq 0x14(%rbx), %r15
leaq 0x16(%rbx), %r12
movb $0x0, 0x16(%rbx)
movq 0x8(%rbx), %r13
movzwl 0x10(%r13), %ebp
subw 0x10(%rbx), %bp
testq %r13, %r13
je 0xb566
movzwl 0x12(%r13), %eax
cmpw %ax, %bp
jbe 0xb4de
subl %eax, %ebp
movq (%r13), %r13
jmp 0xb4b8
movq (%rsp), %rdi
callq 0x4e16
jmp 0xb555
movl $0xffff, %r14d          # imm = 0xFFFF
testq %r13, %r13
je 0xb523
movzwl %bp, %edi
addq 0x8(%r13), %rdi
movzwl 0x12(%r13), %esi
subl %ebp, %esi
andl %r14d, %esi
callq 0x133e3
notl %eax
movzwl 0x12(%r13), %esi
subl %ebp, %esi
andl %r14d, %eax
andl %r14d, %esi
movl %eax, %edi
movq %r15, %rdx
movq %r12, %rcx
callq 0xb108
movq (%r13), %r13
xorl %ebp, %ebp
jmp 0xb4e4
movq (%rsp), %r14
movq 0x8(%r14), %rdi
callq 0x51c5
movq 0x10(%rsp), %rcx
addw %ax, 0x9e(%rcx)
movq (%rbx), %rax
movq %rax, (%r14)
movq %r14, (%rbx)
cmpq $0x0, (%r14)
jne 0xb553
andw $0x0, 0xa0(%rcx)
xorl %ebp, %ebp
movl %ebp, %eax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x8d5f(%rip), %rdi      # 0x142cc
leaq 0xa4c8(%rip), %rsi      # 0x15a3c
leaq 0xa21c(%rip), %rcx      # 0x15797
movl $0x3bb, %edx            # imm = 0x3BB
jmp 0xb5d4
leaq 0x8d43(%rip), %rdi      # 0x142cc
leaq 0xa45b(%rip), %rsi      # 0x159eb
leaq 0xa200(%rip), %rcx      # 0x15797
movl $0x34b, %edx            # imm = 0x34B
jmp 0xb5d4
leaq 0x8d27(%rip), %rdi      # 0x142cc
leaq 0xa461(%rip), %rsi      # 0x15a0d
leaq 0xa1e4(%rip), %rcx      # 0x15797
movl $0x353, %edx            # imm = 0x353
jmp 0xb5d4
leaq 0x8d0b(%rip), %rdi      # 0x142cc
leaq 0xa467(%rip), %rsi      # 0x15a2f
leaq 0xa1c8(%rip), %rcx      # 0x15797
movl $0x35b, %edx            # imm = 0x35B
xorl %eax, %eax
callq 0x20d0
xorl %edi, %edi
callq 0x21b0
callq 0x2050