Load of advancements

This commit is contained in:
Wiesner András 2022-11-07 21:51:18 +01:00
parent 49fa57b63e
commit 3e1a2174a6
27 changed files with 720 additions and 126 deletions

View File

@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = /home/epagris/VCSDEV/EtherLib/docs
OUTPUT_DIRECTORY = ./../docs
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@ -316,7 +316,7 @@ OPTIMIZE_OUTPUT_SLICE = NO
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran class files). For instance to make doxygen treat .inc files
# default for Fortran type files). For instance to make doxygen treat .inc files
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C.
#
@ -385,7 +385,7 @@ SIP_SUPPORT = NO
# getter and setter methods for a property. Setting this option to YES will make
# doxygen to replace the get and set methods by a property in the documentation.
# This will only work if the methods are indeed getting or setting a simple
# class. If this is not the case, or you want to show the methods anyway, you
# type. If this is not the case, or you want to show the methods anyway, you
# should set this option to NO.
# The default value is: YES.
@ -406,9 +406,9 @@ DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same class
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# class (e.g. under the Public Functions section). Set it to NO to prevent
# type (e.g. under the Public Functions section). Set it to NO to prevent
# subgrouping. Alternatively, this can be done per class using the
# \nosubgrouping command.
# The default value is: YES.
@ -680,7 +680,7 @@ SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
# class resolution of all parameters of a function it will reject a match between
# type resolution of all parameters of a function it will reject a match between
# the prototype and the implementation of a member function even if there is
# only one candidate or it is obvious which candidate to choose by doing a
# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
@ -864,7 +864,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = /home/epagris/VCSDEV/EtherLib/etherlib
INPUT = .
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -943,7 +943,7 @@ FILE_PATTERNS = *.c \
# be searched for input files as well.
# The default value is: NO.
RECURSIVE = NO
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
@ -1153,7 +1153,7 @@ VERBATIM_HEADERS = YES
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which doxygen's built-in parser lacks the necessary class information.
# which doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
@ -1840,7 +1840,7 @@ LATEX_MAKEINDEX_CMD = makeindex
COMPACT_LATEX = NO
# The PAPER_TYPE tag can be used to set the paper class that is used by the
# The PAPER_TYPE tag can be used to set the paper type that is used by the
# printer.
# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
# 14 inches) and executive (7.25 x 10.5 inches).
@ -2218,7 +2218,7 @@ ENABLE_PREPROCESSING = YES
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = NO
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
@ -2226,7 +2226,7 @@ MACRO_EXPANSION = NO
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_ONLY_PREDEF = YES
EXPAND_ONLY_PREDEF = NO
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
@ -2240,7 +2240,7 @@ SEARCH_INCLUDES = YES
# preprocessor.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
INCLUDE_PATH = .
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
@ -2429,7 +2429,7 @@ UML_LOOK = NO
# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
# class node. If there are many fields or methods and many nodes the graph may
# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
# number of items for each class to make the size more manageable. Set this to 0
# number of items for each type to make the size more manageable. Set this to 0
# for no limit. Note that the threshold may be exceeded by 50% before the limit
# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
# but if the number exceeds 15, the total amount of fields shown is limited to
@ -2441,7 +2441,7 @@ UML_LIMIT_NUM_FIELDS = 10
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add class and arguments for attributes and
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
@ -2453,7 +2453,7 @@ UML_LIMIT_NUM_FIELDS = 10
DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length_type exceeds this threshold
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.

13
connection_block.c Normal file
View File

@ -0,0 +1,13 @@
//
// Created by epagris on 2022.11.07..
//
#include "connection_block.h"
#include <stddef.h>
void connb_remove(ConnBlock *connb) {
if (connb != NULL) {
packsieve_remove_layer(connb->sieveLayer);
}
}

23
connection_block.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef ETHERLIB_CONNECTION_BLOCK_H
#define ETHERLIB_CONNECTION_BLOCK_H
#include "packet_sieve.h"
#include "eth_interface.h"
struct ConnBlock_;
typedef int (*ConnBlockTransmitFn)(EthInterface * intf, const uint8_t * data, uint32_t size, const struct ConnBlock_ * connBlock);
typedef struct ConnBlock_ {
EthInterface * intf; ///< Ethernet interface
PcktSieveLayer * sieveLayer; ///< Sieve layer
ConnBlockTransmitFn transmitFn; ///< Conn-block related transmit function
} ConnBlock;
/**
* Remove connection block.
* @param connb pointer to existing connection block
*/
void connb_remove(ConnBlock * connb);
#endif //ETHERLIB_CONNECTION_BLOCK_H

22
eth_interface.c Normal file
View File

@ -0,0 +1,22 @@
//
// Created by epagris on 2022.10.20..
//
#include "eth_interface.h"
#include "dynmem.h"
#include "utils.h"
EthInterface *ethintf_new() {
EthInterface * ethIntf = (EthInterface *)dynmem_alloc(sizeof(EthInterface));
ASSERT_NULL(ethIntf);
memset(&ethIntf->sieve.layer0, 0, sizeof(PcktSieveLayer));
return ethIntf;
}
void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt) {
packsieve_input(&intf->sieve, rawPckt);
}
void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt) {
intf->ioDef.llTx(rawPckt);
}

37
eth_interface.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef ETHERLIB_ETH_INTERFACE_H
#define ETHERLIB_ETH_INTERFACE_H
#include "packet_sieve.h"
#include "prefab/packet_parsers/packet_parsers.h"
typedef struct {
int (*llTx)(const RawPckt * rawPckt); ///< Function pointer to low-level transmit function
int (*llTxDone)(const RawPckt * rawPckt); ///< Transmission done (interrupt) callback
int (*llLinkChg)(int linkState); ///< Link change interrupt
int (*llError)(int error); ///< Low-level error interrupt
} EthIODef;
typedef struct {
PcktSieve sieve; ///< Packet sieve
EthIODef ioDef; ///< Low-level IO definitions
EthernetAddress mac; ///< Ethernet address
} EthInterface;
/**
* Allocate a new Ethernet interface
* @return new interface instance
*/
EthInterface * ethintf_new();
/**
* Receive uncooked packet.
* @param rawPckt
*/
void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt);
/**
* Transmit packet.
*/
void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt);
#endif //ETHERLIB_ETH_INTERFACE_H

View File

@ -3,6 +3,7 @@
#include "dynmem.h"
#include "prefab/prefab.h"
#include "packet_sieve.h"
EthState gEthState;
@ -13,69 +14,27 @@ static void register_packet_parsers() {
cdesc.containerClass = 0;
cdesc.procFun = parse_ethernet;
cdesc.propertySize = sizeof(EthernetProps);
packreg_add(E.pcktReg, &cdesc);
packreg_add_class(E.pcktReg, &cdesc);
// IPv4 packet parser
cdesc.class = ETH_IPv4_PACKET_CLASS;
cdesc.containerClass = 0;
cdesc.procFun = parse_ipv4;
cdesc.propertySize = sizeof(IPv4Props);
packreg_add(E.pcktReg, &cdesc);
packreg_add_class(E.pcktReg, &cdesc);
// UDP packet parser
cdesc.class = ETH_UDP_PACKET_CLASS;
cdesc.containerClass = ETH_IPv4_PACKET_CLASS;
cdesc.procFun = parse_udp;
cdesc.propertySize = sizeof(UDPProps);
packreg_add(E.pcktReg, &cdesc);
cdesc.propertySize = sizeof(UdpProps);
packreg_add_class(E.pcktReg, &cdesc);
}
void ethlib_init() {
dynmem_init(); // initialize dynamic memory subsystem
E.pcktReg = packreg_new(); // create new packet registry
register_packet_parsers(); // register packet parsers
}
typedef struct PcktHeaderElement_ {
struct PcktHeaderElement_ * next, * prev; ///< Next and previous header in the linked list
PcktProps props; ///< Properties (allocated to appropriate size)
} PcktHeaderElement;
#define ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE (2 * sizeof(PcktHeaderElement *))
void process_raw_packet(const uint8_t * data, uint32_t size) {
uint16_t ownClass = 0, containerClass = 0; // Ethernet...
uint16_t offset = 0;
PcktHeaderElement * lastHeader = NULL;
do {
// get packet descriptor
const PcktClassDesc * cdesc = packreg_get_by_class(E.pcktReg, ownClass, containerClass);
if (cdesc == NULL) {
break;
}
// allocate property object
PcktHeaderElement * header = (PcktHeaderElement *) dynmem_alloc(ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + cdesc->propertySize);
header->props.ownPacketClass = ownClass;
header->props.propSize = cdesc->propertySize;
header->prev = lastHeader;
if (lastHeader) {
lastHeader->next = header;
}
// call parsing function
cdesc->procFun(data + offset, size - offset, &header->props);
uint16_t containedClass = header->props.containedPacketClass;
if (containedClass != 0) {
containerClass = ownClass;
offset += header->props.headerSize;
//dynmem_free(props);
}
ownClass = containedClass;
lastHeader = header;
} while (ownClass != 0);
// TODO process innermost packet
return;
E.ethIntf = ethintf_new(); // create new Ethernet interface
}

View File

@ -3,6 +3,8 @@
#include "memory_pool.h"
#include "packet_registry.h"
#include "packet_sieve.h"
#include "eth_interface.h"
/**
* Global EtherLib state.
@ -10,6 +12,7 @@
typedef struct {
MP * mp; ///< Memory pool for dynamic allocations
PcktRegistry * pcktReg; ///< Packet registry
EthInterface * ethIntf; ///< Array of Ethernet interfaces
} EthState;
extern EthState gEthState;

View File

@ -140,5 +140,7 @@ void mp_report(MP *mp) {
recIter--;
bi++;
}
INFO("\n");
INFO("----------------------\n");
INFO("Used: %u (mgmt: %u)\nFree: %u of %u\n\n", (mp->poolSize - mp->freeSpace),
(mp->blockRecCnt + 1) * sizeof(MPAllocRecord), mp->freeSpace, mp->poolSize);
}

View File

@ -2,4 +2,4 @@
// Created by epagris on 2022.10.17..
//
#include "common_types.h"
#include "packet.h"

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_COMMON_TYPES_H
#define ETHERLIB_COMMON_TYPES_H
#ifndef ETHERLIB_PACKET_H
#define ETHERLIB_PACKET_H
#include <stdint.h>
@ -10,22 +10,26 @@
typedef struct {
uint8_t * payload; ///> Pointer to raw packet payload.
uint32_t size; ///> Raw packet size.
uint32_t time_s; ///> Timestamp seconds field
uint32_t time_ns; ///> Timestamp nanoseconds field
} RawPckt;
struct PcktHeaderElement_;
/**
* \struct Pckt
* \brief Generic packet
* @struct Pckt
* @brief Generic packet
*
* Fields have been reordered so that fields are aligned.
*/
typedef struct {
uint64_t time_s; ///< Timestamp seconds part.
uint32_t time_ns; ///< Timestamp nanoseconds part.
uint8_t * header; ///< Pointer to packet header. Points to the outmost header (e.g. Ethernet-header in case of a UDP-packet)
const struct PcktHeaderElement_ * header; ///< Pointer to packet header. Points to the innermost header
uint8_t * payload; ///< Pointer to (innermost) payload.
uint16_t headerSize; ///< Packet header size in bytes.
uint16_t payloadSize; ///< Payload size in bytes.
uint16_t type; ///< Packet class indicator (e.g. UDP, TCP, IPv4 etc.)
//uint16_t type; ///< Packet class indicator (e.g. UDP, TCP, IPv4 etc.)
} Pckt;
#endif //ETHERLIB_COMMON_TYPES_H
#endif //ETHERLIB_PACKET_H

View File

@ -1,5 +0,0 @@
//
// Created by epagris on 2022.10.20..
//
#include "packet_input.h"

View File

@ -1,6 +0,0 @@
#ifndef ETHERLIB_PACKET_INPUT_H
#define ETHERLIB_PACKET_INPUT_H
void input_packet();
#endif //ETHERLIB_PACKET_INPUT_H

View File

@ -18,7 +18,7 @@ PcktRegistry * packreg_new() {
return packReg;
}
void packreg_add(PcktRegistry * packReg, const PcktClassDesc * classDesc) {
void packreg_add_class(PcktRegistry * packReg, const PcktClassDesc * classDesc) {
// if buffer is full and reallocation and resize is needed
if (packReg->reservedCnt == packReg->entCnt) {
PcktClassDesc * newEnts = (PcktClassDesc *) dynmem_alloc(packReg->reservedCnt * 2);

View File

@ -21,11 +21,12 @@ typedef uint8_t bool8_t;
struct PcktClassDesc_;
#define PcktPropsHeader \
uint16_t propSize; /* Size of this property object */ \
uint16_t headerSize; /*< Header size in bytes */ \
uint16_t containedPacketClass; /*< Class of contained packet. Zero if no packet contained. */ \
uint16_t ownPacketClass; /* Our own packet class */ \
bool8_t validityOK; /*< Indicates that checksum is OK. */ \
uint16_t propSize; /**< Size of this property object */ \
uint16_t headerSize; /**< Header size in bytes */ \
uint16_t containedPacketClass; /**< Class of contained packet. Zero if no packet contained. */ \
uint16_t ownPacketClass; /**< Our own packet class */ \
uint16_t accumulatedOffset; /** Accumulated offset from the beginning of the packet */ \
bool8_t validityOK; /**< Indicates that checksum is OK. */ \
typedef struct {
@ -78,7 +79,7 @@ PcktRegistry *packreg_new();
* Add new packet class. (e.g. UDP, IP...)
* @param classDesc Packet class descriptor
*/
void packreg_add(PcktRegistry *packReg, const PcktClassDesc *classDesc);
void packreg_add_class(PcktRegistry *packReg, const PcktClassDesc *classDesc);
/**
* Get packet descriptor by own class and container class.
@ -89,4 +90,6 @@ void packreg_add(PcktRegistry *packReg, const PcktClassDesc *classDesc);
*/
const PcktClassDesc *packreg_get_by_class(const PcktRegistry *packReg, uint16_t ownClass, uint16_t containerClass);
#endif //ETHERLIB_PACKET_REGISTRY_H

190
packet_sieve.c Normal file
View File

@ -0,0 +1,190 @@
//
// Created by epagris on 2022.11.06..
//
#include <stddef.h>
#include "packet_sieve.h"
#include "global_state.h"
#include "dynmem.h"
#include "utils.h"
bool packfiltcond_cmp(const PcktSieveFilterCondition * c1, const PcktSieveFilterCondition * c2) {
return !memcmp(c1, c2, sizeof(PcktSieveFilterCondition));
}
void packfiltcond_zero(PcktSieveFilterCondition * cond) {
memset(cond, 0, sizeof(PcktSieveFilterCondition));
}
PcktSieve *packsieve_new() {
PcktSieve *sieve = (PcktSieve *) dynmem_alloc(sizeof(PcktSieve));
ASSERT_NULL(sieve);
memset(&sieve->layer0, 0, sizeof(PcktSieveLayer)); // clear layer0 data
return sieve;
}
void packsieve_input(const PcktSieve *sieve, const RawPckt * rawPckt) {
// extract fields
uint8_t * data = rawPckt->payload;
uint32_t size = rawPckt->size;
// process payload, fetch packet class etc.
uint16_t ownClass = 0, containerClass = 0; // Ethernet...
uint16_t offset = 0;
PcktHeaderElement *lastHeader = NULL, *outermostHeader = NULL;
do {
// get packet descriptor
const PcktClassDesc *cdesc = packreg_get_by_class(E.pcktReg, ownClass, containerClass);
if (cdesc == NULL) {
break;
}
// allocate property object
PcktHeaderElement *header = (PcktHeaderElement *) dynmem_alloc(ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + cdesc->propertySize);
header->props.ownPacketClass = ownClass;
header->props.propSize = cdesc->propertySize;
header->prev = lastHeader;
if (lastHeader) {
lastHeader->next = header;
}
if (outermostHeader == NULL) {
outermostHeader = lastHeader;
}
// call parsing function
cdesc->procFun(data + offset, size - offset, &header->props);
uint16_t containedClass = header->props.containedPacketClass;
if (containedClass != 0) {
containerClass = ownClass;
//dynmem_free(props);
}
offset += header->props.headerSize;
header->props.accumulatedOffset = offset;
ownClass = containedClass;
lastHeader = header;
} while (ownClass != 0);
// ------------------------------------
Pckt packet;
packet.time_s = rawPckt->time_s;
packet.time_ns = rawPckt->time_ns;
// lookup headers in the sieve
const PcktHeaderElement * headerIter = outermostHeader;
const PcktSieveLayer *layer = &sieve->layer0; // innermost matched sieve layer
bool found = true; // first structure is always an Ethernet-frame
while (found && headerIter) {
const PcktSieveLayer * nodeIter = layer->nodes;
found = false;
while (nodeIter && !found) {
found |= nodeIter->filtFn(&nodeIter->filtCond, &headerIter->props, &headerIter->next->props);
if (found) {
layer = nodeIter; // advance in the sieve tree
const PcktHeaderElement * containedHeader = headerIter->next; // advance on headers
if (layer->cbFn != NULL) { // if defined, invoke layer callback function
offset = containedHeader->props.accumulatedOffset; // accumulated offset + own header size
packet.header = containedHeader;
packet.payload = data + offset;
packet.headerSize = offset;
packet.payloadSize = size - offset;
layer->cbFn(&packet);
}
headerIter = containedHeader;
} else {
nodeIter = nodeIter->next; // advance on linked list and countinue search
}
}
}
// if there are no more sieve layers (cannot process headers further) BUT
// meaningful headers have been left unprocessed
// if (layer->next == NULL && headerIter) {
// INFO("Packet headers not fully processed!\n");
// }
return;
}
PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag, uint16_t pcktClass) {
// search for matching layer
PcktSieveLayer * nodeIter = parent->nodes;
bool alreadyExists = false;
while (nodeIter != NULL && !alreadyExists) {
if (packfiltcond_cmp(&nodeIter->filtCond, filtCond) && (nodeIter->filtFn == filtFn)) { // if matching...
alreadyExists = true;
} else {
nodeIter = nodeIter->next;
}
}
// if found, then return with the pointer to the existing layer
if (alreadyExists) {
return nodeIter; // OK
} else { // if allocation of a new layer is required
PcktSieveLayer *layer = (PcktSieveLayer *) dynmem_alloc(sizeof(PcktSieveLayer));
ASSERT_NULL(layer);
PcktSieveLayer *oldListFirst = parent->nodes;
parent->nodes = layer; // replace first element (it's the fastest way of new element insertion, since element position does not carry any meaning this case)
layer->packetClass = pcktClass;
layer->parent = parent;
layer->prev = NULL;
layer->next = oldListFirst;
if (oldListFirst != NULL) {
layer->prev = layer;
}
layer->nodes = NULL;
layer->filtCond = *filtCond;
layer->filtFn = filtFn;
layer->cbFn = cbFn;
layer->tag = tag;
return layer;
}
}
bool packsieve_remove_layer(PcktSieveLayer * layer) {
// avoid NULL-operations
if (layer == NULL) {
return true;
}
// remove parent elements if their only subnode is the one we're deleting
PcktSieveLayer * parent;
while (layer != NULL && layer->nodes == NULL) {
parent = layer->parent; // store parent
// chain out our layer
if (layer->next == NULL && layer->prev == NULL) { // we are the only subnode
parent->nodes = NULL;
} else { // there are multiple subnodes, just chain us out
if (layer->next != NULL) {
layer->next->prev = layer->prev;
}
if (layer->prev != NULL) {
layer->prev->next = layer->next;
}
if (parent->nodes == layer) {
parent->nodes = layer->next;
}
}
dynmem_free(layer); // deallocate layer
layer = parent; // advance in the tree
}
return layer == NULL;
}
#define ETH_SIEVE_LAYER_INDENT_PER_LEVEL (4)
void packsieve_report(const PcktSieveLayer *layer, uint32_t indent) {
INFO("%*c\\--|%d|---\n", indent, ' ', layer->packetClass);
const PcktSieveLayer * nodeIter = layer->nodes;
while(nodeIter) {
packsieve_report(nodeIter, indent + ETH_SIEVE_LAYER_INDENT_PER_LEVEL);
nodeIter = nodeIter->next;
}
}

104
packet_sieve.h Normal file
View File

@ -0,0 +1,104 @@
#ifndef ETHERLIB_PACKET_SIEVE_H
#define ETHERLIB_PACKET_SIEVE_H
#include <stdbool.h>
#include "packet_registry.h"
#include "packet.h"
typedef struct PcktHeaderElement_ {
struct PcktHeaderElement_ * next, * prev; ///< Next and previous header in the linked list
PcktProps props; ///< Properties (allocated to appropriate size)
} PcktHeaderElement;
#define ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE (2 * sizeof(PcktHeaderElement *))
/**
* @union PcktSieveFilterCondition
* Union for storing filter conditions.
*/
typedef union {
uint16_t uw[8];
uint32_t u[4];
uint64_t lu[2];
int16_t sw[8];
int32_t i[4];
int64_t li[2];
uint8_t d[16];
} PcktSieveFilterCondition;
/**
* Function for comparing filter conditions.
* @param c1 condition 1
* @param c2 condition 2
* @return true if cond1 matches cond2, otherwise false
*/
bool packfiltcond_cmp(const PcktSieveFilterCondition * c1, const PcktSieveFilterCondition * c2);
/**
* Clear packet filter condition structure.
* @param cond pointer to existing filter condition structure
*/
void packfiltcond_zero(PcktSieveFilterCondition * cond);
typedef bool (*SieveFilterFn)(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps);
struct PcktSieveLayer_;
typedef int (*SieveCallBackFn)(const Pckt * pckt);
typedef union {
void * p;
uint32_t u;
} PcktSieveLayerTag;
typedef struct PcktSieveLayer_ {
uint16_t packetClass; ///< Packet class (e.g. IP)
PcktSieveFilterCondition filtCond; ///< Filter condition, arbitrary type (e.g. destination IP-address)
SieveFilterFn filtFn; ///< Filter function pointer
SieveCallBackFn cbFn; ///< Associated callback function
PcktSieveLayerTag tag; ///< Layer tag (arbitrary information)
struct PcktSieveLayer_ * parent; ///< Pointer to parent node in the sieve tree
struct PcktSieveLayer_ * next, * prev; ///< Next and previous sieve layer on the same level
struct PcktSieveLayer_ * nodes; ///< Subnodes on the sieve tree
} PcktSieveLayer;
typedef struct {
PcktSieveLayer layer0; ///< Top of sieve tree
} PcktSieve;
/**
* Create new packet sieve.
* @return pointer to packet sieve object or NULL on failure
*/
PcktSieve * packsieve_new();
/**
* Process packet with packet sieve.
* @param bottomLayer
* @param data
* @param size
*/
void packsieve_input(const PcktSieve * sieve, const RawPckt * rawPckt);
/**
* Create a new sieve filter layer.
* @param parent parent layer
* @return pointer to new layer object or NULL on failure
*/
PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag, uint16_t pcktClass);
/**
* Remove sieve layer from packet sieve.
* @param layer Layer to remove and deallocate
*/
bool packsieve_remove_layer(PcktSieveLayer * layer);
/**
* Display layer on terminal.
* @param layer pointer to existing layer
* @param indent sub-tree indentation
*/
void packsieve_report(const PcktSieveLayer *layer, uint32_t indent);
#endif //ETHERLIB_PACKET_SIEVE_H

View File

@ -0,0 +1,27 @@
//
// Created by epagris on 2022.11.07..
//
#include "ipv4_connblock.h"
#include "../packet_parsers/packet_parsers.h"
#include "../../utils.h"
static bool filtIPv4(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps) {
EthernetProps * etherProps = (EthernetProps *) contProps;
IPv4Props * ipProps = (IPv4Props *) ownProps;
return etherProps->length_type == ETH_IPv4_PACKET_CLASS && filtCond->u[0] == ipProps->DestIPAddr;
}
ConnBlock ipv4_new_connblock(EthInterface *intf, ip4_addr ipAddr, SieveCallBackFn cbFn) {
ConnBlock connb;
PcktSieveFilterCondition filtCond;
packfiltcond_zero(&filtCond);
filtCond.u[0] = ipAddr;
PcktSieveLayerTag tag;
tag.u = 0;
connb.sieveLayer = packsieve_new_layer(&intf->sieve.layer0, &filtCond, filtIPv4, cbFn, tag, ETH_IPv4_PACKET_CLASS);
ASSERT_NULL(connb.sieveLayer);
return connb;
}

View File

@ -0,0 +1,29 @@
#ifndef ETHERLIB_IPV4_CONNBLOCK_H
#define ETHERLIB_IPV4_CONNBLOCK_H
#include <stdint.h>
#include "../../connection_block.h"
#include "../../eth_interface.h"
typedef uint32_t ip4_addr;
/**
* Create new IPv4 connection block.
* @param intf interface to the connection block will be associated
* @param ipAddr address of the connection block
* @param cbFn callback function fired when connection block receives data
* @return instance of a new connection block
*/
ConnBlock ipv4_new_connblock(EthInterface * intf, ip4_addr ipAddr, SieveCallBackFn cbFn);
/**
* Send IPv4 packet to specified IPv4 address.
* @param intf interface we will use
* @param addr address to send to
* @param data data to be transmitted
* @param size data size
* @param headers linked list of headers, always list top contains relevant info
*/
void ipv4_send(EthInterface * intf, ip4_addr addr, const uint8_t * data, uint32_t size, const PcktHeaderElement * headers);
#endif //ETHERLIB_IPV4_CONNBLOCK_H

View File

@ -0,0 +1,56 @@
//
// Created by epagris on 2022.11.07..
//
#include "udp_connblock.h"
#include <stddef.h>
#include "../packet_parsers/packet_parsers.h"
#include "../../utils.h"
#include "../../dynmem.h"
static bool filtUdp(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps) {
IPv4Props * ipProps = (IPv4Props *) contProps;
UdpProps * udpProps = (UdpProps *) ownProps;
return ipProps->Protocol == ETH_UDP_PACKET_CLASS && filtCond->uw[0] == udpProps->DestinationPort;
}
ConnBlock udp_new_connblock(EthInterface * intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn) {
ConnBlock udpConnB;
ConnBlock ipConnB = ipv4_new_connblock(intf, ipAddr, NULL); // create new IPv4 connection block
PcktSieveFilterCondition filtCond;
packfiltcond_zero(&filtCond);
filtCond.uw[0] = port;
PcktSieveLayerTag tag;
tag.u = 0;
udpConnB.sieveLayer = packsieve_new_layer(ipConnB.sieveLayer, &filtCond, filtUdp, cbFn, tag, ETH_UDP_PACKET_CLASS);
ASSERT_NULL(udpConnB.sieveLayer);
return udpConnB;
}
#define ALLOC_HEADER_ELEMENT(T) (PcktHeaderElement *) dynmem_alloc(ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + sizeof(T))
#define HEADER_FETCH_PROPS(T,h) (T *)(&h->props)
int udp_send(const struct ConnBlock_ * connBlock, const uint8_t *data, uint32_t size) {
// allocate headers
PcktHeaderElement * udpHeader = ALLOC_HEADER_ELEMENT(UdpProps);
PcktHeaderElement * ipHeader = ALLOC_HEADER_ELEMENT(IPv4Props);
PcktHeaderElement * ethHeader = ALLOC_HEADER_ELEMENT(EthernetProps);
udpHeader->next = NULL;
udpHeader->prev = ipHeader;
ipHeader->next = udpHeader;
ipHeader->prev = ethHeader;
ethHeader->next = ipHeader;
ethHeader->prev = NULL;
UdpProps * udpProps = HEADER_FETCH_PROPS(UdpProps, udpHeader);
IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, udpHeader);
EthernetProps * ethProps = HEADER_FETCH_PROPS(EthernetProps, udpHeader);
udpProps->Length = size;
return 0;
}

View File

@ -0,0 +1,24 @@
#ifndef ETHERLIB_UDP_CONNBLOCK_H
#define ETHERLIB_UDP_CONNBLOCK_H
#include <stdint.h>
#include "../../connection_block.h"
#include "../../eth_interface.h"
#include "ipv4_connblock.h"
/**
* Create new IPv4 connection block.
* @param intf interface to the connection block will be associated
* @param ipAddr address of the connection block
* @param port port of the connection block
* @param cbFn callback function fired when connection block receives data or some event occurs
* @return instance of a new connection block
*/
ConnBlock udp_new_connblock(EthInterface * intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn);
/**
* UDP transmit callback.
*/
int udp_send(const struct ConnBlock_ * connBlock, const uint8_t * data, uint32_t size);
#endif //ETHERLIB_UDP_CONNBLOCK_H

View File

@ -5,16 +5,16 @@
#include <memory.h>
#include <stdbool.h>
#include "ethernet_frame.h"
#include "etherlib/utils.h"
#include "../../utils.h"
#define ETH_ETHERTYPE_LENGTH_THRESHOLD (1500)
#define ETH_ETHERNET_HEADER_SIZE (14)
int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktProps * props) {
EthernetProps * frameProps = (EthernetProps *)props;
COPY_ADVANCE(frameProps->destAddr, hdr, ETH_HW_ADDR_LEN); // copy destination address
COPY_ADVANCE(frameProps->sourceAddr, hdr, ETH_HW_ADDR_LEN); // copy destination address
COPY_WORD_H2N_ADVANCE(&frameProps->length_type, hdr); // copy length/type field
FETCH_ADVANCE(frameProps->destAddr, hdr, ETH_HW_ADDR_LEN); // copy destination address
FETCH_ADVANCE(frameProps->sourceAddr, hdr, ETH_HW_ADDR_LEN); // copy destination address
FETCH_WORD_H2N_ADVANCE(&frameProps->length_type, hdr); // copy length/type field
// fill-in packet property header fields
frameProps->validityOK = true;
@ -24,3 +24,10 @@ int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktProps * props) {
return frameProps->containedPacketClass;
}
void insert_ethernet_header(uint8_t *hdr, const PcktHeaderElement *headers) {
EthernetProps * ethProps = (EthernetProps *) &headers->props;
FILL_ADVANCE(hdr, ethProps->destAddr, ETH_HW_ADDR_LEN);
FILL_ADVANCE(hdr, ethProps->sourceAddr, ETH_HW_ADDR_LEN);
FILL_WORD_H2N_ADVANCE(hdr, ethProps->length_type);
}

View File

@ -6,18 +6,22 @@
#define ETHERLIB_ETHERNET_FRAME_H
#include <stdint.h>
#include "etherlib/packet_registry.h"
#include "../../packet_registry.h"
#include "../../packet_sieve.h"
#define ETH_HW_ADDR_LEN (6)
#define ETH_ETHERNET_HEADER_SIZE (14)
typedef uint8_t EthernetAddress[ETH_HW_ADDR_LEN];
/**
* @struct EthernetProps
* Ethernet frame properties
*/
typedef struct {
PcktPropsHeader
uint8_t destAddr[ETH_HW_ADDR_LEN]; ///< destination address
uint8_t sourceAddr[ETH_HW_ADDR_LEN]; ///< source address
PcktPropsHeader;
EthernetAddress destAddr[ETH_HW_ADDR_LEN]; ///< destination address
EthernetAddress sourceAddr[ETH_HW_ADDR_LEN]; ///< source address
uint16_t length_type; ///< frame length_type
} EthernetProps;
@ -30,4 +34,11 @@ typedef struct {
*/
int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktProps * props);
/**
* Insert Ethernet header to specified address.
* @param hdr space where the header is to be inserted
* @param headers linked list of header, top is always relevant
*/
void insert_ethernet_header(uint8_t * hdr, const PcktHeaderElement * headers);
#endif //ETHERLIB_ETHERNET_FRAME_H

View File

@ -4,7 +4,7 @@
#include <stdbool.h>
#include "ipv4_packet.h"
#include "etherlib/utils.h"
#include "../../utils.h"
static uint16_t ip_checksum(const IPv4Props * ipProps) {
// sum fields
@ -44,21 +44,23 @@ static bool check_ipv4_validity(const IPv4Props * ipProps) {
int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktProps * props) {
IPv4Props * ipProps = (IPv4Props *)props;
uint8_t version_length;
COPY_ADVANCE(&version_length, hdr, 1);
FETCH_ADVANCE(&version_length, hdr, 1);
ipProps->Version = (version_length) >> 4;
ipProps->IHL = (version_length) & 0x0F;
COPY_ADVANCE(&ipProps->DSF, hdr, 1);
COPY_WORD_H2N_ADVANCE(&ipProps->TotalLength, hdr);
COPY_WORD_H2N_ADVANCE(&ipProps->Identification, hdr);
FETCH_ADVANCE(&ipProps->DSF, hdr, 1);
FETCH_WORD_H2N_ADVANCE(&ipProps->TotalLength, hdr);
FETCH_WORD_H2N_ADVANCE(&ipProps->Identification, hdr);
uint16_t flags_fragOffset;
COPY_WORD_H2N_ADVANCE(&flags_fragOffset, hdr);
FETCH_WORD_H2N_ADVANCE(&flags_fragOffset, hdr);
ipProps->Flags = (flags_fragOffset >> 13) & 0x07;
ipProps->FragmentOffset = (flags_fragOffset & ~(0x07 << 13));
COPY_ADVANCE(&ipProps->TTL, hdr, 1);
COPY_ADVANCE(&ipProps->Protocol, hdr, 1);
COPY_WORD_H2N_ADVANCE(&ipProps->HeaderChecksum, hdr);
COPY_DWORD_H2N_ADVANCE(&ipProps->SourceIPAddr, hdr);
COPY_DWORD_H2N_ADVANCE(&ipProps->DestIPAddr, hdr);
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);
@ -67,3 +69,19 @@ int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktProps * props) {
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) | (flags_fragOffset & ~(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);
}

View File

@ -2,11 +2,14 @@
#define ETHERLIB_IPV4_PACKET_H
#include <stdint.h>
#include "etherlib/packet_registry.h"
#include "../../packet_registry.h"
#include "../../packet_sieve.h"
#define ETH_IPv4_PACKET_CLASS (0x0800)
// IPv4 fejlécet leíró struktúra
/**
* IPv4 header structure
*/
typedef struct {
PcktPropsHeader
@ -22,7 +25,7 @@ typedef struct {
uint16_t FragmentOffset; ///< packet fragmentation offset
// 3. 32-bit
uint8_t TTL; // Time-To-Live
uint8_t TTL; ///< Time-To-Live
uint8_t Protocol; ///< Protocol
uint16_t HeaderChecksum; ///< header IP-checksum
@ -40,4 +43,11 @@ typedef struct {
*/
int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktProps * props);
/**
* Insert IPv4 header.
* @param hdr space where the header is to be inserted
* @param headers linked list of header, top is always relevant
*/
void insert_ipv4_header(uint8_t * hdr, const PcktHeaderElement * headers);
#endif //ETHERLIB_IPV4_PACKET_H

View File

@ -1,15 +1,46 @@
#include <stdbool.h>
#include "udp_packet.h"
#include "etherlib/utils.h"
#include "../../utils.h"
#include "ipv4_packet.h"
#define ETH_UDP_HEADER_SIZE (8)
typedef struct {
uint32_t sourceIpAddr;
uint32_t destIpAddr;
uint8_t zero;
uint8_t protocol;
uint16_t udpLength;
} UdpPseudoHeader;
static uint16_t udp_checksum(const UdpPseudoHeader * pseudoHeader, const uint8_t * headerPayload, uint32_t headerPayloadSize) {
uint16_t chksum = 0;
uint16_t i;
// pseudoheader
for (i = 0; i < sizeof(UdpPseudoHeader) / 2; i++) {
chksum += ~((uint16_t *)pseudoHeader)[i];
}
// UDP header and payload
for (i = 0; i < headerPayloadSize / 2; i++) {
if (i != 3) { // skip Checksum field
chksum += ~((uint16_t *) headerPayload)[i];
}
}
// pad if packet size is odd
chksum += ~((uint16_t)headerPayload[headerPayloadSize - 1] << 8);
return chksum;
}
int parse_udp(const uint8_t *hdr, uint32_t size, PcktProps * props) {
UDPProps * udpProps = (UDPProps *)props;
COPY_WORD_H2N_ADVANCE(&udpProps->SourcePort, hdr);
COPY_WORD_H2N_ADVANCE(&udpProps->DestinationPort, hdr);
COPY_WORD_H2N_ADVANCE(&udpProps->Length, hdr);
COPY_WORD_H2N_ADVANCE(&udpProps->Checksum, hdr);
UdpProps * udpProps = (UdpProps *)props;
FETCH_WORD_H2N_ADVANCE(&udpProps->SourcePort, hdr);
FETCH_WORD_H2N_ADVANCE(&udpProps->DestinationPort, hdr);
FETCH_WORD_H2N_ADVANCE(&udpProps->Length, hdr);
FETCH_WORD_H2N_ADVANCE(&udpProps->Checksum, hdr);
// common fields...
udpProps->headerSize = ETH_UDP_HEADER_SIZE;
@ -18,3 +49,19 @@ int parse_udp(const uint8_t *hdr, uint32_t size, PcktProps * props) {
return udpProps->validityOK ? 0 : -1;
}
void insert_udp_header(uint8_t *hdr, const PcktHeaderElement *headers) {
UdpProps * udpProps = (UdpProps *) &headers->props;
FILL_WORD_H2N_ADVANCE(hdr, udpProps->SourcePort);
FILL_WORD_H2N_ADVANCE(hdr, udpProps->DestinationPort);
FILL_WORD_H2N_ADVANCE(hdr, udpProps->Length);
// calculate checksum
const IPv4Props * ipProps = (IPv4Props *)&headers->prev->props;
UdpPseudoHeader ph = { ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_UDP_PACKET_CLASS, udpProps->Length };
udpProps->Checksum = udp_checksum(&ph, hdr, udpProps->Length);
FILL_WORD_H2N_ADVANCE(hdr, udpProps->Checksum);
}

View File

@ -2,12 +2,13 @@
#define ETHERLIB_UDP_PACKET_H
#include <stdint.h>
#include "etherlib/packet_registry.h"
#include "../../packet_registry.h"
#include "../../packet_sieve.h"
#define ETH_UDP_PACKET_CLASS (17)
/**
* @struct UDPProps
* @struct UdpProps
* UDP packet properties.
*/
typedef struct {
@ -17,7 +18,7 @@ typedef struct {
uint16_t DestinationPort; ///> destination port
uint16_t Length; ///> packet size
uint16_t Checksum; ///> UDP checksum
} UDPProps;
} UdpProps;
/**
* Parse raw UDP packets.
@ -28,4 +29,11 @@ typedef struct {
*/
int parse_udp(const uint8_t *hdr, uint32_t size, PcktProps * props);
/**
* Insert UDP header.
* @param hdr space where the header is to be inserted
* @param headers linked list of header, top is always relevant
*/
void insert_udp_header(uint8_t * hdr, const PcktHeaderElement * headers);
#endif //ETHERLIB_UDP_PACKET_H

14
utils.h
View File

@ -33,15 +33,23 @@
#define ERROR(...) printf(__VA_ARGS__)
#define INFO(...) printf(__VA_ARGS__)
#define MSG(...) printf(__VA_ARGS__)
#define IPv4(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24))
#define PRINT_IPv4(ip) MSG("%u.%u.%u.%u", (ip & 0xFF), ((ip >> 8) & 0xFF), ((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF))
#define ASSERT_BAD_ALIGN(p) if ((size_t)(p) & 0b11) ERROR("Bad memory alignment in function '%s' in file '%s' on line %d!\n", __func__, __FILE__, __LINE__)
#define ASSERT_NULL(p) if ((p) == NULL) ERROR("NULL in function '%s' in file '%s' on line %d!\n", __func__, __FILE__, __LINE__)
#define ALIGN(p,t) (((size_t)(p) + (sizeof(t) - 1)) & ~(sizeof(t) - 1))
#define COPY_ADVANCE(dst,src,n) memcpy((dst), (src), n), src += n
#define COPY_WORD_H2N_ADVANCE(dst,w) { uint16_t u; memcpy(&u, w, 2); u = htons(u); memcpy((dst), &u, 2); w += 2; }
#define COPY_DWORD_H2N_ADVANCE(dst,dw) { uint32_t du; memcpy(&du, dw, 4); du = htonl(du); memcpy((dst), &du, 4); dw += 4; }
#define FETCH_ADVANCE(dst,src,n) memcpy((dst), (src), n), (src) += n
#define FILL_ADVANCE(dst,src,n) memcpy((dst), (src), n), (dst) += n
#define FETCH_WORD_H2N_ADVANCE(dst,w) { uint16_t u; memcpy(&u, w, 2); u = htons(u); memcpy((dst), &u, 2); (w) += 2; }
#define FILL_WORD_H2N_ADVANCE(dst,w) { uint16_t u = htons(w); memcpy((dst), &u, 2); (dst) += 2; }
#define FETCH_DWORD_H2N_ADVANCE(dst,dw) { uint32_t du; memcpy(&du, dw, 4); du = htonl(du); memcpy((dst), &du, 4); (dw) += 4; }
#define FILL_DWORD_H2N_ADVANCE(dst,w) { uint32_t du = htonl(dw); memcpy(dst, &du, 4); (dst) += 4; }
// ------------------