#include #include #include #include #include struct ethernet_header { uint8_t dest[6]; uint8_t src[6]; uint16_t ethertype; } __attribute__((packed)); struct ipv6_header { uint32_t vtf; /*uint32_t version :4; uint32_t traffic_class :8; uint32_t flow_label :20;*/ uint16_t len; uint8_t next_header; uint8_t hop_limit; uint8_t src[16]; uint8_t dest[16]; } __attribute__((packed)); struct icmpv6_header { uint8_t type; uint8_t code; uint16_t checksum; } __attribute__((packed)); struct ipv6_pseudo { uint8_t src[16]; uint8_t dest[16]; uint32_t len; uint32_t zeros :24; uint32_t next_header :8; } __attribute__((packed)); struct icmpv6_echo { uint16_t identifier; uint16_t sequence; } __attribute__((packed)); struct packet { struct ethernet_header eth; struct ipv6_header ip6; struct icmpv6_header icmp; struct icmpv6_echo echo; uint32_t ethernet_frame_check; } __attribute__((packed)); uint16_t checksum (uint16_t *addr, size_t bytes) { unsigned int i; uint16_t *p = addr; uint32_t sum = 0; /* Sum */ for (i=bytes; i > 1; i -= 2) sum += *p++; /* If uneven length */ if (i > 0) sum += (uint16_t) *((unsigned char *) (p)); /* Carry */ while ((sum & 0xFFFF0000) != 0) sum = (sum >> 16) + (sum & 0xFFFF); return ~((uint16_t) sum); } uint16_t calc_icmpv6_checksum(struct ipv6_header *ip6_header, void *data, size_t len) { uint8_t buf[1500] = {}; struct ipv6_pseudo pseudo = {}; memcpy(pseudo.src, ip6_header->src, sizeof(ip6_header->src)); memcpy(pseudo.dest, ip6_header->dest, sizeof(ip6_header->dest)); pseudo.next_header = ip6_header->next_header; pseudo.len = htonl(len); memcpy(buf, &pseudo, sizeof(pseudo)); memcpy(buf + sizeof(pseudo), data, len); return checksum(&buf, sizeof(pseudo) + len); } int main() { struct packet pkt; uint8_t eth_dest[] = {0xfc, 0xde, 0xad, 0xbe, 0xef, 0x05}; uint8_t eth_src[] = {0xfc, 0xde, 0xad, 0xbe, 0xef, 0x56}; memcpy(pkt.eth.dest, eth_dest, sizeof(pkt.eth.dest)); memcpy(pkt.eth.src, eth_src, sizeof(pkt.eth.src)); pkt.eth.ethertype = 0xdd86; // ipv6 pkt.ip6.vtf = htonl ((6 << 28) | (0 << 20) | 0); /*pkt.ip6.version = 6; pkt.ip6.traffic_class = 0; pkt.ip6.flow_label = 0;*/ pkt.ip6.len = htons(sizeof(struct icmpv6_header) + sizeof(struct icmpv6_echo)); pkt.ip6.next_header = 0x3a; // ipv6-icmp pkt.ip6.hop_limit = 2; uint8_t ipv6_src[] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }; uint8_t ipv6_dest[] = { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x5d, 0x18, 0xfb, 0x5e, 0x52, 0xec, 0xc0, }; memcpy(pkt.ip6.src, ipv6_src, sizeof(pkt.ip6.src)); memcpy(pkt.ip6.dest, ipv6_dest, sizeof(pkt.ip6.dest)); pkt.icmp.type = 129; // icmp reply pkt.icmp.checksum = 0; pkt.echo.identifier = 0; pkt.echo.sequence = 0; pkt.icmp.checksum = calc_icmpv6_checksum(&pkt.ip6, &pkt.icmp, sizeof(struct icmpv6_header) + sizeof(struct icmpv6_echo)); pkt.ethernet_frame_check = 0xdeadbeef; printf("sizeof(pkt) = %lu, pointer %p\n", sizeof(pkt), &pkt); printf("checksum %#x\n", pkt.icmp.checksum); int i; for (i=0; i < sizeof(pkt); i++) { printf("%02x ", *(((uint8_t *)&pkt) + i)); } printf("\n%d", i); return 0; }