user: Please show me the C implementation that matches the assembly code listed below:

```asm
<udp4_checksum>:
  endbr64
  push   %rbp
  mov    %rsp,%rbp
  push   %r14
  push   %r13
  mov    %r8,%r13
  push   %r12
  push   %rbx
  mov    %r9d,%ebx
  sub    $0x30,%rsp
  mov    %rdx,-0x50(%rbp)
  mov    %ecx,-0x48(%rbp)
  mov    %rsp,%rcx
  mov    %rdi,-0x40(%rbp)
  mov    %esi,-0x38(%rbp)
  mov    %fs:0x28,%rax
  mov    %rax,-0x28(%rbp)
  mov    D0(%rip),%rax
  movslq (%rax),%rax
  add    $0xf,%rax
  mov    %rax,%rdx
  and    $0xfffffffffffff000,%rax
  sub    %rax,%rcx
  and    $0xfffffffffffffff0,%rdx
  cmp    %rcx,%rsp
  je     L57
L51:
  sub    $0x1000,%rsp
  orq    $0x0,0xff8(%rsp)
  cmp    %rcx,%rsp
  jne    L51
L57:
  and    $0xfff,%edx
  sub    %rdx,%rsp
  test   %rdx,%rdx
  jne    L48
L40:
  lea    -0x38(%rbp),%rsi
  mov    $0x4,%edx
  mov    %rsp,%rdi
  mov    %rsp,%r14
  call   <memcpy@plt>
  lea    -0x40(%rbp),%r12
  lea    -0x3c(%rbp),%rsi
  mov    $0x4,%edx
  lea    0x4(%rsp),%rdi
  call   <memcpy@plt>
  mov    %r12,%rsi
  lea    0x9(%rsp),%rdi
  lea    -0x50(%rbp),%r12
  mov    $0x4,%edx
  movb   $0x0,0x8(%rsp)
  call   <memcpy@plt>
  mov    %r12,%rsi
  lea    0xd(%rsp),%rdi
  mov    $0x4,%edx
  call   <memcpy@plt>
  lea    -0x48(%rbp),%rsi
  lea    0x11(%rsp),%rdi
  mov    $0x4,%edx
  call   <memcpy@plt>
  lea    -0x4c(%rbp),%rsi
  lea    0x15(%rsp),%rdi
  mov    $0x4,%edx
  call   <memcpy@plt>
  mov    %r12,%rsi
  lea    0x19(%rsp),%rdi
  mov    $0x4,%edx
  call   <memcpy@plt>
  lea    0x1f(%rsp),%r12
  xor    %eax,%eax
  mov    %ebx,%edx
  mov    %r13,%rsi
  mov    %r12,%rdi
  mov    %ax,0x1d(%rsp)
  call   <memcpy@plt>
  mov    %ebx,%ecx
  movslq %ebx,%rax
  lea    0x1f(%rbx),%esi
  shr    $0x1f,%ecx
  add    %r12,%rax
  lea    (%rbx,%rcx,1),%edx
  and    $0x1,%edx
  sub    %ecx,%edx
  cmp    $0x1,%edx
  jne    L32
  movb   $0x0,(%rax)
  lea    0x20(%rbx),%esi
L32:
  mov    %r14,%rdi
  call   <checksum@plt>
  mov    -0x28(%rbp),%rdx
  sub    %fs:0x28,%rdx
  jne    L53
  lea    -0x20(%rbp),%rsp
  pop    %rbx
  pop    %r12
  pop    %r13
  pop    %r14
  pop    %rbp
  ret
  nop
L48:
  orq    $0x0,-0x8(%rsp,%rdx,1)
  jmp    L40
L53:
  call   <__stack_chk_fail@plt>
```

assistant: ```c
uint16_t udp4_checksum(struct ip iphdr, struct udphdr udphdr, uint8_t *payload, int payloadlen) {
  char buf[IP_MAXPACKET];
  char *ptr;
  int chksumlen = 0;
  int i;
  ptr = &buf[0];
  memcpy(ptr, &iphdr.ip_src.s_addr, sizeof(iphdr.ip_src.s_addr));
  ptr += sizeof(iphdr.ip_src.s_addr);
  chksumlen += sizeof(iphdr.ip_src.s_addr);
  memcpy(ptr, &iphdr.ip_dst.s_addr, sizeof(iphdr.ip_dst.s_addr));
  ptr += sizeof(iphdr.ip_dst.s_addr);
  chksumlen += sizeof(iphdr.ip_dst.s_addr);
  *ptr = 0;
  ptr++;
  chksumlen += 1;
  memcpy(ptr, &iphdr.ip_p, sizeof(iphdr.ip_p));
  ptr += sizeof(iphdr.ip_p);
  chksumlen += sizeof(iphdr.ip_p);
  memcpy(ptr, &udphdr.len, sizeof(udphdr.len));
  ptr += sizeof(udphdr.len);
  chksumlen += sizeof(udphdr.len);
  memcpy(ptr, &udphdr.source, sizeof(udphdr.source));
  ptr += sizeof(udphdr.source);
  chksumlen += sizeof(udphdr.source);
  memcpy(ptr, &udphdr.dest, sizeof(udphdr.dest));
  ptr += sizeof(udphdr.dest);
  chksumlen += sizeof(udphdr.dest);
  memcpy(ptr, &udphdr.len, sizeof(udphdr.len));
  ptr += sizeof(udphdr.len);
  chksumlen += sizeof(udphdr.len);
  *ptr = 0;
  ptr++;
  *ptr = 0;
  ptr++;
  chksumlen += 2;
  memcpy(ptr, payload, payloadlen);
  ptr += payloadlen;
  chksumlen += payloadlen;
  for (i = 0; i < payloadlen % 2; i++, ptr++) {
    *ptr = 0;
    ptr++;
    chksumlen++;
  }
  return checksum((uint16_t *)buf, chksumlen);
}
```