// File: /workspace/github_c_makefile_star2_O0/FH0[P]tun_direct/lwip-2.1.2/src/core/ipv6/ip6_frag.c
// Function: ip6_frag
err_t
ip6_frag(struct pbuf *p, struct netif *netif, const ip6_addr_t *dest)
{
  struct ip6_hdr *original_ip6hdr;
  struct ip6_hdr *ip6hdr;
  struct ip6_frag_hdr *frag_hdr;
  struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
  struct pbuf *newpbuf;
  u16_t newpbuflen = 0;
  u16_t left_to_copy;
#endif
  static u32_t identification;
  u16_t left, cop;
  const u16_t mtu = nd6_get_destination_mtu(dest, netif);
  const u16_t nfb = (u16_t)((mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK);
  u16_t fragment_offset = 0;
  u16_t last;
  u16_t poff = IP6_HLEN;

  identification++;

  original_ip6hdr = (struct ip6_hdr *)p->payload;

  /* @todo we assume there are no options in the unfragmentable part (IPv6 header). */
  LWIP_ASSERT("p->tot_len >= IP6_HLEN", p->tot_len >= IP6_HLEN);
  left = (u16_t)(p->tot_len - IP6_HLEN);

  while (left) {
    last = (left <= nfb);

    /* Fill this fragment */
    cop = last ? left : nfb;

#if LWIP_NETIF_TX_SINGLE_PBUF
    rambuf = pbuf_alloc(PBUF_IP, cop + IP6_FRAG_HLEN, PBUF_RAM);
    if (rambuf == NULL) {
      IP6_FRAG_STATS_INC(ip6_frag.memerr);
      return ERR_MEM;
    }
    LWIP_ASSERT("this needs a pbuf in one piece!",
      (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
    poff += pbuf_copy_partial(p, (u8_t*)rambuf->payload + IP6_FRAG_HLEN, cop, poff);
    /* make room for the IP header */
    if (pbuf_add_header(rambuf, IP6_HLEN)) {
      pbuf_free(rambuf);
      IP6_FRAG_STATS_INC(ip6_frag.memerr);
      return ERR_MEM;
    }
    /* fill in the IP header */
    SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
    ip6hdr = (struct ip6_hdr *)rambuf->payload;
    frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
#else
    /* When not using a static buffer, create a chain of pbufs.
     * The first will be a PBUF_RAM holding the link, IPv6, and Fragment header.
     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
     * but limited to the size of an mtu.
     */
    rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM);
    if (rambuf == NULL) {
      IP6_FRAG_STATS_INC(ip6_frag.memerr);
      return ERR_MEM;
    }
    LWIP_ASSERT("this needs a pbuf in one piece!",
                (p->len >= (IP6_HLEN)));
    SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
    ip6hdr = (struct ip6_hdr *)rambuf->payload;
    frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);

    /* Can just adjust p directly for needed offset. */
    p->payload = (u8_t *)p->payload + poff;
    p->len = (u16_t)(p->len - poff);
    p->tot_len = (u16_t)(p->tot_len - poff);

    left_to_copy = cop;
    while (left_to_copy) {
      struct pbuf_custom_ref *pcr;
      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;
      /* Is this pbuf already empty? */
      if (!newpbuflen) {
        p = p->next;
        continue;
      }
      pcr = ip6_frag_alloc_pbuf_custom_ref();
      if (pcr == NULL) {
        pbuf_free(rambuf);
        IP6_FRAG_STATS_INC(ip6_frag.memerr);
        return ERR_MEM;
      }
      /* Mirror this pbuf, although we might not need all of it. */
      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
      if (newpbuf == NULL) {
        ip6_frag_free_pbuf_custom_ref(pcr);
        pbuf_free(rambuf);
        IP6_FRAG_STATS_INC(ip6_frag.memerr);
        return ERR_MEM;
      }
      pbuf_ref(p);
      pcr->original = p;
      pcr->pc.custom_free_function = ip6_frag_free_pbuf_custom;

      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain
       * so that it is removed when pbuf_dechain is later called on rambuf.
       */
      pbuf_cat(rambuf, newpbuf);
      left_to_copy = (u16_t)(left_to_copy - newpbuflen);
      if (left_to_copy) {
        p = p->next;
      }
    }
    poff = newpbuflen;
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */

    /* Set headers */
    frag_hdr->_nexth = original_ip6hdr->_nexth;
    frag_hdr->reserved = 0;
    frag_hdr->_fragment_offset = lwip_htons((u16_t)((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG)));
    frag_hdr->_identification = lwip_htonl(identification);

    IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
    IP6H_PLEN_SET(ip6hdr, (u16_t)(cop + IP6_FRAG_HLEN));

    /* No need for separate header pbuf - we allowed room for it in rambuf
     * when allocated.
     */
    IP6_FRAG_STATS_INC(ip6_frag.xmit);
    netif->output_ip6(netif, rambuf, dest);

    /* Unfortunately we can't reuse rambuf - the hardware may still be
     * using the buffer. Instead we free it (and the ensuing chain) and
     * recreate it next time round the loop. If we're lucky the hardware
     * will have already sent the packet, the free will really free, and
     * there will be zero memory penalty.
     */

    pbuf_free(rambuf);
    left = (u16_t)(left - cop);
    fragment_offset = (u16_t)(fragment_offset + cop);
  }
  return ERR_OK;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movw $0x0, -0x4a(%rbp)
movq -0x20(%rbp), %rdi
movq -0x18(%rbp), %rsi
callq 0x24910
movw %ax, -0x52(%rbp)
movzwl -0x52(%rbp), %eax
subl $0x30, %eax
andl $0xfff8, %eax           # imm = 0xFFF8
movw %ax, -0x54(%rbp)
movw $0x0, -0x56(%rbp)
movw $0x28, -0x5a(%rbp)
movl 0x10567(%rip), %eax     # 0x2fa14
addl $0x1, %eax
movl %eax, 0x1055e(%rip)     # 0x2fa14
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rax
movzwl 0x10(%rax), %eax
cmpl $0x28, %eax
jge 0x1f500
jmp 0x1f4d1
leaq 0x7df4(%rip), %rdi      # 0x272cc
leaq 0xa68c(%rip), %rsi      # 0x29b6b
movl $0x2e8, %edx            # imm = 0x2E8
leaq 0xa5bd(%rip), %rcx      # 0x29aa8
movb $0x0, %al
callq 0x20d0
xorl %eax, %eax
movl %eax, %edi
callq 0x21b0
callq 0x2040
jmp 0x1f502
movq -0x10(%rbp), %rax
movzwl 0x10(%rax), %eax
subl $0x28, %eax
movw %ax, -0x4e(%rbp)
cmpw $0x0, -0x4e(%rbp)
je 0x1f812
movzwl -0x4e(%rbp), %eax
movzwl -0x54(%rbp), %ecx
cmpl %ecx, %eax
setle %al
andb $0x1, %al
movzbl %al, %eax
movw %ax, -0x58(%rbp)
movzwl -0x58(%rbp), %eax
cmpl $0x0, %eax
je 0x1f544
movzwl -0x4e(%rbp), %eax
movl %eax, -0x6c(%rbp)
jmp 0x1f54b
movzwl -0x54(%rbp), %eax
movl %eax, -0x6c(%rbp)
movl -0x6c(%rbp), %eax
movw %ax, -0x50(%rbp)
movl $0xe, %edi
movl $0x30, %esi
movl $0x280, %edx            # imm = 0x280
callq 0x6e20
movq %rax, -0x40(%rbp)
cmpq $0x0, -0x40(%rbp)
jne 0x1f57a
movb $-0x1, -0x1(%rbp)
jmp 0x1f816
jmp 0x1f57c
movq -0x10(%rbp), %rax
movzwl 0x12(%rax), %eax
cmpl $0x28, %eax
jge 0x1f5ba
jmp 0x1f58b
leaq 0x7d3a(%rip), %rdi      # 0x272cc
leaq 0xa297(%rip), %rsi      # 0x29830
movl $0x310, %edx            # imm = 0x310
leaq 0xa503(%rip), %rcx      # 0x29aa8
movb $0x0, %al
callq 0x20d0
xorl %eax, %eax
movl %eax, %edi
callq 0x21b0
callq 0x2040
jmp 0x1f5bc
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x28(%rbp), %rsi
movl $0x28, %edx
callq 0x2180
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x40(%rbp), %rax
movq 0x8(%rax), %rax
addq $0x28, %rax
movq %rax, -0x38(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rcx
movzwl -0x5a(%rbp), %eax
cltq
addq %rax, %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x10(%rbp), %rax
movzwl 0x12(%rax), %eax
movzwl -0x5a(%rbp), %ecx
subl %ecx, %eax
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x12(%rax)
movq -0x10(%rbp), %rax
movzwl 0x10(%rax), %eax
movzwl -0x5a(%rbp), %ecx
subl %ecx, %eax
movw %ax, %cx
movq -0x10(%rbp), %rax
movw %cx, 0x10(%rax)
movw -0x50(%rbp), %ax
movw %ax, -0x4c(%rbp)
cmpw $0x0, -0x4c(%rbp)
je 0x1f74d
movzwl -0x4c(%rbp), %eax
movq -0x10(%rbp), %rcx
movzwl 0x12(%rcx), %ecx
cmpl %ecx, %eax
jge 0x1f665
movzwl -0x4c(%rbp), %eax
movl %eax, -0x70(%rbp)
jmp 0x1f670
movq -0x10(%rbp), %rax
movzwl 0x12(%rax), %eax
movl %eax, -0x70(%rbp)
movl -0x70(%rbp), %eax
movw %ax, -0x4a(%rbp)
cmpw $0x0, -0x4a(%rbp)
jne 0x1f68b
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x10(%rbp)
jmp 0x1f641
callq 0x1f820
movq %rax, -0x68(%rbp)
cmpq $0x0, -0x68(%rbp)
jne 0x1f6ad
movq -0x40(%rbp), %rdi
callq 0x7260
movb $-0x1, -0x1(%rbp)
jmp 0x1f816
movw -0x4a(%rbp), %ax
movq -0x68(%rbp), %rcx
movq -0x10(%rbp), %rdx
movq 0x8(%rdx), %r8
xorl %edi, %edi
movl $0x41, %edx
movzwl %ax, %esi
movzwl -0x4a(%rbp), %r9d
callq 0x74e0
movq %rax, -0x48(%rbp)
cmpq $0x0, -0x48(%rbp)
jne 0x1f6f7
movq -0x68(%rbp), %rdi
callq 0x1f830
movq -0x40(%rbp), %rdi
callq 0x7260
movb $-0x1, -0x1(%rbp)
jmp 0x1f816
movq -0x10(%rbp), %rdi
callq 0x7c30
movq -0x10(%rbp), %rcx
movq -0x68(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x68(%rbp), %rax
leaq 0x179(%rip), %rcx       # 0x1f890
movq %rcx, 0x18(%rax)
movq -0x40(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x7cb0
movzwl -0x4c(%rbp), %eax
movzwl -0x4a(%rbp), %ecx
subl %ecx, %eax
movw %ax, -0x4c(%rbp)
cmpw $0x0, -0x4c(%rbp)
je 0x1f748
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x10(%rbp)
jmp 0x1f641
movw -0x4a(%rbp), %ax
movw %ax, -0x5a(%rbp)
movq -0x28(%rbp), %rax
movb 0x6(%rax), %cl
movq -0x38(%rbp), %rax
movb %cl, (%rax)
movq -0x38(%rbp), %rax
movb $0x0, 0x1(%rax)
movzwl -0x56(%rbp), %eax
andl $0xfff8, %eax           # imm = 0xFFF8
movzwl -0x58(%rbp), %esi
movl $0x1, %ecx
xorl %edx, %edx
cmpl $0x0, %esi
cmovnel %edx, %ecx
orl %ecx, %eax
movzwl %ax, %edi
callq 0x251c0
movw %ax, %cx
movq -0x38(%rbp), %rax
movw %cx, 0x2(%rax)
movl 0x10275(%rip), %edi     # 0x2fa14
callq 0x251f0
movl %eax, %ecx
movq -0x38(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x30(%rbp), %rax
movb $0x2c, 0x6(%rax)
movzwl -0x50(%rbp), %eax
addl $0x8, %eax
movzwl %ax, %edi
callq 0x251c0
movw %ax, %cx
movq -0x30(%rbp), %rax
movw %cx, 0x4(%rax)
movq -0x18(%rbp), %rax
movq 0xd0(%rax), %rax
movq -0x18(%rbp), %rdi
movq -0x40(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq *%rax
movq -0x40(%rbp), %rdi
callq 0x7260
movzwl -0x4e(%rbp), %eax
movzwl -0x50(%rbp), %ecx
subl %ecx, %eax
movw %ax, -0x4e(%rbp)
movzwl -0x56(%rbp), %eax
movzwl -0x50(%rbp), %ecx
addl %ecx, %eax
movw %ax, -0x56(%rbp)
jmp 0x1f511
movb $0x0, -0x1(%rbp)
movb -0x1(%rbp), %al
addq $0x70, %rsp
popq %rbp
retq
nop