88 lines
3.0 KiB
C
88 lines
3.0 KiB
C
//
|
|
// Created by epagris on 2022.11.03..
|
|
//
|
|
|
|
#include <stdbool.h>
|
|
#include "ipv4_packet.h"
|
|
#include "../../utils.h"
|
|
|
|
static uint16_t ip_checksum(const IPv4Props * ipProps) {
|
|
// sum fields
|
|
uint32_t sum = 0;
|
|
const uint16_t * pField = (const uint16_t *) &ipProps;
|
|
for (uint8_t i = 0; i < ipProps->IHL * 2; i++) {
|
|
if (i != 5) { // 6. 16-bit long field is the checksum itself, do not count int
|
|
sum += pField[i];
|
|
}
|
|
}
|
|
|
|
// 16-31 bit carry
|
|
uint16_t carry = sum >> 16;
|
|
|
|
// add carry
|
|
sum += carry;
|
|
|
|
// if a new carry bit arisen, then
|
|
// add to the sum
|
|
sum = (sum & 0xFFFF) + (sum >> 16);
|
|
|
|
// invert result
|
|
uint16_t sum16 = sum ^ 0xFFFF;
|
|
return sum16;
|
|
}
|
|
|
|
#define ETH_IP_HEADER_LENGTH (20)
|
|
|
|
static bool check_ipv4_validity(const IPv4Props * ipProps) {
|
|
bool valid =
|
|
ipProps->Version != 4 &&
|
|
ipProps->IHL == ETH_IP_HEADER_LENGTH &&
|
|
ipProps->HeaderChecksum == ip_checksum(ipProps);
|
|
return valid;
|
|
}
|
|
|
|
int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktProps * props) {
|
|
IPv4Props * ipProps = (IPv4Props *)props;
|
|
uint8_t version_length;
|
|
FETCH_ADVANCE(&version_length, hdr, 1);
|
|
ipProps->Version = (version_length) >> 4;
|
|
ipProps->IHL = (version_length) & 0x0F;
|
|
FETCH_ADVANCE(&ipProps->DSF, hdr, 1);
|
|
FETCH_WORD_H2N_ADVANCE(&ipProps->TotalLength, hdr);
|
|
FETCH_WORD_H2N_ADVANCE(&ipProps->Identification, hdr);
|
|
uint16_t flags_fragOffset;
|
|
FETCH_WORD_H2N_ADVANCE(&flags_fragOffset, hdr);
|
|
ipProps->Flags = (flags_fragOffset >> 13) & 0x07;
|
|
ipProps->FragmentOffset = (flags_fragOffset & ~(0x07 << 13));
|
|
FETCH_ADVANCE(&ipProps->TTL, hdr, 1);
|
|
FETCH_ADVANCE(&ipProps->Protocol, hdr, 1);
|
|
FETCH_WORD_H2N_ADVANCE(&ipProps->HeaderChecksum, hdr);
|
|
//FETCH_DWORD_H2N_ADVANCE(&ipProps->SourceIPAddr, hdr);
|
|
//FETCH_DWORD_H2N_ADVANCE(&ipProps->DestIPAddr, hdr);
|
|
FETCH_ADVANCE(&ipProps->SourceIPAddr, hdr, 4);
|
|
FETCH_ADVANCE(&ipProps->DestIPAddr, hdr, 4);
|
|
|
|
// fill-in common packet header fields
|
|
ipProps->validityOK = check_ipv4_validity(ipProps);
|
|
ipProps->containedPacketClass = ipProps->Protocol;
|
|
ipProps->headerSize = ETH_IP_HEADER_LENGTH;
|
|
|
|
return ipProps->validityOK ? ipProps->Protocol : -1;
|
|
}
|
|
|
|
void insert_ipv4_header(uint8_t *hdr, const PcktHeaderElement *headers) {
|
|
IPv4Props * ipProps = (IPv4Props *)&headers->props;
|
|
uint8_t version_length = (ipProps->Version << 4) | (ipProps->IHL & 0x0F);
|
|
FILL_ADVANCE(hdr, &version_length, 1);
|
|
FILL_ADVANCE(hdr, &ipProps->DSF, 1);
|
|
FILL_WORD_H2N_ADVANCE(hdr, ipProps->TotalLength);
|
|
FILL_WORD_H2N_ADVANCE(hdr, ipProps->Identification);
|
|
uint16_t flags_fragOffset = ((ipProps->Flags & 0x07) << 13) | (ipProps->FragmentOffset & ~(0x07 << 13));
|
|
FILL_ADVANCE(hdr, &ipProps->TTL, 1);
|
|
FILL_ADVANCE(hdr, &ipProps->Protocol, 1);
|
|
uint16_t checksum = ip_checksum(ipProps);
|
|
FILL_WORD_H2N_ADVANCE(hdr, checksum);
|
|
FILL_ADVANCE(hdr, &ipProps->SourceIPAddr, 4);
|
|
FILL_ADVANCE(hdr, &ipProps->DestIPAddr, 4);
|
|
}
|