// File: /workspace/github_c_makefile_star2_O0/FH0[P]tun_direct/lwip-2.1.2/src/core/ipv4/ip4_frag.c
// Function: ip4_frag
err_t
ip4_frag(struct pbuf *p, struct netif *netif, const ip4_addr_t *dest)
{
  struct pbuf *rambuf;
#if !LWIP_NETIF_TX_SINGLE_PBUF
  struct pbuf *newpbuf;
  u16_t newpbuflen = 0;
  u16_t left_to_copy;
#endif
  struct ip_hdr *original_iphdr;
  struct ip_hdr *iphdr;
  const u16_t nfb = (u16_t)((netif->mtu - IP_HLEN) / 8);
  u16_t left, fragsize;
  u16_t ofo;
  int last;
  u16_t poff = IP_HLEN;
  u16_t tmp;
  int mf_set;

  original_iphdr = (struct ip_hdr *)p->payload;
  iphdr = original_iphdr;
  if (IPH_HL_BYTES(iphdr) != IP_HLEN) {
    /* ip4_frag() does not support IP options */
    return ERR_VAL;
  }
  LWIP_ERROR("ip4_frag(): pbuf too short", p->len >= IP_HLEN, return ERR_VAL);

  /* Save original offset */
  tmp = lwip_ntohs(IPH_OFFSET(iphdr));
  ofo = tmp & IP_OFFMASK;
  /* already fragmented? if so, the last fragment we create must have MF, too */
  mf_set = tmp & IP_MF;

  left = (u16_t)(p->tot_len - IP_HLEN);

  while (left) {
    /* Fill this fragment */
    fragsize = LWIP_MIN(left, (u16_t)(nfb * 8));

#if LWIP_NETIF_TX_SINGLE_PBUF
    rambuf = pbuf_alloc(PBUF_IP, fragsize, PBUF_RAM);
    if (rambuf == NULL) {
      goto memerr;
    }
    LWIP_ASSERT("this needs a pbuf in one piece!",
                (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL));
    poff += pbuf_copy_partial(p, rambuf->payload, fragsize, poff);
    /* make room for the IP header */
    if (pbuf_add_header(rambuf, IP_HLEN)) {
      pbuf_free(rambuf);
      goto memerr;
    }
    /* fill in the IP header */
    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
    iphdr = (struct ip_hdr *)rambuf->payload;
#else /* LWIP_NETIF_TX_SINGLE_PBUF */
    /* When not using a static buffer, create a chain of pbufs.
     * The first will be a PBUF_RAM holding the link and IP 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, IP_HLEN, PBUF_RAM);
    if (rambuf == NULL) {
      goto memerr;
    }
    LWIP_ASSERT("this needs a pbuf in one piece!",
                (rambuf->len >= (IP_HLEN)));
    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);
    iphdr = (struct ip_hdr *)rambuf->payload;

    left_to_copy = fragsize;
    while (left_to_copy) {
      struct pbuf_custom_ref *pcr;
      u16_t plen = (u16_t)(p->len - poff);
      LWIP_ASSERT("p->len >= poff", p->len >= poff);
      newpbuflen = LWIP_MIN(left_to_copy, plen);
      /* Is this pbuf already empty? */
      if (!newpbuflen) {
        poff = 0;
        p = p->next;
        continue;
      }
      pcr = ip_frag_alloc_pbuf_custom_ref();
      if (pcr == NULL) {
        pbuf_free(rambuf);
        goto memerr;
      }
      /* Mirror this pbuf, although we might not need all of it. */
      newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc,
                                    (u8_t *)p->payload + poff, newpbuflen);
      if (newpbuf == NULL) {
        ip_frag_free_pbuf_custom_ref(pcr);
        pbuf_free(rambuf);
        goto memerr;
      }
      pbuf_ref(p);
      pcr->original = p;
      pcr->pc.custom_free_function = ipfrag_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) {
        poff = 0;
        p = p->next;
      }
    }
    poff = (u16_t)(poff + newpbuflen);
#endif /* LWIP_NETIF_TX_SINGLE_PBUF */

    /* Correct header */
    last = (left <= netif->mtu - IP_HLEN);

    /* Set new offset and MF flag */
    tmp = (IP_OFFMASK & (ofo));
    if (!last || mf_set) {
      /* the last fragment has MF set if the input frame had it */
      tmp = tmp | IP_MF;
    }
    IPH_OFFSET_SET(iphdr, lwip_htons(tmp));
    IPH_LEN_SET(iphdr, lwip_htons((u16_t)(fragsize + IP_HLEN)));
    IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
    IF__NETIF_CHECKSUM_ENABLED(netif, NETIF_CHECKSUM_GEN_IP) {
      IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));
    }
#endif /* CHECKSUM_GEN_IP */

    /* No need for separate header pbuf - we allowed room for it in rambuf
     * when allocated.
     */
    netif->output(netif, rambuf, dest);
    IPFRAG_STATS_INC(ip_frag.xmit);

    /* 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 - fragsize);
    ofo = (u16_t)(ofo + nfb);
  }
  MIB2_STATS_INC(mib2.ipfragoks);
  return ERR_OK;
memerr:
  MIB2_STATS_INC(mib2.ipfragfails);
  return ERR_MEM;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x80, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movw $0x0, -0x32(%rbp)
movq -0x18(%rbp), %rax
movzwl 0xe0(%rax), %eax
subl $0x14, %eax
movl $0x8, %ecx
cltd
idivl %ecx
movw %ax, -0x4a(%rbp)
movw $0x14, -0x56(%rbp)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movzbl (%rax), %eax
andl $0xf, %eax
shll $0x2, %eax
movzbl %al, %eax
cmpl $0x14, %eax
je 0x1b78f
movb $-0x6, -0x1(%rbp)
jmp 0x1bb39
jmp 0x1b791
movq -0x10(%rbp), %rax
movzwl 0x12(%rax), %eax
cmpl $0x14, %eax
jge 0x1b7cf
jmp 0x1b7a0
leaq 0xbb25(%rip), %rdi      # 0x272cc
leaq 0xe067(%rip), %rsi      # 0x29815
movl $0x2fc, %edx            # imm = 0x2FC
leaq 0xe00b(%rip), %rcx      # 0x297c5
movb $0x0, %al
callq 0x20d0
xorl %eax, %eax
movl %eax, %edi
callq 0x21b0
callq 0x2040
jmp 0x1b7d1
movq -0x48(%rbp), %rax
movzwl 0x6(%rax), %edi
callq 0x251c0
movw %ax, -0x58(%rbp)
movzwl -0x58(%rbp), %eax
andl $0x1fff, %eax           # imm = 0x1FFF
movw %ax, -0x50(%rbp)
movzwl -0x58(%rbp), %eax
andl $0x2000, %eax           # imm = 0x2000
movl %eax, -0x5c(%rbp)
movq -0x10(%rbp), %rax
movzwl 0x10(%rax), %eax
subl $0x14, %eax
movw %ax, -0x4c(%rbp)
cmpw $0x0, -0x4c(%rbp)
je 0x1bb2f
movzwl -0x4c(%rbp), %eax
movzwl -0x4a(%rbp), %ecx
shll $0x3, %ecx
movzwl %cx, %ecx
cmpl %ecx, %eax
jge 0x1b830
movzwl -0x4c(%rbp), %eax
movl %eax, -0x70(%rbp)
jmp 0x1b83d
movzwl -0x4a(%rbp), %eax
shll $0x3, %eax
movzwl %ax, %eax
movl %eax, -0x70(%rbp)
movl -0x70(%rbp), %eax
movw %ax, -0x4e(%rbp)
movl $0xe, %edi
movl $0x14, %esi
movl $0x280, %edx            # imm = 0x280
callq 0x6e20
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
jne 0x1b868
jmp 0x1bb35
jmp 0x1b86a
movq -0x28(%rbp), %rax
movzwl 0x12(%rax), %eax
cmpl $0x14, %eax
jge 0x1b8a8
jmp 0x1b879
leaq 0xba4c(%rip), %rdi      # 0x272cc
leaq 0xdfa9(%rip), %rsi      # 0x29830
movl $0x325, %edx            # imm = 0x325
leaq 0xdf32(%rip), %rcx      # 0x297c5
movb $0x0, %al
callq 0x20d0
xorl %eax, %eax
movl %eax, %edi
callq 0x21b0
callq 0x2040
jmp 0x1b8aa
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rax
movq -0x40(%rbp), %rcx
movq (%rcx), %rdx
movq %rdx, (%rax)
movq 0x8(%rcx), %rdx
movq %rdx, 0x8(%rax)
movl 0x10(%rcx), %ecx
movl %ecx, 0x10(%rax)
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x48(%rbp)
movw -0x4e(%rbp), %ax
movw %ax, -0x34(%rbp)
cmpw $0x0, -0x34(%rbp)
je 0x1ba48
movq -0x10(%rbp), %rax
movzwl 0x12(%rax), %eax
movzwl -0x56(%rbp), %ecx
subl %ecx, %eax
movw %ax, -0x6a(%rbp)
movq -0x10(%rbp), %rax
movzwl 0x12(%rax), %eax
movzwl -0x56(%rbp), %ecx
cmpl %ecx, %eax
jge 0x1b93c
jmp 0x1b90d
leaq 0xb9b8(%rip), %rdi      # 0x272cc
leaq 0xdf35(%rip), %rsi      # 0x29850
movl $0x32d, %edx            # imm = 0x32D
leaq 0xde9e(%rip), %rcx      # 0x297c5
movb $0x0, %al
callq 0x20d0
xorl %eax, %eax
movl %eax, %edi
callq 0x21b0
callq 0x2040
jmp 0x1b93e
movzwl -0x34(%rbp), %eax
movzwl -0x6a(%rbp), %ecx
cmpl %ecx, %eax
jge 0x1b953
movzwl -0x34(%rbp), %eax
movl %eax, -0x74(%rbp)
jmp 0x1b95a
movzwl -0x6a(%rbp), %eax
movl %eax, -0x74(%rbp)
movl -0x74(%rbp), %eax
movw %ax, -0x32(%rbp)
cmpw $0x0, -0x32(%rbp)
jne 0x1b97e
movw $0x0, -0x56(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x10(%rbp)
jmp 0x1b8de
callq 0x1bb50
movq %rax, -0x68(%rbp)
cmpq $0x0, -0x68(%rbp)
jne 0x1b99c
movq -0x28(%rbp), %rdi
callq 0x7260
jmp 0x1bb35
movw -0x32(%rbp), %ax
movq -0x68(%rbp), %rcx
movq -0x10(%rbp), %rdx
movq 0x8(%rdx), %r8
movzwl -0x56(%rbp), %edx
movslq %edx, %rdx
addq %rdx, %r8
xorl %edi, %edi
movl $0x41, %edx
movzwl %ax, %esi
movzwl -0x32(%rbp), %r9d
callq 0x74e0
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x30(%rbp)
jne 0x1b9ec
movq -0x68(%rbp), %rdi
callq 0x1bb60
movq -0x28(%rbp), %rdi
callq 0x7260
jmp 0x1bb35
movq -0x10(%rbp), %rdi
callq 0x7c30
movq -0x10(%rbp), %rcx
movq -0x68(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x68(%rbp), %rax
leaq 0x1b4(%rip), %rcx       # 0x1bbc0
movq %rcx, 0x18(%rax)
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x7cb0
movzwl -0x34(%rbp), %eax
movzwl -0x32(%rbp), %ecx
subl %ecx, %eax
movw %ax, -0x34(%rbp)
cmpw $0x0, -0x34(%rbp)
je 0x1ba43
movw $0x0, -0x56(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x10(%rbp)
jmp 0x1b8de
movzwl -0x56(%rbp), %eax
movzwl -0x32(%rbp), %ecx
addl %ecx, %eax
movw %ax, -0x56(%rbp)
movzwl -0x4c(%rbp), %eax
movq -0x18(%rbp), %rcx
movzwl 0xe0(%rcx), %ecx
subl $0x14, %ecx
cmpl %ecx, %eax
setle %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x54(%rbp)
movzwl -0x50(%rbp), %eax
andl $0x1fff, %eax           # imm = 0x1FFF
movw %ax, -0x58(%rbp)
cmpl $0x0, -0x54(%rbp)
je 0x1ba8e
cmpl $0x0, -0x5c(%rbp)
je 0x1ba9b
movzwl -0x58(%rbp), %eax
orl $0x2000, %eax           # imm = 0x2000
movw %ax, -0x58(%rbp)
movzwl -0x58(%rbp), %edi
callq 0x251c0
movw %ax, %cx
movq -0x48(%rbp), %rax
movw %cx, 0x6(%rax)
movzwl -0x4e(%rbp), %eax
addl $0x14, %eax
movzwl %ax, %edi
callq 0x251c0
movw %ax, %cx
movq -0x48(%rbp), %rax
movw %cx, 0x2(%rax)
movq -0x48(%rbp), %rax
movw $0x0, 0xa(%rax)
movq -0x48(%rbp), %rdi
movl $0x14, %esi
callq 0x25f20
movw %ax, %cx
movq -0x48(%rbp), %rax
movw %cx, 0xa(%rax)
movq -0x18(%rbp), %rax
movq 0xc0(%rax), %rax
movq -0x18(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq *%rax
movq -0x28(%rbp), %rdi
callq 0x7260
movzwl -0x4c(%rbp), %eax
movzwl -0x4e(%rbp), %ecx
subl %ecx, %eax
movw %ax, -0x4c(%rbp)
movzwl -0x50(%rbp), %eax
movzwl -0x4a(%rbp), %ecx
addl %ecx, %eax
movw %ax, -0x50(%rbp)
jmp 0x1b80a
movb $0x0, -0x1(%rbp)
jmp 0x1bb39
movb $-0x1, -0x1(%rbp)
movb -0x1(%rbp), %al
addq $0x80, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)