C Program on ICMPv6 Neighbor Advertizement (unsolicited) Message

C Program on implementing ICMPv6 Neighbor Advertisement Message using Raw sockets

How to use the binary:

Neelkanth $sudo ./a.out  
Invalid input : 1
Help section
=====================================
Enter 5 arguments:
1. Outgoing Interface Name
2. Source IPV6 Address
3. ICMPV6 Target IP Address

Neelkanth $sudo ./a.out  wlp4s0 fe80::ad6:3956:56b0:97d7 fe80::1
MAC address for interface wlp4s0 is 7c:b0:c2:19:8e:f8
Index for interface wlp4s0 is 3
Destination IPV6 address derived from target: fe80::ad6:3956:56b0:97d7
The are bytes from the packets for calculating the checksum:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
fe80 0 0 0 ad6 3956 56b0 97d7 ff02 0 0 0 0 0 0 1 0 20 0 3a 8800 a000 0 fe80 0 0 0 ad6 3956 56b0 97d7 0 201 7cb0 c219 8ef8 
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
sum: 8d59
1's complement of sum is answer(Final Checksum): a672

#####################################################

C Program Start here...

#####################################################


/*
 *##############################################################################################
 *
 *         ICMPv6 Neighbor Advertisement Unsolicited Message C program  
 *
 *##############################################################################################
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>           /* close() */
#include <string.h>           /* strcpy, memset(), and memcpy() */

#include <netdb.h>            /* struct addrinfo */
#include <sys/types.h>        /* needed for socket(), uint8_t, uint16_t */
#include <sys/socket.h>       /* needed for socket() */
#include <netinet/in.h>       /* IPPROTO_ICMPV6, INET6_ADDRSTRLEN */
#include <netinet/ip.h>       /* IP_MAXPACKET (which is 65535) */
#include <netinet/ip6.h>      /* struct ip6_hdr */
#include <netinet/icmp6.h>    /* struct icmp6_hdr and ICMP6_ECHO_REQUEST */
#include <arpa/inet.h>        /* inet_pton() and inet_ntop() */
#include <sys/ioctl.h>        /* macro ioctl is defined */
#include <bits/ioctls.h>      /* defines values for argument "request" of ioctl. */
#include <net/if.h>           /* struct ifreq */
#include <linux/if_ether.h>   /* ETH_P_IP = 0x0800, ETH_P_IPV6 = 0x86DD */
#include <linux/if_packet.h>  /* struct sockaddr_ll (see man 7 packet) */
#include <net/ethernet.h>

#include <errno.h>            /* errno, perror() */

/* Various Header Lengths  */
#define ETH_HDRLEN            14      /* Ethernet header length */
#define IPV6_HDRLEN           40      /* IPv6 header length */
#define ICMPV6_HDRLEN         24      /* ICMPv6 header length for neighbor advertisement unsolicited */
#define ICMPV6_OPTION_HDLEN    8      /* ICMPv6 option header length for neighbor advertisement unsolicited */

/* 
 * Function prototypes
 */
uint16_t checksum(uint16_t *, int);
uint16_t icmp6_checksum(struct ip6_hdr, 
                        struct nd_neighbor_advert, 
                        uint8_t *,
                        int);
char    *allocate_strmem(int);
uint8_t *allocate_ustrmem(int);

/*
 *#####################################################################################
 *                            MAIN FUNCTION STARTS HERE
 *#####################################################################################
 */
int main (int argc, char **argv)
{
    int i, status, frame_length, sd, bytes;
    char *interface = NULL, 
         *target    = NULL, 
         *src_ip    = NULL, 
         *dst_ip    = NULL;

    uint8_t *src_mac     = NULL, 
            *ether_frame = NULL;

    uint8_t *multicast_dest_mac_in_bytes = NULL;
    struct addrinfo hints, *res;
    struct sockaddr_in6 *ipv6;
    struct sockaddr_in6 icmpv6_target_ipv6_address;
    struct sockaddr_ll device;
    struct ifreq ifr;
    void *tmp = NULL;
    char multicast_dest_mac_in_str[24] = {0};    
    char *ipv6_header_dest_ip_addr = NULL;

    /*
     * Structures for ipv6 , icmpv6 Neighbor Advertisement and
     * icmpv6 options header.
     */
    struct ip6_hdr ipv6_hdr;
    struct icmp6_hdr icmphdr;
    struct nd_neighbor_advert na;
    unsigned char icmpv6_option1[ICMPV6_OPTION_HDLEN]={0};    

    /*
     * argv[1]: Outgoing interface
     * argv[2]: source ipv6 address
     * argv[3]: destination ipv6 address
     */
    if (argc != 4) {
        printf("Invalid input : %d\n", argc);
        printf("Help section\n"
                "=====================================\n"
                "Enter 3 arguments:\n"
                "1. Outgoing Interface Name\n"
                "2. Source IPV6 Address\n"
                "3. ICMPV6 Target IP Address\n"
              );
        printf("Input Arguments: %s %s %s\n",
               argv[1], argv[2], argv[3]);
        return -1;
    }

    /* 
     * Allocate memory for various arrays.
     */
    src_mac = allocate_ustrmem(6);
    multicast_dest_mac_in_bytes = allocate_ustrmem(6);
    ether_frame = allocate_ustrmem(IP_MAXPACKET);
    interface   = allocate_strmem(40);
    target = allocate_strmem(INET6_ADDRSTRLEN);
    src_ip = allocate_strmem(INET6_ADDRSTRLEN);
    dst_ip = allocate_strmem(INET6_ADDRSTRLEN);
    ipv6_header_dest_ip_addr = allocate_strmem(INET6_ADDRSTRLEN);

    /*
     *****************************************************************************
     *   INTERFACE, SOURCE IPV6 ADDRESS, DESTINATION IPV6 ADDRESS, 
     *   DESTINATION MAC ADDRESS  AND SOURCE MAC ADDRESS
     *****************************************************************************
     * */
    /* Interface to send packet through.  */
    strcpy(interface, argv[1]);

    /* Source IPv6 address: you need to fill this out */
    strcpy(src_ip, argv[2]);

    /*
     *  Destination IPv6 address either:
     *  1) unicast address of node which sent solicitation, or if the
     *  solicitation came from the unspecified address (::), use the
     *  2) IPv6 "all nodes" link-local multicast address (ff02::1).
     *  You need to fill this out.
     *  ipv6 address to be programmed in IPV6 header--> all nodes link local multicast address  
     */
    strcpy(ipv6_header_dest_ip_addr, "ff02::1");

    /* ICMPV6 target ip address.. is the link local ip address of the router  */
    strcpy (target, argv[3]);

    /* ethernet header ipv6 destination multicast MAC */
    strcpy(multicast_dest_mac_in_str, "33:33:00:00:00:01");
    sscanf(multicast_dest_mac_in_str, "%x:%x:%x:%x:%x:%x", 
           (unsigned int *)&multicast_dest_mac_in_bytes[0],
           (unsigned int *)&multicast_dest_mac_in_bytes[1],
           (unsigned int *)&multicast_dest_mac_in_bytes[2],
           (unsigned int *)&multicast_dest_mac_in_bytes[3],
           (unsigned int *)&multicast_dest_mac_in_bytes[4],
           (unsigned int *)&multicast_dest_mac_in_bytes[5]);

    /******************************************************************************/

    /* Submit request for a socket descriptor to look up interface.  */
    if ((sd = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
        perror ("socket() failed to get socket descriptor for using ioctl() ");
        exit (EXIT_FAILURE);
    }

    /* Use ioctl() to look up interface name and get its MAC address.  */
    memset(&ifr, 0, sizeof(ifr));
    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface);
    if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) {
        perror("ioctl() failed to get source MAC address ");
        return (EXIT_FAILURE);
    }
    close (sd);

    /* Copy source MAC address.  */
    memcpy(src_mac, ifr.ifr_hwaddr.sa_data, 6 * sizeof (uint8_t));
    /* 
     * Print Source MAC address of source interface from which the 
     * packet will go out. 
     */
    printf("MAC address for interface %s is ", interface);
    for (i=0; i<5; i++) {
        printf("%02x:", src_mac[i]);
    }
    printf("%02x\n", src_mac[5]);

    /* 
     * Find interface index from interface name and store index in
     * struct sockaddr_ll device, 
     * which will be used as an argument of sendto().
     */
    memset(&device, 0, sizeof (device));
    if ((device.sll_ifindex = if_nametoindex (interface)) == 0) {
        perror ("if_nametoindex() failed to obtain interface index ");
        exit (EXIT_FAILURE);
    }
    printf ("Index for interface %s is %i\n", interface, device.sll_ifindex);


    /*
     * THIS IS ONLY NEEDED WHEN TARGET IS URL AND NOT IP ADDRESS. IN THAT CASE,
     * IP ADDRESS OF THE DESTINATION IS DERIVED USING 'getaddrinfo() API 
     */
    /* Fill out hints for getaddrinfo(). */
    memset (&hints, 0, sizeof (hints));
    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = hints.ai_flags | AI_CANONNAME;
    /*  Resolve target using getaddrinfo().  */
    if ((status = getaddrinfo (src_ip, NULL, &hints, &res)) != 0) {
        fprintf (stderr, "getaddrinfo() failed: %s\n", gai_strerror (status));
        exit (EXIT_FAILURE);
    }
    
    memset(&icmpv6_target_ipv6_address, '\0', sizeof(icmpv6_target_ipv6_address));
    memcpy(&icmpv6_target_ipv6_address, res->ai_addr, res->ai_addrlen);

    ipv6 = (struct sockaddr_in6 *)res->ai_addr;
    tmp = &(ipv6->sin6_addr);
    if (inet_ntop (AF_INET6, tmp, dst_ip, INET6_ADDRSTRLEN) == NULL) {
        status = errno;
        fprintf (stderr, "inet_ntop() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }
    freeaddrinfo (res);
    printf("Destination IPV6 address derived from target: %s\n", dst_ip);    

   /* 
    *#################################################################################
    *          THE ACTUAL ICMPV6 PACKET HEADER FORMATION BEGINS FROM THIS PLACE
    *#################################################################################
    */
    /* Fill out sockaddr_ll.   */
    device.sll_family = AF_PACKET;
    memcpy (device.sll_addr, src_mac, 6 * sizeof (uint8_t));
    device.sll_halen = 6;

    /*
     * Frame 10635: 86 bytes on wire (688 bits), 86 bytes captured (688 bits) on interface 0
        Interface id: 0 (wlp4s0)
        Interface name: wlp4s0

       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       @                                 L2 Ethernet header
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       Ethernet II, Src: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8), Dst: IPv6mcast_01 (33:33:00:00:00:01)
        Destination: IPv6mcast_01 (33:33:00:00:00:01)
        Address: IPv6mcast_01 (33:33:00:00:00:01)
        .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
        .... ...1 .... .... .... .... = IG bit: Group address (multicast/broadcast)
        Source: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
        Address: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        Type: IPv6 (0x86dd)
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       @                                 L3 IPV6 header  
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       Internet Protocol Version 6, Src: fe80::ad6:3956:56b0:97d7, Dst: ff02::1
        0110 .... = Version: 6
        .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
        .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
        .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
        .... .... .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
        Payload Length: 32
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       @                                 ICMPV6 header   (24 bytes) 
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       Next Header: ICMPv6 (58)
        Hop Limit: 255
        Source: fe80::ad6:3956:56b0:97d7
        Destination: ff02::1
        Internet Control Message Protocol v6
        Type: Neighbor Advertisement (136)
        Code: 0
        Checksum: 0xa672 [correct]
        [Checksum Status: Good]
        Flags: 0xa0000000, Router, Override
        1... .... .... .... .... .... .... .... = Router: Set
        .0.. .... .... .... .... .... .... .... = Solicited: Not set
        ..1. .... .... .... .... .... .... .... = Override: Set
        ...0 0000 0000 0000 0000 0000 0000 0000 = Reserved: 0
        Target Address: fe80::ad6:3956:56b0:97d7
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       @                                 ICMPV6 option header  (8 bytes) 
       @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
       ICMPv6 Option (Target link-layer address : 7c:b0:c2:19:8e:f8)
        Type: Target link-layer address (2)
        Length: 1 (8 bytes)
        Link-layer address: IntelCor_19:8e:f8 (7c:b0:c2:19:8e:f8)
    */

    /*                            IPV6 HEADER                     */
    /*  
     * 0 and 1)  IPv6 version (4 bits), Traffic class (8 bits), Flow label (20 bits)  = [32 bits or 4 bytes]
     * 2) Payload length = ICMP header(24 bytes) + ICMP option header(8 bytes)        =  [32 bytes]
     * 3) Next header (8 bits): 58 for ICMP                                           = [1 byte]
     * 4) Hop limit (8 bits): default to maximum value                                = [1 byte] 
     * 5) Source IPv6 address (128 bits)                                              = [16 bytes] 
     * 6) Destination IPv6 address (128 bits)                                          = [16 bytes]
     */
    ipv6_hdr.ip6_flow = htonl ((6 << 28) | (0 << 20) | 0);
    ipv6_hdr.ip6_plen = htons(ICMPV6_HDRLEN + ICMPV6_OPTION_HDLEN);
    ipv6_hdr.ip6_nxt = IPPROTO_ICMPV6;
    ipv6_hdr.ip6_hops = 255;
    if ((status = inet_pton(AF_INET6, src_ip, &(ipv6_hdr.ip6_src))) != 1) {
        fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }
    if ((status = inet_pton(AF_INET6, ipv6_header_dest_ip_addr, &(ipv6_hdr.ip6_dst))) != 1) {
        fprintf (stderr, "inet_pton() failed.\nError message: %s", strerror (status));
        exit (EXIT_FAILURE);
    }


    /*                   IPMPV6 HEADER                    */
    /*  Populate icmp6_hdr portion of neighbor advertisement struct. */
    memset(&na, 0, sizeof(na));
    na.nd_na_hdr.icmp6_type  = ND_NEIGHBOR_ADVERT;   /* 136 (RFC 4861) */
    na.nd_na_hdr.icmp6_code  = 0;                    /* zero for neighbor solicitation (RFC 4861) */
    na.nd_na_hdr.icmp6_cksum = htons(0);            /* zero when calculating checksum */

    /*  Set R/S/O flags as: R=1, S=1, O=1. Set reserved to zero (RFC 4861) */
    na.nd_na_flags_reserved = htonl((1 << 31) + (1 << 29));
    na.nd_na_target = icmpv6_target_ipv6_address.sin6_addr;      /* Target address (NOT MULTICAST) (as type in6_addr) */

    /*                   ICMPV6 OPTIONS HEADER                 */
    icmpv6_option1[0] = 2;                        /* Option Type - "Target link layer address" (Section 4.6 of RFC 4861) */
    icmpv6_option1[1] = ICMPV6_OPTION_HDLEN/8;    /* Option Length - units of 8 octets (RFC 4861) */
    for (i = 0; i < 6; i++) {
        icmpv6_option1[i+2] = (uint8_t) src_mac[i];
    }

    /* 
     * Ethernet frame header.
     */

    #define ETH_DEST_MAC_OFFSET       0
    #define ETH_DEST_MAC_LEN          6    
    #define ETH_SRC_MAC_OFFSET        (ETH_DEST_MAC_OFFSET + ETH_DEST_MAC_LEN)
    #define ETH_SRC_MAC_LEN           6
    #define ETH_ETHERTYPE_LB_OFFSET   (ETH_SRC_MAC_OFFSET + ETH_SRC_MAC_LEN)
    #define ETH_ETHERTYPE_UB_OFFSET   (ETH_ETHERTYPE_LB_OFFSET + 1)
    #define ETHER_TYPE_LEN            2

    /* 
     * Ethernet frame length = 
     * ethernet header (MAC + MAC + ether type) + IP6 header + ICMPV6 header + ICMPV6 OPTIONS header
     */
    frame_length = ETH_DEST_MAC_LEN + ETH_SRC_MAC_LEN + 
                   ETHER_TYPE_LEN + IPV6_HDRLEN + ICMPV6_HDRLEN + ICMPV6_OPTION_HDLEN;

    /* Destination and Source MAC addresses */
    memcpy (ether_frame, multicast_dest_mac_in_bytes, ETH_DEST_MAC_LEN * sizeof (uint8_t));
    memcpy (ether_frame + ETH_SRC_MAC_OFFSET, src_mac, ETH_SRC_MAC_LEN * sizeof (uint8_t));

    /* 
     * Next is ethernet type code (ETH_P_IPV6 for IPv6).
     * http://www.iana.org/assignments/ethernet-numbers
     */
    ether_frame[ETH_ETHERTYPE_LB_OFFSET] = ETH_P_IPV6 / 256;
    ether_frame[ETH_ETHERTYPE_UB_OFFSET] = ETH_P_IPV6 % 256;

    /* Next is ethernet frame data (IPv6 header + ICMPV6 header + ICMPV6 option header). */

    /* IPv6 header */
    memcpy (ether_frame + ETH_HDRLEN, 
            &ipv6_hdr, IPV6_HDRLEN * sizeof (uint8_t));

    struct nd_neighbor_advert *ns_ptr = NULL;
    /* ICMPV6 header */
    memcpy (ether_frame + ETH_HDRLEN + IPV6_HDRLEN, 
            &na, ICMPV6_HDRLEN * sizeof (uint8_t));


    /* ICMPV6 Option header */
    memcpy(ether_frame + ETH_HDRLEN + IPV6_HDRLEN + ICMPV6_HDRLEN, 
           icmpv6_option1, ICMPV6_OPTION_HDLEN * sizeof (uint8_t));

    /* 
     * In order to update the checksum, retrieve the location of checksum 
     * from the packet 
     */
    ns_ptr = (struct nd_neighbor_advert *)(ether_frame + ETH_HDRLEN + IPV6_HDRLEN);
    ns_ptr->nd_na_hdr.icmp6_cksum = icmp6_checksum(ipv6_hdr,       /* ip header structure     */ 
                                                   na,             /* icmpv6 NA header structure */
                                                   icmpv6_option1, /* icmpv6 options header */        
                                                   ICMPV6_OPTION_HDLEN);

    /*  
     *  Create a raw socket to put the packet on the Wire. 
     */
    if ((sd = socket(PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0) {
        perror ("socket() failed ");
        exit (EXIT_FAILURE);
    }

    /* Send ethernet frame to socket. */
    if ((bytes = sendto (sd, ether_frame, frame_length, 
                         0, (struct sockaddr *) &device, 
                         sizeof (device))) <= 0) {
        perror ("sendto() failed");
        exit (EXIT_FAILURE);
    }

    /* Close socket descriptor. */
    close (sd);

    /* Free allocated memory. */
    free (src_mac);
    free (multicast_dest_mac_in_bytes);
    free (ether_frame);
    free (interface);
    free (target);
    free (src_ip);
    free (dst_ip);
    free (ipv6_header_dest_ip_addr);

    return (EXIT_SUCCESS);
}

/* 
 * Computing the internet checksum (RFC 1071).
 * Note that the internet checksum does not preclude collisions.
 */
uint16_t checksum (uint16_t *addr, int len)
{
    int count = len;
    register uint32_t sum = 0;
    uint16_t answer = 0;

    /* Sum up 2-byte values until none or only one byte left. */
    printf("The are bytes from the packets for calculating the checksum:\n");
    printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
    while (count > 1) {
        printf("%x ", htons(*addr));
        sum += *(addr++);
        count -= 2;
    }
    printf("\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");

    /* Add left-over byte, if any. */
    if (count > 0) {
        sum += *(uint8_t *) addr;
    }

    /* 
     * Fold 32-bit sum into 16 bits; we lose information by doing this,
     * increasing the chances of a collision.
     * sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits)
     */
    while (sum >> 16) {
        sum = (sum & 0xffff) + (sum >> 16);
    }
    printf("sum: %x\n", sum);

    /* Checksum is one's compliment of sum. */
    answer = ~sum;
    printf("1's complement of sum is answer(Final Checksum): %x\n", htons(answer));

    return (answer);
}

/* 
 * Build IPv6 ICMP pseudo-header and call checksum function 
 * (Section 8.1 of RFC 2460).
 */
uint16_t icmp6_checksum (struct ip6_hdr ipv6_hdr, 
                         struct nd_neighbor_advert na, 
                         uint8_t *payload, 
                         int payloadlen)
{
    char buf[IP_MAXPACKET];
    char *ptr = NULL;
    int chksumlen = 0;
    int i;

    /* ptr points to beginning of buffer buf */
    ptr = &buf[0];  

    /* Copy source IP address into buf (128 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_src.s6_addr, sizeof (ipv6_hdr.ip6_src.s6_addr));
    ptr += sizeof (ipv6_hdr.ip6_src);
    chksumlen += sizeof (ipv6_hdr.ip6_src);

    /* Copy destination IP address into buf (128 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_dst.s6_addr, sizeof (ipv6_hdr.ip6_dst.s6_addr));
    ptr += sizeof (ipv6_hdr.ip6_dst.s6_addr);
    chksumlen += sizeof (ipv6_hdr.ip6_dst.s6_addr);

    /* 
     * Copy Upper Layer Packet length into buf (32 bits).
     * Should not be greater than 65535 (i.e., 2 bytes).
     */ 
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    *ptr = (ICMPV6_HDRLEN + payloadlen) / 256;
    ptr++;
    *ptr = (ICMPV6_HDRLEN + payloadlen) % 256;
    ptr++;
    chksumlen += 4;

    /* Copy zero field to buf (24 bits) */
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    chksumlen += 3;

    /* Copy next header field to buf (8 bits) */
    memcpy (ptr, &ipv6_hdr.ip6_nxt, sizeof (ipv6_hdr.ip6_nxt));
    ptr += sizeof (ipv6_hdr.ip6_nxt);
    chksumlen += sizeof (ipv6_hdr.ip6_nxt);

    /* Copy ICMPv6 type to buf (8 bits) */
    memcpy (ptr, &na.nd_na_hdr.icmp6_type, sizeof (na.nd_na_hdr.icmp6_type));
    ptr += sizeof (na.nd_na_hdr.icmp6_type);
    chksumlen += sizeof (na.nd_na_hdr.icmp6_type);

    /* Copy ICMPv6 code to buf (8 bits) */
    memcpy (ptr, &na.nd_na_hdr.icmp6_code, sizeof (na.nd_na_hdr.icmp6_code));
    ptr += sizeof (na.nd_na_hdr.icmp6_code);
    chksumlen += sizeof (na.nd_na_hdr.icmp6_code);

    /* Copy ICMPv6 ID to buf (16 bits) */
    memcpy (ptr, &na.nd_na_hdr.icmp6_id, sizeof (na.nd_na_hdr.icmp6_id));
    ptr += sizeof (na.nd_na_hdr.icmp6_id);
    chksumlen += sizeof (na.nd_na_hdr.icmp6_id);

    /* Copy ICMPv6 sequence number to buff (16 bits) */
    memcpy (ptr, &na.nd_na_hdr.icmp6_seq, sizeof (na.nd_na_hdr.icmp6_seq));
    ptr += sizeof (na.nd_na_hdr.icmp6_seq);
    chksumlen += sizeof (na.nd_na_hdr.icmp6_seq);

    /* Copy ICMPv6 Neighbor Target IP6 address to buff (128 bits) */
    memcpy (ptr, &na.nd_na_target, sizeof (na.nd_na_target));
    ptr += sizeof (na.nd_na_target);
    chksumlen += sizeof (na.nd_na_target);


    /* 
     * Copy ICMPv6 checksum to buf (16 bits)
     * Zero, since we don't know it yet.
     */ 
    *ptr = 0; ptr++;
    *ptr = 0; ptr++;
    chksumlen += 2;

    /* Copy ICMPv6 payload to buf */
    memcpy (ptr, payload, payloadlen * sizeof (uint8_t));
    ptr += payloadlen;
    chksumlen += payloadlen;

    /* Pad to the next 16-bit boundary */
    for (i = 0; i < payloadlen%2; i++, ptr++) {
        *ptr = 0;
        ptr += 1;
        chksumlen += 1;
    }

    return checksum ((uint16_t *) buf, chksumlen);
}

/* Allocate memory for an array of chars. */
char * allocate_strmem(int len)
{
    void *tmp;

    if (len <= 0) {
        fprintf(stderr, "ERROR: Cannot allocate memory because len = %i in allocate_strmem().\n", len);
        exit(EXIT_FAILURE);
    }

    tmp = (char *) malloc(len * sizeof(char));
    if (tmp != NULL) {
        memset (tmp, 0, len * sizeof(char));
        return(tmp);
    } else {
        fprintf (stderr, "ERROR: Cannot allocate memory for array allocate_strmem().\n");
        exit(EXIT_FAILURE);
    }
}

/* Allocate memory for an array of unsigned chars. */
uint8_t *allocate_ustrmem(int len)
{
    void *tmp;

    if (len <= 0) {
        fprintf(stderr, "ERROR: Cannot allocate memory because len = %i in allocate_ustrmem().\n", len);
        exit(EXIT_FAILURE);
    }

    tmp = (uint8_t *) malloc(len * sizeof (uint8_t));
    if (tmp != NULL) {
        memset(tmp, 0, len * sizeof (uint8_t));
        return(tmp);
    } else {
        fprintf(stderr, "ERROR: Cannot allocate memory for array allocate_ustrmem().\n");
        exit(EXIT_FAILURE);
    }
}