77 lines
1.8 KiB
C++
77 lines
1.8 KiB
C++
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include "ip4.h"
|
|
|
|
namespace ip4 {
|
|
|
|
char const * tostr(uint32_t a)
|
|
{
|
|
static char tmp[16];
|
|
return inet_ntop(AF_INET, reinterpret_cast<void const *>(&a), tmp, 16);
|
|
}
|
|
|
|
uint32_t checksum_partial(uint32_t sum, void const * src, int length)
|
|
{
|
|
uint8_t const * addr = reinterpret_cast<uint8_t const *>(src);
|
|
|
|
ptrdiff_t i = 0;
|
|
while (length >= 2) {
|
|
sum += (addr[i+0] << 8) | (addr[i+1] << 0);
|
|
i += 2;
|
|
length -= 2;
|
|
}
|
|
|
|
if (length > 0) {
|
|
sum += (addr[i+0] << 8);
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
uint32_t checksum_finish(uint32_t sum)
|
|
{
|
|
while (sum >> 16) {
|
|
sum = (sum & 0xffff) + (sum >> 16);
|
|
}
|
|
|
|
return static_cast<uint16_t>(~sum);
|
|
}
|
|
|
|
uint32_t checksum(void const * src, int length)
|
|
{
|
|
uint32_t sum = checksum_partial(0, src, length);
|
|
return checksum_finish(sum);
|
|
}
|
|
|
|
header * make_header(void * buf,
|
|
uint16_t payload_length,
|
|
uint16_t identification,
|
|
uint32_t source_address, // big endian
|
|
uint32_t destination_address) // big endian
|
|
{
|
|
memset(buf, 0, (sizeof (header)));
|
|
header * hdr = reinterpret_cast<header *>(buf);
|
|
|
|
const int version = 4;
|
|
const int ihl = (sizeof (header)) / 4;
|
|
const int total_length = payload_length + (sizeof (header));
|
|
|
|
hdr->version_ihl = (version << 4) | (ihl << 0);
|
|
//hdr->type_of_service = 0xb8;
|
|
hdr->total_length = htons(total_length);
|
|
hdr->identification = htons(identification);
|
|
hdr->time_to_live = 64;
|
|
hdr->protocol = protocol::udp;
|
|
hdr->source_address = source_address;
|
|
hdr->destination_address = destination_address;
|
|
|
|
hdr->header_checksum = htons(checksum(buf, (sizeof (header))));
|
|
|
|
return hdr;
|
|
}
|
|
}
|