Timestamping and bunch of bugfix and optimization

- Timestamping management added
- Errors due to reading uninitialized data in ARP fixed
- EthInterface reworked, incoming packet notification and payload readout separated (through which fixing concurrent access problems)
- RX and TX offloads added
- Capability to add a packet sieve layer without prior registration of specific packet class added (this makes it possible to register arbitrary EtherType connection blocks, for example)
This commit is contained in:
Wiesner András 2023-04-27 09:38:26 +02:00
parent 30af96f4c9
commit ab8d45932f
47 changed files with 537 additions and 157 deletions

View File

@ -114,7 +114,7 @@ void arpc_ask(ArpCache *arpc, ip4_addr addr) {
} }
void arpc_respond(ArpCache *arpc, const EthernetAddress hwAddr, ip4_addr ipAddr) { void arpc_respond(ArpCache *arpc, const EthernetAddress hwAddr, ip4_addr ipAddr) {
ArpProps arpProps; ArpProps arpProps = { 0 };
arpProps.HTYPE = 1; arpProps.HTYPE = 1;
arpProps.PTYPE = ETH_IPv4_PACKET_CLASS; arpProps.PTYPE = ETH_IPv4_PACKET_CLASS;

View File

@ -7,6 +7,10 @@
#include <stddef.h> #include <stddef.h>
void connb_init_defaults(ConnBlock *connb) {
// ...
}
void connb_remove(ConnBlock *connb) { void connb_remove(ConnBlock *connb) {
if (connb != NULL) { if (connb != NULL) {
packsieve_remove_layer(connb->sieveLayer); packsieve_remove_layer(connb->sieveLayer);

View File

@ -13,9 +13,14 @@ typedef int (*ConnBlockTransmitFn)(struct EthInterface_ * intf, const uint8_t *
typedef struct ConnBlock_ { typedef struct ConnBlock_ {
PcktSieve * sieve; ///< Ethernet interface PcktSieve * sieve; ///< Ethernet interface
PcktSieveLayer * sieveLayer; ///< Sieve layer PcktSieveLayer * sieveLayer; ///< Sieve layer
void * tag; ///< Arbitrary tagging
} ConnBlock; } ConnBlock;
/**
* Initialize non-mandatory fields to default values.
* @param connb
*/
void connb_init_defaults(ConnBlock * connb);
/** /**
* Remove connection block. * Remove connection block.
* @param connb pointer to existing connection block * @param connb pointer to existing connection block

View File

@ -7,6 +7,11 @@
#include <stdio.h> #include <stdio.h>
#endif #endif
#ifdef VALGRIND_DEBUG
#include <stdlib.h>
#include <stdio.h>
#endif
/** /**
* Initialize EtherLib dynamic memory management subsystem, * Initialize EtherLib dynamic memory management subsystem,
* based on heap pointer and size given in etherlib_options.h * based on heap pointer and size given in etherlib_options.h
@ -22,6 +27,8 @@ void * dynmem_alloc_(uint32_t size);
#ifdef DYNMEM_DEBUG #ifdef DYNMEM_DEBUG
#define dynmem_alloc(size) dynmem_alloc_(size); MSG("ALLOC: %d %s() in %s:%d\n", size, __FUNCTION__, __FILE__, __LINE__) #define dynmem_alloc(size) dynmem_alloc_(size); MSG("ALLOC: %d %s() in %s:%d\n", size, __FUNCTION__, __FILE__, __LINE__)
#elif defined(VALGRIND_DEBUG)
#define dynmem_alloc(size) malloc(size)
#else #else
#define dynmem_alloc(size) dynmem_alloc_(size) #define dynmem_alloc(size) dynmem_alloc_(size)
#endif #endif
@ -34,6 +41,8 @@ void dynmem_free_(void * ptr);
#ifdef DYNMEM_DEBUG #ifdef DYNMEM_DEBUG
#define dynmem_free(ptr) MSG("FREE: %s() in %s:%d\n", __FUNCTION__, __FILE__, __LINE__), dynmem_free_(ptr) #define dynmem_free(ptr) MSG("FREE: %s() in %s:%d\n", __FUNCTION__, __FILE__, __LINE__), dynmem_free_(ptr)
#elif defined(VALGRIND_DEBUG)
#define dynmem_free(p) free(p)
#else #else
#define dynmem_free(ptr) dynmem_free_(ptr) #define dynmem_free(ptr) dynmem_free_(ptr)
#endif #endif

View File

@ -6,16 +6,22 @@
#include "dynmem.h" #include "dynmem.h"
#include "utils.h" #include "utils.h"
#include "etherlib_options.h" #include "etherlib_options.h"
#include "etherlib/prefab/conn_blocks/ethernet_info.h" #include "etherlib/prefab/conn_blocks/ethernet_connblock.h"
static int ethintf_llrecv(EthIODef * io, const RawPckt * pckt) { static int ethintf_llrecv(EthIODef * io, const RawPckt * pckt) {
ethinf_receive((EthInterface *) io->tag, pckt); ethinf_receive((EthInterface *) io->tag, pckt);
return 0; return 0;
} }
static int ethintf_llrxnotify(EthIODef * io) {
ethinf_notify((EthInterface *) io->tag);
return 0;
}
static void ethintf_register(EthInterface * intf) { static void ethintf_register(EthInterface * intf) {
intf->ioDef->tag = intf; intf->ioDef->tag = intf;
intf->ioDef->llRxDone = ethintf_llrecv; intf->ioDef->llRxStore = ethintf_llrecv;
intf->ioDef->llRxNotify = ethintf_llrxnotify;
} }
// interface processing thread // interface processing thread
@ -36,11 +42,13 @@ EthInterface *ethintf_new(EthIODef * io) {
ethIntf->txQ = mq_create(ETHLIB_DEF_MQ_SIZE); ethIntf->txQ = mq_create(ETHLIB_DEF_MQ_SIZE);
ethIntf->rxQ = mq_create(ETHLIB_DEF_MQ_SIZE); ethIntf->rxQ = mq_create(ETHLIB_DEF_MQ_SIZE);
ETHLIB_OS_SEM_CREATE(&ethIntf->rxSem, ETHLIB_DEF_MQ_SIZE); ETHLIB_OS_SEM_CREATE(&ethIntf->rxSem, ETHLIB_DEF_MQ_SIZE);
ETHLIB_OS_THREAD_DEFINE(ethinf_proc_thread, ipp, osPriorityHigh, 4096, ethIntf); ETHLIB_OS_THREAD_DEFINE(ethinf_proc_thread, ethrx, osPriorityHigh, 4096, ethIntf);
ETHLIB_OS_THREAD_CREATE(ipp, ethIntf); ETHLIB_OS_THREAD_CREATE(ethrx, ethIntf);
ethIntf->ipra = ipra_new(); ethIntf->ipra = ipra_new();
ethIntf->capabilities = 0;
return ethIntf; return ethIntf;
} }
@ -48,7 +56,8 @@ static void * ethinf_proc_thread(void * param) {
EthInterface * intf = (EthInterface *) param; EthInterface * intf = (EthInterface *) param;
while (true) { while (true) {
ETHLIB_OS_SEM_WAIT(&intf->rxSem); ETHLIB_OS_SEM_WAIT(&intf->rxSem);
if (mq_avail(intf->rxQ) > 0) { intf->ioDef->llRxRead(intf->ioDef, intf->rxQ); // read packets
while (mq_avail(intf->rxQ) > 0) {
RawPckt rawPckt = mq_top(intf->rxQ); RawPckt rawPckt = mq_top(intf->rxQ);
mq_pop(intf->rxQ); mq_pop(intf->rxQ);
packsieve_input(&intf->sieve, &rawPckt); packsieve_input(&intf->sieve, &rawPckt);
@ -59,9 +68,7 @@ static void * ethinf_proc_thread(void * param) {
void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt) { void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt) {
bool pushOK = mq_push(intf->rxQ, rawPckt); bool pushOK = mq_push(intf->rxQ, rawPckt);
if (pushOK) { if (!pushOK) {
ETHLIB_OS_SEM_POST(&intf->rxSem);
} else {
dynmem_free(rawPckt->payload); dynmem_free(rawPckt->payload);
ERROR("Input queue full, packet dropped!\n"); ERROR("Input queue full, packet dropped!\n");
} }
@ -72,3 +79,11 @@ void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt) {
intf->ioDef->llTxTrigger(intf->ioDef, intf->txQ); intf->ioDef->llTxTrigger(intf->ioDef, intf->txQ);
} }
void ethinf_notify(EthInterface *intf) {
ETHLIB_OS_SEM_POST(&intf->rxSem);
}
void ethinf_set_capabilities(EthInterface *intf, uint32_t cap) {
intf->capabilities = cap;
}

View File

@ -17,12 +17,27 @@ typedef struct EthIODef_ {
int (*llTxTrigger)(struct EthIODef_ * io, MsgQueue * mq); ///< Function pointer to low-level transmit function trigger int (*llTxTrigger)(struct EthIODef_ * io, MsgQueue * mq); ///< Function pointer to low-level transmit function trigger
int (*llTxDone)(struct EthIODef_ * io, const RawPckt * rawPckt); ///< Transmission done (interrupt) callback int (*llTxDone)(struct EthIODef_ * io, const RawPckt * rawPckt); ///< Transmission done (interrupt) callback
int (*llLinkChg)(struct EthIODef_ * io, int linkState); ///< Link change interrupt int (*llLinkChg)(struct EthIODef_ * io, int linkState); ///< Link change interrupt
int (*llRxDone)(struct EthIODef_ * io, const RawPckt * rawPckt); ///< Receive done callback int (*llRxStore)(struct EthIODef_ * io, const RawPckt * rawPckt); ///< Receive done callback
int (*llError)(struct EthIODef_ * io, int error); ///< Low-level error interrupt int (*llError)(struct EthIODef_ * io, int error); ///< Low-level error interrupt
int (*llRxRead)(struct EthIODef_ * io, MsgQueue * mq); ///< Read received packets
int (*llRxNotify)(struct EthIODef_ * io); ///< Notify of received packets
void * tag; ///< Some arbitrary tagging void * tag; ///< Some arbitrary tagging
} EthIODef; } EthIODef;
/**
* Ethernet interface capabilities
*/
typedef enum {
ETHINF_CAP_NONE = 0,
ETHINF_CAP_TX_CRC_OFFLOAD = 1,
ETHINF_CAP_TX_IPCHKSUM_OFFLOAD = 2,
ETHINF_CAP_TX_TCPUDPCHKSUM_OFFLOAD = 4,
ETHINF_CAP_RX_IPCHKSUM_OFFLOAD = 8,
ETHINF_CAP_RX_TCPUDPCHKSUM_OFFLOAD = 16,
ETHINF_CAP_ALL_RX_TX_CHECKSUM_OFFLOADS = 0b11111,
} EthIntfCap;
/** /**
* Ethernet interface representation. * Ethernet interface representation.
*/ */
@ -30,6 +45,7 @@ typedef struct EthInterface_ {
PcktSieve sieve; ///< Packet sieve PcktSieve sieve; ///< Packet sieve
EthIODef * ioDef; ///< Low-level IO definitions EthIODef * ioDef; ///< Low-level IO definitions
EthernetAddress mac; ///< Ethernet address EthernetAddress mac; ///< Ethernet address
uint32_t capabilities; ///< Ethernet interface capabilities
ip4_addr ip; ///< IP address ip4_addr ip; ///< IP address
ip4_addr router; ///< Router IP address ip4_addr router; ///< Router IP address
ip4_addr netmask; ///< Subnet mask ip4_addr netmask; ///< Subnet mask
@ -55,9 +71,23 @@ EthInterface *ethintf_new(EthIODef * io);
*/ */
void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt); void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt);
/**
* Notify interface of a received, buffered packet, which needs transferred
* from the low level Ethernet-driver.
* @param intf Pointer to Ethernet-interface
*/
void ethinf_notify(EthInterface *intf);
/** /**
* Transmit packet. * Transmit packet.
*/ */
void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt); void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt);
/**
* Set interface capabilities.
* @param intf pointer to Ethernet interface
* @param cap OR-ed bitfield of capabilities
*/
void ethinf_set_capabilities(EthInterface *intf, uint32_t cap);
#endif //ETHERLIB_ETH_INTERFACE_H #endif //ETHERLIB_ETH_INTERFACE_H

14
etherlib.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef ETHERLIB_ETHERLIB_H
#define ETHERLIB_ETHERLIB_H
#include "prefab/prefab.h"
#include "global_state.h"
#include "timestamping.h"
#include "utils.h"
// TODO group these includes..
#include "prefab/conn_blocks/igmp_connblock.h"
#include "prefab/conn_blocks/udp_connblock.h"
#include "prefab/conn_blocks/custom_ethertype_connblock.h"
#endif //ETHERLIB_ETHERLIB_H

View File

@ -92,3 +92,7 @@ void close_connection(cbd d) {
connb_remove(&connBlock); // remove connection block connb_remove(&connBlock); // remove connection block
} }
EthInterface *get_default_interface() {
return E.ethIntf;
}

View File

@ -35,4 +35,10 @@ void process_raw_packet(const uint8_t * data, uint32_t size);
*/ */
void close_connection(cbd d); void close_connection(cbd d);
/**
* Get default Ethernet interface
* @return pointer to default Ethernet interface
*/
EthInterface * get_default_interface();
#endif //ETHERLIB_GLOBAL_STATE_H #endif //ETHERLIB_GLOBAL_STATE_H

View File

@ -137,6 +137,10 @@ static void mp_join_free_blocks(MP *mp) {
} }
void mp_free(MP *mp, const uint8_t *p) { void mp_free(MP *mp, const uint8_t *p) {
if (p == NULL) { // don't do anything with a NULL pointer
return;
}
// look for registry record // look for registry record
bool success = false; bool success = false;
MPAllocRecord *recIter = mp->blockRegistry; MPAllocRecord *recIter = mp->blockRegistry;

View File

@ -10,7 +10,7 @@
#include <stdio.h> #include <stdio.h>
MsgQueue *mq_create(uint32_t size) { MsgQueue *mq_create(uint32_t size) {
MsgQueue * mq = (MsgQueue *) dynmem_alloc(sizeof(MsgQueue) + size * sizeof(RawPckt)); MsgQueue *mq = (MsgQueue *) dynmem_alloc(sizeof(MsgQueue) + size * sizeof(RawPckt));
mq->size = size; mq->size = size;
mq->readIdx = 0; mq->readIdx = 0;
mq->writeIdx = 0; mq->writeIdx = 0;
@ -19,19 +19,23 @@ MsgQueue *mq_create(uint32_t size) {
return mq; return mq;
} }
void mq_clear(MsgQueue * mq) { void mq_clear(MsgQueue *mq) {
mq->readIdx = 0; mq->readIdx = 0;
mq->writeIdx = 0; mq->writeIdx = 0;
memset(mq->pckts, 0, mq->size * sizeof(RawPckt)); memset(mq->pckts, 0, mq->size * sizeof(RawPckt));
} }
uint32_t mq_avail(const MsgQueue * mq) { uint32_t mq_avail(const MsgQueue *mq) {
return mq->writeIdx - mq->readIdx; int32_t delta = (int32_t) (mq->writeIdx - mq->readIdx);
if (delta < 0) { // modulo...
delta += (int32_t) mq->size;
}
return delta;
} }
#define MQ_NEXT(size,current) (((current)+1)%(size)) #define MQ_NEXT(size, current) (((current)+1)%(size))
bool mq_push(MsgQueue * mq, const RawPckt * raw) { bool mq_push(MsgQueue *mq, const RawPckt *raw) {
if (MQ_NEXT(mq->size, mq->writeIdx) == mq->readIdx) { // cannot push, queue is full if (MQ_NEXT(mq->size, mq->writeIdx) == mq->readIdx) { // cannot push, queue is full
return false; return false;
} }
@ -45,11 +49,11 @@ bool mq_push(MsgQueue * mq, const RawPckt * raw) {
return true; return true;
} }
RawPckt mq_top(MsgQueue * mq) { RawPckt mq_top(MsgQueue *mq) {
return mq->pckts[mq->readIdx]; return mq->pckts[mq->readIdx];
} }
void mq_pop(MsgQueue * mq) { void mq_pop(MsgQueue *mq) {
if (mq_avail(mq) > 0) { // if there's anything to pop if (mq_avail(mq) > 0) { // if there's anything to pop
mq->readIdx = MQ_NEXT(mq->size, mq->readIdx); mq->readIdx = MQ_NEXT(mq->size, mq->readIdx);
} }

View File

@ -10,8 +10,16 @@
typedef struct { typedef struct {
uint8_t * payload; ///> Pointer to raw packet payload. uint8_t * payload; ///> Pointer to raw packet payload.
uint32_t size; ///> Raw packet size. uint32_t size; ///> Raw packet size.
union {
struct {
uint32_t time_s; ///> Timestamp seconds field uint32_t time_s; ///> Timestamp seconds field
uint32_t time_ns; ///> Timestamp nanoseconds field uint32_t time_ns; ///> Timestamp nanoseconds field
} rx;
struct {
void(*txTsCb)(uint32_t ts_s, uint32_t ts_ns, uint32_t tag); ///> Transmit timestamp callback pointer
uint32_t arg; ///> User-defined argument
} tx;
} ext; ///> Extensions
} RawPckt; } RawPckt;
struct PcktHeaderElement_; struct PcktHeaderElement_;
@ -23,7 +31,7 @@ struct PcktHeaderElement_;
* Fields have been reordered so that fields are aligned. * Fields have been reordered so that fields are aligned.
*/ */
typedef struct { typedef struct {
uint64_t time_s; ///< Timestamp seconds part. uint64_t time_s; ///< Timestamp seconds part
uint32_t time_ns; ///< Timestamp nanoseconds part. uint32_t time_ns; ///< Timestamp nanoseconds part.
struct PcktHeaderElement_ * header; ///< Pointer to packet header. Points to the innermost header struct PcktHeaderElement_ * header; ///< Pointer to packet header. Points to the innermost header
uint8_t * payload; ///< Pointer to (innermost) payload. uint8_t * payload; ///< Pointer to (innermost) payload.

View File

@ -28,7 +28,7 @@ struct PcktHeaderElement_;
* @param hdr buffer to insert header into * @param hdr buffer to insert header into
* @param pcktHdrLe linked list of packet headers * @param pcktHdrLe linked list of packet headers
*/ */
typedef void (*PcktHeaderInsertFn)(uint8_t * hdr, const struct PcktHeaderElement_ * pcktHdrLe); typedef void (*PcktHeaderInsertFn)(uint8_t * hdr, const struct PcktHeaderElement_ * pcktHdrLe, struct EthInterface_ * intf);
#define PcktPropsHeader \ #define PcktPropsHeader \
PcktHeaderInsertFn hdrInsFn; /**< Header insert function pointer (used only on transmission) */ \ PcktHeaderInsertFn hdrInsFn; /**< Header insert function pointer (used only on transmission) */ \

View File

@ -16,8 +16,8 @@ void packfiltcond_zero(PcktSieveFilterCondition *cond) {
memset(cond, 0, sizeof(PcktSieveFilterCondition)); memset(cond, 0, sizeof(PcktSieveFilterCondition));
} }
PcktSieve *packsieve_new(EthInterface * intf) { PcktSieve* packsieve_new(EthInterface *intf) {
PcktSieve *sieve = (PcktSieve *) dynmem_alloc(sizeof(PcktSieve)); PcktSieve *sieve = (PcktSieve*) dynmem_alloc(sizeof(PcktSieve));
ASSERT_NULL(sieve); ASSERT_NULL(sieve);
memset(&sieve->layer0, 0, sizeof(PcktSieveLayer)); // clear layer0 data memset(&sieve->layer0, 0, sizeof(PcktSieveLayer)); // clear layer0 data
sieve->intf = intf; sieve->intf = intf;
@ -30,7 +30,7 @@ void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
uint32_t size = rawPckt->size; uint32_t size = rawPckt->size;
bool mrd = true; // 'Must Release Data': at the end of processing not only release headers but data buffer as well bool mrd = true; // 'Must Release Data': at the end of processing not only release headers but data buffer as well
restart:; restart: ;
// process payload, fetch packet class etc. // process payload, fetch packet class etc.
uint16_t ownClass = 0, containerClass = 0; // Ethernet... uint16_t ownClass = 0, containerClass = 0; // Ethernet...
uint16_t offset = 0; uint16_t offset = 0;
@ -48,16 +48,14 @@ void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
uint32_t hdrSize = ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + cdesc->propertySize; uint32_t hdrSize = ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + cdesc->propertySize;
// look for possible former allocated cache area // look for possible former allocated cache area
PcktHeaderElement *header = NULL; PcktHeaderElement *header = NULL;
if (cdesc->cacheSize <= hdrSize) { // allocate cache area if (cdesc->cacheSize < hdrSize) { // allocate cache area if previously allocated area is too small
if (cdesc->cacheArea != NULL) { dynmem_free(cdesc->cacheArea); // does nothing if cacheArea is NULL
dynmem_free(cdesc->cacheArea); cdesc->cacheArea = (uint8_t*) dynmem_alloc(hdrSize);
}
cdesc->cacheArea = (uint8_t *)dynmem_alloc(hdrSize);
ASSERT_NULL(cdesc->cacheArea); ASSERT_NULL(cdesc->cacheArea);
cdesc->cacheSize = hdrSize; cdesc->cacheSize = hdrSize; // retain cache size
} }
header = (PcktHeaderElement *)cdesc->cacheArea; header = (PcktHeaderElement*) cdesc->cacheArea;
memset(header, 0, hdrSize); memset(header, 0, hdrSize);
header->props.ownPacketClass = ownClass; header->props.ownPacketClass = ownClass;
@ -81,7 +79,8 @@ void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
mrd = pb.b; mrd = pb.b;
// NO BREAK! // NO BREAK!
case PROC_FN_RET_ABORT: case PROC_FN_RET_ABORT:
goto header_release; // GOTO :D! goto header_release;
// GOTO :D!
break; break;
case PROC_FN_RET_OK: case PROC_FN_RET_OK:
default: default:
@ -102,17 +101,22 @@ void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
lastHeader = header; lastHeader = header;
} while ((ownClass != 0) && lastHeader->props.validityOK); } while ((ownClass != 0) && lastHeader->props.validityOK);
if (lastHeader == NULL) { // if found nothing, don't attempt to process
goto data_release;
}
lastHeader->next = NULL; lastHeader->next = NULL;
// ------------------------------------ // ------------------------------------
if (!lastHeader->props.validityOK) { // if packet is not valid, then drop if (!lastHeader->props.validityOK) { // if packet is not valid, then drop
goto header_release; // GOTO here! goto header_release;
// GOTO here!
} }
Pckt packet; Pckt packet;
packet.time_s = rawPckt->time_s; packet.time_s = rawPckt->ext.rx.time_s;
packet.time_ns = rawPckt->time_ns; packet.time_ns = rawPckt->ext.rx.time_ns;
// lookup headers in the sieve // lookup headers in the sieve
const PcktHeaderElement *headerIter = outermostHeader; const PcktHeaderElement *headerIter = outermostHeader;
@ -125,7 +129,10 @@ void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
found |= nodeIter->matchAny || nodeIter->filtFn(&nodeIter->filtCond, &headerIter->props, &headerIter->next->props, sieve->intf); // specific or general match found |= nodeIter->matchAny || nodeIter->filtFn(&nodeIter->filtCond, &headerIter->props, &headerIter->next->props, sieve->intf); // specific or general match
if (found) { if (found) {
layer = nodeIter; // advance in the sieve tree layer = nodeIter; // advance in the sieve tree
const PcktHeaderElement *containedHeader = headerIter->next; // advance on headers PcktHeaderElement *containedHeader = headerIter;
if (headerIter->next != NULL) {
containedHeader = containedHeader->next; // advance on headers
}
if (layer->cbFn != NULL) { // if defined, invoke layer callback function if (layer->cbFn != NULL) { // if defined, invoke layer callback function
offset = containedHeader->props.accumulatedOffset; // accumulated offset + own header size offset = containedHeader->props.accumulatedOffset; // accumulated offset + own header size
packet.header = containedHeader; packet.header = containedHeader;
@ -156,9 +163,8 @@ void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
// INFO("Packet headers not fully processed!\n"); // INFO("Packet headers not fully processed!\n");
// } // }
// release header chain blocks // release header chain blocks
header_release:; // empty line, solely for label placement header_release: ; // empty line, solely for label placement
// PcktHeaderElement *iter = outermostHeader; // PcktHeaderElement *iter = outermostHeader;
// while (iter != NULL) { // while (iter != NULL) {
// PcktHeaderElement *next = iter->next; // PcktHeaderElement *next = iter->next;
@ -168,13 +174,14 @@ void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
if (procRet == PROC_FN_RET_REPRST) { // if a restart was requested, then run everything again! if (procRet == PROC_FN_RET_REPRST) { // if a restart was requested, then run everything again!
goto restart; goto restart;
} }
data_release:; data_release: ;
if (mrd) { if (mrd) {
dynmem_free(data); dynmem_free(data);
} }
} }
PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, bool matchAny, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag, uint16_t pcktClass) { PcktSieveLayer* packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, bool matchAny, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag,
uint16_t pcktClass) {
// search for matching layer // search for matching layer
PcktSieveLayer *nodeIter = parent->nodes; PcktSieveLayer *nodeIter = parent->nodes;
bool alreadyExists = false; bool alreadyExists = false;
@ -190,7 +197,7 @@ PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilte
if (alreadyExists) { if (alreadyExists) {
return nodeIter; // OK return nodeIter; // OK
} else { // if allocation of a new layer is required } else { // if allocation of a new layer is required
PcktSieveLayer *layer = (PcktSieveLayer *) dynmem_alloc(sizeof(PcktSieveLayer)); PcktSieveLayer *layer = (PcktSieveLayer*) dynmem_alloc(sizeof(PcktSieveLayer));
ASSERT_NULL(layer); ASSERT_NULL(layer);
PcktSieveLayer *oldListFirst = parent->nodes; PcktSieveLayer *oldListFirst = parent->nodes;
@ -221,6 +228,7 @@ PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilte
layer->cbFn = cbFn; layer->cbFn = cbFn;
layer->tag = tag; layer->tag = tag;
layer->connBReportFn = NULL; layer->connBReportFn = NULL;
layer->txTsCb = NULL;
return layer; return layer;
} }
} }
@ -260,10 +268,10 @@ bool packsieve_remove_layer(PcktSieveLayer *layer) {
#define ETH_SIEVE_LAYER_INDENT_PER_LEVEL (4) #define ETH_SIEVE_LAYER_INDENT_PER_LEVEL (4)
void packsieve_report(const PcktSieve * sieve, const PcktSieveLayer *layer, uint32_t indent) { void packsieve_report(const PcktSieve *sieve, const PcktSieveLayer *layer, uint32_t indent) {
if (layer->connBReportFn != NULL) { if (layer->connBReportFn != NULL) {
INFO("%*c└─┤", indent, ' '); INFO("%*c└─┤", indent, ' ');
const ConnBlock connBlock = { sieve, layer, NULL }; // tag not required ConnBlock connBlock = { sieve, layer }; // tag not required
layer->connBReportFn(&connBlock); layer->connBReportFn(&connBlock);
INFO("├───\n"); INFO("├───\n");
} else { } else {
@ -276,11 +284,11 @@ void packsieve_report(const PcktSieve * sieve, const PcktSieveLayer *layer, uint
} }
} }
void packsieve_layer_info(const PcktSieve * sieve, const PcktSieveLayer * layer) { void packsieve_layer_info(const PcktSieve *sieve, const PcktSieveLayer *layer) {
const PcktSieveLayer *iter = layer; const PcktSieveLayer *iter = layer;
while (iter != NULL) { // climb up to the top in the sieve tree while (iter != NULL) { // climb up to the top in the sieve tree
if (iter->connBReportFn != NULL) { if (iter->connBReportFn != NULL) {
const ConnBlock connBlock = {sieve, iter, NULL}; // tag not required ConnBlock connBlock = { sieve, iter }; // tag not required
iter->connBReportFn(&connBlock); iter->connBReportFn(&connBlock);
} else { } else {
INFO("[%d]", layer->packetClass); INFO("[%d]", layer->packetClass);

View File

@ -10,7 +10,7 @@
* Packet header information. * Packet header information.
*/ */
typedef struct PcktHeaderElement_ { typedef struct PcktHeaderElement_ {
struct PcktHeaderElement_ * next, * prev; ///< Next and previous header in the linked list struct PcktHeaderElement_ *next, *prev; ///< Next and previous header in the linked list
PcktProps props; ///< Properties (allocated to appropriate size) PcktProps props; ///< Properties (allocated to appropriate size)
} PcktHeaderElement; } PcktHeaderElement;
@ -18,7 +18,7 @@ typedef struct PcktHeaderElement_ {
* Free chain of packet header. List is auto-rewound. * Free chain of packet header. List is auto-rewound.
* @param hdr pointer to header chain element * @param hdr pointer to header chain element
*/ */
void pckthdr_chain_free(PcktHeaderElement * hdr); void pckthdr_chain_free(PcktHeaderElement *hdr);
#define ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE (2 * sizeof(PcktHeaderElement *)) #define ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE (2 * sizeof(PcktHeaderElement *))
@ -42,25 +42,25 @@ typedef union {
* @param c2 condition 2 * @param c2 condition 2
* @return true if cond1 matches cond2, otherwise false * @return true if cond1 matches cond2, otherwise false
*/ */
bool packfiltcond_cmp(const PcktSieveFilterCondition * c1, const PcktSieveFilterCondition * c2); bool packfiltcond_cmp(const PcktSieveFilterCondition *c1, const PcktSieveFilterCondition *c2);
/** /**
* Clear packet filter condition structure. * Clear packet filter condition structure.
* @param cond pointer to existing filter condition structure * @param cond pointer to existing filter condition structure
*/ */
void packfiltcond_zero(PcktSieveFilterCondition * cond); void packfiltcond_zero(PcktSieveFilterCondition *cond);
struct EthInterface_; struct EthInterface_;
/** /**
* Sieve filter function type. * Sieve filter function type.
*/ */
typedef bool (*SieveFilterFn)(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps, struct EthInterface_ * intf); typedef bool (*SieveFilterFn)(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, struct EthInterface_ *intf);
struct PcktSieveLayer_; struct PcktSieveLayer_;
typedef union { typedef union {
void * p; void *p;
uint32_t u; uint32_t u;
} PcktSieveLayerTag; } PcktSieveLayerTag;
@ -70,14 +70,15 @@ typedef union {
/** /**
* Callback function type for packet sieve match. * Callback function type for packet sieve match.
*/ */
typedef int (*SieveCallBackFn)(const Pckt * pckt, PcktSieveLayerTag tag); typedef int (*SieveCallBackFn)(const Pckt *pckt, PcktSieveLayerTag tag);
/** /**
* Callback function for printing connblock report. * Callback function for printing connblock report.
*/ */
struct ConnBlock_; struct ConnBlock_;
typedef void (*ConnBlockReportFn)(const struct ConnBlock_ * connBlock); typedef void (*ConnBlockReportFn)(const struct ConnBlock_ *connBlock);
typedef void(*TxTimeStampCBFn)(uint32_t ts_s, uint32_t ts_ns, uint32_t tag);
#define PCKT_SIEVE_INFOTAG_LEN (24) #define PCKT_SIEVE_INFOTAG_LEN (24)
@ -91,9 +92,10 @@ typedef struct PcktSieveLayer_ {
SieveFilterFn filtFn; ///< Filter function pointer SieveFilterFn filtFn; ///< Filter function pointer
SieveCallBackFn cbFn; ///< Associated callback function SieveCallBackFn cbFn; ///< Associated callback function
PcktSieveLayerTag tag; ///< Layer tag (arbitrary information) PcktSieveLayerTag tag; ///< Layer tag (arbitrary information)
struct PcktSieveLayer_ * parent; ///< Pointer to parent node in the sieve tree TxTimeStampCBFn txTsCb; ///< Transmit timestamp callback pointer
struct PcktSieveLayer_ * next, * prev; ///< Next and previous sieve layer on the same level struct PcktSieveLayer_ *parent; ///< Pointer to parent node in the sieve tree
struct PcktSieveLayer_ * nodes; ///< Subnodes in the sieve tree struct PcktSieveLayer_ *next, *prev; ///< Next and previous sieve layer on the same level
struct PcktSieveLayer_ *nodes; ///< Subnodes in the sieve tree
ConnBlockReportFn connBReportFn; ///< Connection block report function pointer ConnBlockReportFn connBReportFn; ///< Connection block report function pointer
} PcktSieveLayer; } PcktSieveLayer;
@ -102,14 +104,14 @@ typedef struct PcktSieveLayer_ {
*/ */
typedef struct PcktSieve_ { typedef struct PcktSieve_ {
PcktSieveLayer layer0; ///< Top of sieve tree PcktSieveLayer layer0; ///< Top of sieve tree
struct EthInterface_ * intf; ///< Ethernet interface struct EthInterface_ *intf; ///< Ethernet interface
} PcktSieve; } PcktSieve;
/** /**
* Create new packet sieve. * Create new packet sieve.
* @return pointer to packet sieve object or NULL on failure * @return pointer to packet sieve object or NULL on failure
*/ */
PcktSieve * packsieve_new(); PcktSieve *packsieve_new();
/** /**
* Process packet with packet sieve. * Process packet with packet sieve.
@ -136,7 +138,7 @@ PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilte
* Remove sieve layer from packet sieve. * Remove sieve layer from packet sieve.
* @param layer Layer to remove and deallocate * @param layer Layer to remove and deallocate
*/ */
bool packsieve_remove_layer(PcktSieveLayer * layer); bool packsieve_remove_layer(PcktSieveLayer *layer);
/** /**
* Recursively report layer structure on terminal. * Recursively report layer structure on terminal.
@ -144,7 +146,7 @@ bool packsieve_remove_layer(PcktSieveLayer * layer);
* @param layer pointer to existing layer * @param layer pointer to existing layer
* @param indent sub-tree indentation * @param indent sub-tree indentation
*/ */
void packsieve_report(const PcktSieve * sieve, const PcktSieveLayer *layer, uint32_t indent); void packsieve_report(const PcktSieve *sieve, const PcktSieveLayer *layer, uint32_t indent);
#define packsieve_report_full(sieve) packsieve_report((sieve), &(sieve)->layer0, 0) #define packsieve_report_full(sieve) packsieve_report((sieve), &(sieve)->layer0, 0)
@ -153,6 +155,6 @@ void packsieve_report(const PcktSieve * sieve, const PcktSieveLayer *layer, uint
* @param sieve pointer to packet sieve structure * @param sieve pointer to packet sieve structure
* @param layer pointer to an existing layer * @param layer pointer to an existing layer
*/ */
void packsieve_layer_info(const PcktSieve * sieve, const PcktSieveLayer * layer); void packsieve_layer_info(const PcktSieve *sieve, const PcktSieveLayer *layer);
#endif //ETHERLIB_PACKET_SIEVE_H #endif //ETHERLIB_PACKET_SIEVE_H

View File

@ -10,7 +10,7 @@
#include "global_state.h" #include "global_state.h"
#include "utils.h" #include "utils.h"
int pckt_assemble(RawPckt *raw, Pckt *cooked) { int pckt_assemble(RawPckt *raw, Pckt *cooked, EthInterface *intf) {
// calculate frame size // calculate frame size
uint16_t frameSize = 0; uint16_t frameSize = 0;
uint16_t headerSize = 0; uint16_t headerSize = 0;
@ -27,7 +27,11 @@ int pckt_assemble(RawPckt *raw, Pckt *cooked) {
lastHdr = hdrIter; lastHdr = hdrIter;
hdrIter = hdrIter->next; hdrIter = hdrIter->next;
} }
frameSize = headerSize + cooked->payloadSize + 4; // header + payload + CRC32 checksum area frameSize = headerSize + cooked->payloadSize;// + 4; // header + payload
bool computeCRC = !(intf->capabilities & ETHINF_CAP_TX_CRC_OFFLOAD);
if (computeCRC) { // + CRC32 checksum area if needed
frameSize += 4;
}
// calculate padding size // calculate padding size
uint16_t padding = (frameSize < ETH_FRAME_MIN_SIZE) ? (ETH_FRAME_MIN_SIZE - frameSize) : 0; uint16_t padding = (frameSize < ETH_FRAME_MIN_SIZE) ? (ETH_FRAME_MIN_SIZE - frameSize) : 0;
@ -58,7 +62,7 @@ int pckt_assemble(RawPckt *raw, Pckt *cooked) {
} }
while (hdrIter != NULL) { while (hdrIter != NULL) {
hdrIter->props.hdrInsFn(headerInsPtr, hdrIter); // insert header hdrIter->props.hdrInsFn(headerInsPtr, hdrIter, intf); // insert header
hdrIter = hdrIter->prev; // step to previous header hdrIter = hdrIter->prev; // step to previous header
if (hdrIter != NULL) { if (hdrIter != NULL) {
headerInsPtr -= hdrIter->props.headerSize; // advance data pointer headerInsPtr -= hdrIter->props.headerSize; // advance data pointer
@ -69,9 +73,14 @@ int pckt_assemble(RawPckt *raw, Pckt *cooked) {
} }
} }
// insert CRC32 // insert CRC32 if interface is not capable of inserting CRC
if (computeCRC) {
uint32_t crc = crc32(raw->payload, frameSize - 4); uint32_t crc = crc32(raw->payload, frameSize - 4);
memcpy(raw->payload + frameSize - 4, (const uint8_t *)&crc, 4); memcpy(raw->payload + frameSize - 4, (const uint8_t *)&crc, 4);
}
// turn off TX timestamping by default
raw->ext.tx.txTsCb = NULL;
return 0; return 0;
} }

View File

@ -13,6 +13,6 @@ struct EthInterface_;
* @param cooked packet information and headers * @param cooked packet information and headers
* @return 0 on success OR -1 on failure * @return 0 on success OR -1 on failure
*/ */
int pckt_assemble(RawPckt *raw, Pckt *cooked); int pckt_assemble(RawPckt *raw, Pckt *cooked, struct EthInterface_ *intf);
#endif //ETHERLIB_PCKT_ASSEMBLER_H #endif //ETHERLIB_PCKT_ASSEMBLER_H

View File

@ -14,6 +14,7 @@ static bool filtArp(const PcktSieveFilterCondition * filtCond, const PcktProps *
ConnBlock arp_new_connblock(EthInterface * intf, SieveCallBackFn cb) { ConnBlock arp_new_connblock(EthInterface * intf, SieveCallBackFn cb) {
ConnBlock arpConnB; // create ARP connblock ConnBlock arpConnB; // create ARP connblock
connb_init_defaults(&arpConnB);
PcktSieveFilterCondition filtCond; PcktSieveFilterCondition filtCond;
packfiltcond_zero(&filtCond); packfiltcond_zero(&filtCond);
@ -53,12 +54,13 @@ void arp_send(const ConnBlock * connBlock, const ArpProps * props) {
uint32_t txHeaderSize = ETH_ETHERNET_HEADER_SIZE + ETH_ARP_HEADER_SIZE; uint32_t txHeaderSize = ETH_ETHERNET_HEADER_SIZE + ETH_ARP_HEADER_SIZE;
uint32_t txBufSize = MAX(txHeaderSize + 4, 60); uint32_t txBufSize = MAX(txHeaderSize + 4, 60);
uint8_t * txBuf = dynmem_alloc(txBufSize); uint8_t * txBuf = dynmem_alloc(txBufSize);
memset(txBuf, 0, txBufSize);
// insert Ethernet header // insert Ethernet header
insert_ethernet_header(txBuf, ethHeader); insert_ethernet_header(txBuf, ethHeader, NULL);
// insert ARP header // insert ARP header
insert_arp_header(txBuf + ETH_ETHERNET_HEADER_SIZE, arpHeader); insert_arp_header(txBuf + ETH_ETHERNET_HEADER_SIZE, arpHeader, NULL);
// release headers // release headers
dynmem_free(arpHeader); dynmem_free(arpHeader);
@ -72,8 +74,7 @@ void arp_send(const ConnBlock * connBlock, const ArpProps * props) {
RawPckt rpckt; RawPckt rpckt;
rpckt.size = txBufSize; rpckt.size = txBufSize;
rpckt.payload = txBuf; rpckt.payload = txBuf;
rpckt.time_s = 0; rpckt.ext.tx.txTsCb = NULL;
rpckt.time_ns = 0;
ethinf_transmit(connBlock->sieve->intf, &rpckt); ethinf_transmit(connBlock->sieve->intf, &rpckt);
// release transmit buffer // release transmit buffer

View File

@ -0,0 +1,92 @@
//
// Created by epagris on 2023.04.25..
//
#include "custom_ethertype_connblock.h"
#include "../../eth_interface.h"
#include "../../utils.h"
#include "../../dynmem.h"
#include "../../global_state.h"
#include "etherlib/pckt_assembler.h"
static bool filtCET(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface *intf) {
EthernetProps *ethProps = (EthernetProps *) contProps;
//MSG("FILT! %X %X\n", ethProps->length_type, ETHERTYPE_FROM_FILTCOND(filtCond));
return ethProps->length_type == ETHERTYPE_FROM_FILTCOND(filtCond);
}
cbd cet_new_connblock(struct EthInterface_ *intf, uint16_t etherType, SieveCallBackFn cbFn) {
ConnBlock cetConnB;
connb_init_defaults(&cetConnB);
PcktSieveFilterCondition filtCond;
packfiltcond_zero(&filtCond);
ETHERTYPE_TO_FILTCOND(&filtCond, etherType);
PcktSieveLayerTag tag;
tag.u = 0;
cetConnB.sieveLayer = packsieve_new_layer(&intf->sieve.layer0, &filtCond, false, filtCET, cbFn, tag, etherType);
ASSERT_NULL(cetConnB.sieveLayer);
cetConnB.sieveLayer->connBReportFn = cet_print_report;
cetConnB.sieve = &intf->sieve;
// store connection block to CBDT
cbd d = cbdt_alloc_new(E.cbdt, &cetConnB);
if (d == CBDT_ERR) { // on error free everything we have allocated before
packsieve_remove_layer(cetConnB.sieveLayer);
}
return d;
}
int cet_send(cbd d, uint8_t *dest, const uint8_t *data, uint16_t size) {
return cet_send_arg(d, dest, data, size, 0);
}
int cet_send_arg(cbd d, uint8_t *dest, const uint8_t *data, uint16_t size, uint32_t arg) {
ConnBlock connBlock;
if (!cbdt_get_connection_block(E.cbdt, d, &connBlock)) {
ERROR("Invalid CBD descriptor: '%d'!\n", d);
return 0;
}
PcktHeaderElement *ethHeader = ALLOC_HEADER_ELEMENT(EthernetProps);
ethHeader->next = NULL;
ethHeader->prev = NULL;
EthernetProps *ethProps = HEADER_FETCH_PROPS(EthernetProps, ethHeader);
ethProps->length_type = ETHERTYPE_FROM_FILTCOND(&connBlock.sieveLayer->filtCond);
memcpy(ethProps->destAddr, dest, ETH_HW_ADDR_LEN);
memcpy(ethProps->sourceAddr, connBlock.sieve->intf->mac, ETH_HW_ADDR_LEN);
ethProps->hdrInsFn = insert_ethernet_header;
ethProps->headerSize = ETH_ETHERNET_HEADER_SIZE;
Pckt cooked;
cooked.payload = data;
cooked.payloadSize = size;
cooked.header = ethHeader;
// NOT FILLED FIELDS
cooked.headerSize = 0;
cooked.time_s = 0;
cooked.time_ns = 0;
RawPckt raw;
pckt_assemble(&raw, &cooked, connBlock.sieve->intf);
raw.ext.tx.arg = arg; // assign argument
raw.ext.tx.txTsCb = connBlock.sieveLayer->txTsCb; // assign with TX timestamp callback
ethinf_transmit(connBlock.sieve->intf, &raw);
release_resources:
// free headers
dynmem_free(ethHeader);
return size;
}
void cet_print_report(const ConnBlock* connBlock) {
const PcktSieveLayer * sl = connBlock->sieveLayer;
INFO("EtherType: 0x%X", ETHERTYPE_FROM_FILTCOND(&sl->filtCond));
}

View File

@ -0,0 +1,21 @@
#ifndef ETHERLIB_CUSTOM_ETHERTYPE_CONNBLOCK_H
#define ETHERLIB_CUSTOM_ETHERTYPE_CONNBLOCK_H
#include "../../connection_block.h"
#include "../../cbd_table.h"
#include "../packet_parsers/ethernet_frame.h"
#define ETHERTYPE_FROM_FILTCOND(fc) ((fc)->uw[0])
#define ETHERTYPE_TO_FILTCOND(fc,et) (((fc)->uw[0]) = (et))
struct EthInterface_;
cbd cet_new_connblock(struct EthInterface_ * intf, uint16_t etherType, SieveCallBackFn cbFn);
int cet_send_arg(cbd d, uint8_t *dest, const uint8_t *data, uint16_t size, uint32_t arg);
int cet_send(cbd d, EthernetAddress dest, const uint8_t * data, uint16_t size);
void cet_print_report(const ConnBlock* connBlock);
#endif //ETHERLIB_CUSTOM_ETHERTYPE_CONNBLOCK_H

View File

@ -2,7 +2,7 @@
// Created by epagris on 2023.01.30.. // Created by epagris on 2023.01.30..
// //
#include "ethernet_info.h" #include "ethernet_connblock.h"
#include "../../utils.h" #include "../../utils.h"
#include "../../eth_interface.h" #include "../../eth_interface.h"

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_ETHERNET_INFO_H #ifndef ETHERLIB_ETHERNET_CONNBLOCK_H
#define ETHERLIB_ETHERNET_INFO_H #define ETHERLIB_ETHERNET_CONNBLOCK_H
#include "../../connection_block.h" #include "../../connection_block.h"
@ -10,4 +10,4 @@
*/ */
void ethernet_print_report(const ConnBlock* connBlock); void ethernet_print_report(const ConnBlock* connBlock);
#endif //ETHERLIB_ETHERNET_INFO_H #endif //ETHERLIB_ETHERNET_CONNBLOCK_H

View File

@ -21,31 +21,66 @@ static int icmp_recv_cb(const Pckt * pckt, PcktSieveLayerTag tag) {
IcmpProps * icmpProps = HEADER_FETCH_PROPS(IcmpProps, pckt->header); IcmpProps * icmpProps = HEADER_FETCH_PROPS(IcmpProps, pckt->header);
EthInterface * intf = (EthInterface *) tag.p; // icmp_new_connblock() puts pointer to intf into tag field EthInterface * intf = (EthInterface *) tag.p; // icmp_new_connblock() puts pointer to intf into tag field
static PcktHeaderElement * txIcmpHdr = NULL;
static PcktHeaderElement * txIpHdr = NULL;
static PcktHeaderElement * txEthHdr = NULL;
static IcmpProps * txIcmpProps = NULL;
static IPv4Props * txIpProps = NULL;
static EthernetProps * txEthProps = NULL;
if (txIcmpHdr == NULL) {
txIcmpHdr = (PcktHeaderElement *)dynmem_alloc(ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + sizeof(IcmpProps));
txIcmpHdr->next = NULL;
txIcmpProps = HEADER_FETCH_PROPS(IcmpProps, txIcmpHdr);
}
if (txIpHdr == NULL) {
txIpHdr = (PcktHeaderElement *)dynmem_alloc(ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + sizeof(IPv4Props));
txIcmpHdr->prev = txIpHdr;
txIpHdr->next = txIcmpHdr;
txIpProps = HEADER_FETCH_PROPS(IPv4Props, txIpHdr);
}
if (txEthHdr == NULL) {
txEthHdr = (PcktHeaderElement *)dynmem_alloc(ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + sizeof(EthernetProps));
txIpHdr->prev = txEthHdr;
txEthHdr->next = txIpHdr;
txEthHdr->prev = NULL;
txEthProps = HEADER_FETCH_PROPS(EthernetProps , txEthHdr);
}
switch (icmpProps->type) { switch (icmpProps->type) {
case ICMP_MT_ECHO_REQUEST: { case ICMP_MT_ECHO_REQUEST: {
icmpProps->type = ICMP_MT_ECHO_REPLY; // replace request with reply *txIcmpProps = *icmpProps;
icmpProps->hdrInsFn = insert_icmp_header; txIcmpProps->type = ICMP_MT_ECHO_REPLY; // replace request with reply
txIcmpProps->hdrInsFn = insert_icmp_header;
// swap source an destination IP addresses // swap source an destination IP addresses
IPv4Props * iPv4Props = HEADER_FETCH_PROPS(IPv4Props, pckt->header->prev); IPv4Props * iPv4Props = HEADER_FETCH_PROPS(IPv4Props, pckt->header->prev);
ip4_addr tmpIp = iPv4Props->SourceIPAddr; *txIpProps = *iPv4Props;
iPv4Props->SourceIPAddr = iPv4Props->DestIPAddr; ip4_addr tmpIp = txIpProps->SourceIPAddr;
iPv4Props->DestIPAddr = tmpIp; txIpProps->SourceIPAddr = txIpProps->DestIPAddr;
iPv4Props->hdrInsFn = insert_ipv4_header; txIpProps->DestIPAddr = tmpIp;
txIpProps->hdrInsFn = insert_ipv4_header;
// swap Ethernet fields // swap Ethernet fields
EthernetAddress tmpEth; EthernetAddress tmpEth;
EthernetProps * ethProps = HEADER_FETCH_PROPS(EthernetProps, pckt->header->prev->prev); EthernetProps * ethProps = HEADER_FETCH_PROPS(EthernetProps, pckt->header->prev->prev);
HWACPY(tmpEth, ethProps->sourceAddr); *txEthProps = *ethProps;
HWACPY(ethProps->sourceAddr, ethProps->destAddr); HWACPY(tmpEth, txEthProps->sourceAddr);
HWACPY(ethProps->destAddr, tmpEth); HWACPY(txEthProps->sourceAddr, txEthProps->destAddr);
ethProps->hdrInsFn = insert_ethernet_header; HWACPY(txEthProps->destAddr, tmpEth);
txEthProps->hdrInsFn = insert_ethernet_header;
// payload is the same... // payload is the same...
Pckt reply;
reply.header = txEthHdr;
reply.payload = pckt->payload;
reply.payloadSize = pckt->payloadSize;
reply.headerSize = pckt->headerSize;
// assemble packet // assemble packet
RawPckt raw; RawPckt raw;
pckt_assemble(&raw, pckt); pckt_assemble(&raw, &reply, intf);
// release headers // release headers
//pckthdr_chain_free(pckt->header); //pckthdr_chain_free(pckt->header);
@ -62,6 +97,8 @@ static int icmp_recv_cb(const Pckt * pckt, PcktSieveLayerTag tag) {
ConnBlock icmp_new_connblock(EthInterface * intf) { ConnBlock icmp_new_connblock(EthInterface * intf) {
ConnBlock icmpConnB; ConnBlock icmpConnB;
connb_init_defaults(&icmpConnB);
ConnBlock ipConnB = ipv4_new_connblock(intf, IPv4_IF_ADDR, NULL); // create new IPv4 connection block ConnBlock ipConnB = ipv4_new_connblock(intf, IPv4_IF_ADDR, NULL); // create new IPv4 connection block
PcktSieveFilterCondition filtCond; PcktSieveFilterCondition filtCond;

View File

@ -19,6 +19,8 @@ static bool filtIgmp(const PcktSieveFilterCondition * filtCond, const PcktProps
ConnBlock igmp_new_connblock(struct EthInterface_ *intf) { ConnBlock igmp_new_connblock(struct EthInterface_ *intf) {
ConnBlock igmpConnB; ConnBlock igmpConnB;
connb_init_defaults(&igmpConnB);
ConnBlock ipConnB = ipv4_new_connblock(intf, IPv4_IF_ADDR, NULL); // create new IPv4 connection block ConnBlock ipConnB = ipv4_new_connblock(intf, IPv4_IF_ADDR, NULL); // create new IPv4 connection block
PcktSieveFilterCondition filtCond; PcktSieveFilterCondition filtCond;
@ -87,7 +89,7 @@ static void igmp_send(ConnBlock * connBlock, ip4_addr ga, int mt) {
cooked.time_ns = 0; cooked.time_ns = 0;
RawPckt raw; RawPckt raw;
pckt_assemble(&raw, &cooked); pckt_assemble(&raw, &cooked, connBlock->sieve->intf);
ethinf_transmit(connBlock->sieve->intf, &raw); ethinf_transmit(connBlock->sieve->intf, &raw);

View File

@ -177,17 +177,17 @@ bool ipra_try_reassemble(IPv4Assembler *ipra, uint16_t id, uint8_t **payload, ui
iter = iter->next; iter = iter->next;
} }
// release chain
ipra_remove_chain(ipra, id);
// insert headers and change fields to obfuscate defragmentation // insert headers and change fields to obfuscate defragmentation
IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, pcktHdrLe); IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, pcktHdrLe);
ipProps->Flags = 0; ipProps->Flags = 0;
ipProps->FragmentOffset = 0; ipProps->FragmentOffset = 0;
ipProps->TotalLength = chainDesc->fullSize + ETH_IPv4_HEADER_SIZE; ipProps->TotalLength = chainDesc->fullSize + ETH_IPv4_HEADER_SIZE;
insert_ethernet_header(p, pcktHdrLe->prev); // release chain
insert_ipv4_header(p + ETH_ETHERNET_HEADER_SIZE, pcktHdrLe); ipra_remove_chain(ipra, id);
insert_ethernet_header(p, pcktHdrLe->prev, NULL);
insert_ipv4_header(p + ETH_ETHERNET_HEADER_SIZE, pcktHdrLe, NULL);
return true; return true;
} }

View File

@ -19,6 +19,8 @@ static bool filtIPv4(const PcktSieveFilterCondition *filtCond, const PcktProps *
ConnBlock ipv4_new_connblock(EthInterface *intf, ip4_addr ipAddr, SieveCallBackFn cbFn) { ConnBlock ipv4_new_connblock(EthInterface *intf, ip4_addr ipAddr, SieveCallBackFn cbFn) {
ConnBlock connb; ConnBlock connb;
connb_init_defaults(&connb);
PcktSieveFilterCondition filtCond; PcktSieveFilterCondition filtCond;
packfiltcond_zero(&filtCond); packfiltcond_zero(&filtCond);
IP_ADDR_TO_FILTCOND(&filtCond, ipAddr); IP_ADDR_TO_FILTCOND(&filtCond, ipAddr);
@ -48,3 +50,22 @@ void ipv4_print_report(const ConnBlock* connBlock) {
INFO("IP: ANY"); INFO("IP: ANY");
} }
} }
bool ipv4_in_range(ip4_addr a, ip4_addr l, ip4_addr u) {
l = ntohl(l); // this way IP addresses are mathematically sortable (by changing byte order)
u = ntohl(u);
a = ntohl(a);
return (l <= a) && (a <= u);
}
bool ipv4_is_multicast_address(ip4_addr addr) {
return ipv4_in_range(addr, IPv4(224, 0, 0, 0), IPv4(224, 0, 255, 255)) ||
ipv4_in_range(addr, IPv4(224, 1, 0, 0), IPv4(224, 1, 255, 255)) ||
ipv4_in_range(addr, IPv4(224, 3, 0, 0), IPv4(224, 4, 255, 255)) ||
ipv4_in_range(addr, IPv4(225, 0, 0, 0), IPv4(239, 255, 255, 255));
// ipv4_in_range(addr, IPv4(225, 0, 0, 0), IPv4(231, 255, 255, 255)) ||
// ipv4_in_range(addr, IPv4(232, 0, 0, 0), IPv4(232, 255, 255, 255)) ||
// ipv4_in_range(addr, IPv4(233, 0, 0, 0), IPv4(233, 251, 255, 255)) ||
// ipv4_in_range(addr, IPv4(233, 252, 0, 0), IPv4(233, 255, 255, 255)) ||
// ipv4_in_range(addr, IPv4(234, 252, 0, 0), IPv4(239, 255, 255, 255)) ||
}

View File

@ -34,4 +34,11 @@ void ipv4_send(EthInterface * intf, ip4_addr addr, const uint8_t * data, uint32_
*/ */
void ipv4_print_report(const ConnBlock* connBlock); void ipv4_print_report(const ConnBlock* connBlock);
/**
* Is the given address a multicast one?
* @param addr IP address to check
* @return ...
*/
bool ipv4_is_multicast_address(ip4_addr addr);
#endif //ETHERLIB_IPV4_CONNBLOCK_H #endif //ETHERLIB_IPV4_CONNBLOCK_H

View File

@ -233,6 +233,8 @@ void tcp_debug(cbd d, bool debug) {
cbd tcp_new_connblock(EthInterface *intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn) { cbd tcp_new_connblock(EthInterface *intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn) {
ConnBlock tcpConnB; ConnBlock tcpConnB;
connb_init_defaults(&tcpConnB);
ConnBlock ipConnB = ipv4_new_connblock(intf, ipAddr, NULL); // create new IPv4 connection block ConnBlock ipConnB = ipv4_new_connblock(intf, ipAddr, NULL); // create new IPv4 connection block
PcktSieveFilterCondition filtCond; PcktSieveFilterCondition filtCond;
@ -335,7 +337,7 @@ int tcp_send_segment(const struct ConnBlock_ *connBlock, TcpFlag flags, TcpOptio
cooked.time_ns = 0; cooked.time_ns = 0;
RawPckt raw; RawPckt raw;
pckt_assemble(&raw, &cooked); pckt_assemble(&raw, &cooked, connBlock->sieve->intf);
ethinf_transmit(connBlock->sieve->intf, &raw); ethinf_transmit(connBlock->sieve->intf, &raw);

View File

@ -20,6 +20,8 @@ static bool filtUdp(const PcktSieveFilterCondition *filtCond, const PcktProps *c
cbd udp_new_connblock(EthInterface *intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn) { cbd udp_new_connblock(EthInterface *intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn) {
ConnBlock udpConnB; ConnBlock udpConnB;
connb_init_defaults(&udpConnB);
ConnBlock ipConnB = ipv4_new_connblock(intf, ipAddr, NULL); // create new IPv4 connection block ConnBlock ipConnB = ipv4_new_connblock(intf, ipAddr, NULL); // create new IPv4 connection block
PcktSieveFilterCondition filtCond; PcktSieveFilterCondition filtCond;
@ -42,6 +44,10 @@ cbd udp_new_connblock(EthInterface *intf, ip4_addr ipAddr, uint16_t port, SieveC
} }
int udp_sendto(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_t port) { int udp_sendto(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_t port) {
return udp_sendto_arg(d, data, size, addr, port, 0);
}
int udp_sendto_arg(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_t port, uint32_t arg) {
ConnBlock connBlock; ConnBlock connBlock;
if (!cbdt_get_connection_block(E.cbdt, d, &connBlock)) { if (!cbdt_get_connection_block(E.cbdt, d, &connBlock)) {
ERROR("Invalid CBD descriptor: '%d'!\n", d); ERROR("Invalid CBD descriptor: '%d'!\n", d);
@ -82,7 +88,8 @@ int udp_sendto(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_
// Ethernet // Ethernet
layer = layer->parent; layer = layer->parent;
if (addr != 0xFFFFFFFF) { bool isMulticast = ipv4_is_multicast_address(addr);
if ((!isMulticast) && (addr != 0xFFFFFFFF)) { // unicast
ArpCache *arpc = connBlock.sieve->intf->arpc; ArpCache *arpc = connBlock.sieve->intf->arpc;
const ArpEntry *entry = arpc_get_ask(arpc, addr); const ArpEntry *entry = arpc_get_ask(arpc, addr);
if (entry == NULL) { if (entry == NULL) {
@ -90,8 +97,10 @@ int udp_sendto(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_
goto release_resources; // YEAH, goto HERE! goto release_resources; // YEAH, goto HERE!
} }
memcpy(ethProps->destAddr, entry, ETH_HW_ADDR_LEN); memcpy(ethProps->destAddr, entry, ETH_HW_ADDR_LEN);
} else { } else if (isMulticast) { // multicast
memset(ethProps->destAddr, 0xFF, ETH_HW_ADDR_LEN); ethmc_from_ipmc(ethProps->destAddr, addr);
} else { // unicast
memset(ethProps->destAddr, 0xFF, ETH_HW_ADDR_LEN); // broadcast
} }
memcpy(ethProps->sourceAddr, connBlock.sieve->intf->mac, ETH_HW_ADDR_LEN); memcpy(ethProps->sourceAddr, connBlock.sieve->intf->mac, ETH_HW_ADDR_LEN);
ethProps->length_type = ETH_IPv4_PACKET_CLASS; ethProps->length_type = ETH_IPv4_PACKET_CLASS;
@ -111,7 +120,9 @@ int udp_sendto(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_
cooked.time_ns = 0; cooked.time_ns = 0;
RawPckt raw; RawPckt raw;
pckt_assemble(&raw, &cooked); pckt_assemble(&raw, &cooked, connBlock.sieve->intf);
raw.ext.tx.arg = arg; // assign argument
raw.ext.tx.txTsCb = connBlock.sieveLayer->txTsCb; // assign with TX timestamp callback
ethinf_transmit(connBlock.sieve->intf, &raw); ethinf_transmit(connBlock.sieve->intf, &raw);

View File

@ -21,7 +21,7 @@
cbd udp_new_connblock(EthInterface * intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn); cbd udp_new_connblock(EthInterface * intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn);
/** /**
* UDP transmit callback. * UDP transmit function.
* @param connBlock UDP connection block * @param connBlock UDP connection block
* @param data pointer to data buffer * @param data pointer to data buffer
* @param size data size * @param size data size
@ -30,6 +30,17 @@ cbd udp_new_connblock(EthInterface * intf, ip4_addr ipAddr, uint16_t port, Sieve
*/ */
int udp_sendto(cbd connBlock, const uint8_t * data, uint32_t size, ip4_addr addr, uint16_t port); int udp_sendto(cbd connBlock, const uint8_t * data, uint32_t size, ip4_addr addr, uint16_t port);
/**
* UDP transmit function with additional argument.
* @param connBlock UDP connection block
* @param data pointer to data buffer
* @param size data size
* @param addr remote address to send datagram to
* @param addr remote port
* @param arg user-defined parameter
*/
int udp_sendto_arg(cbd connBlock, const uint8_t * data, uint32_t size, ip4_addr addr, uint16_t port, uint32_t arg);
/** /**
* Print UDP connblock report. * Print UDP connblock report.
* @param connBlock UDP connblock * @param connBlock UDP connblock

View File

@ -47,7 +47,7 @@ int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
return arpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT; return arpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT;
} }
void insert_arp_header(uint8_t *hdr, const PcktHeaderElement *headers) { void insert_arp_header(uint8_t *hdr, const PcktHeaderElement *headers, EthInterface *intf) {
ArpProps *arpProps = HEADER_FETCH_PROPS(ArpProps, headers); ArpProps *arpProps = HEADER_FETCH_PROPS(ArpProps, headers);
FILL_WORD_H2N_ADVANCE(hdr, arpProps->HTYPE); // hardware type FILL_WORD_H2N_ADVANCE(hdr, arpProps->HTYPE); // hardware type

View File

@ -58,7 +58,7 @@ int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
* @param hdr pointer to the packet buffer where the ARP header is to be written * @param hdr pointer to the packet buffer where the ARP header is to be written
* @param headers linked list of packet headers * @param headers linked list of packet headers
*/ */
void insert_arp_header(uint8_t *hdr, const PcktHeaderElement *headers); void insert_arp_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf);
#endif //ETHERLIB_ARP_PACKET_H #endif //ETHERLIB_ARP_PACKET_H

View File

@ -5,6 +5,7 @@
#include <memory.h> #include <memory.h>
#include <stdbool.h> #include <stdbool.h>
#include "ethernet_frame.h" #include "ethernet_frame.h"
#include "../../eth_interface.h"
#include "../../utils.h" #include "../../utils.h"
#define ETH_ETHERTYPE_LENGTH_THRESHOLD (1500) #define ETH_ETHERTYPE_LENGTH_THRESHOLD (1500)
@ -24,10 +25,10 @@ int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdr
frameProps->length_type <= ETH_ETHERTYPE_LENGTH_THRESHOLD ? 0 : frameProps->length_type; frameProps->length_type <= ETH_ETHERTYPE_LENGTH_THRESHOLD ? 0 : frameProps->length_type;
frameProps->headerSize = ETH_ETHERNET_HEADER_SIZE; frameProps->headerSize = ETH_ETHERNET_HEADER_SIZE;
return frameProps->containedPacketClass; return PROC_FN_RET_OK;
} }
void insert_ethernet_header(uint8_t *hdr, const PcktHeaderElement *headers) { void insert_ethernet_header(uint8_t *hdr, const PcktHeaderElement *headers, EthInterface *intf) {
EthernetProps * ethProps = (EthernetProps *) &headers->props; EthernetProps * ethProps = (EthernetProps *) &headers->props;
FILL_ADVANCE(hdr, ethProps->destAddr, ETH_HW_ADDR_LEN); FILL_ADVANCE(hdr, ethProps->destAddr, ETH_HW_ADDR_LEN);
FILL_ADVANCE(hdr, ethProps->sourceAddr, ETH_HW_ADDR_LEN); FILL_ADVANCE(hdr, ethProps->sourceAddr, ETH_HW_ADDR_LEN);

View File

@ -49,6 +49,6 @@ int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdr
* @param hdr space where the header is to be inserted * @param hdr space where the header is to be inserted
* @param headers linked list of header, top is always relevant * @param headers linked list of header, top is always relevant
*/ */
void insert_ethernet_header(uint8_t * hdr, const PcktHeaderElement * headers); void insert_ethernet_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf);
#endif //ETHERLIB_ETHERNET_FRAME_H #endif //ETHERLIB_ETHERNET_FRAME_H

View File

@ -26,7 +26,7 @@ int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
return icmpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT; return icmpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT;
} }
void insert_icmp_header(uint8_t *hdr, const PcktHeaderElement *headers) { void insert_icmp_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf) {
uint8_t * hdrStart = hdr; uint8_t * hdrStart = hdr;
IcmpProps *icmpProps = HEADER_FETCH_PROPS(IcmpProps, headers); IcmpProps *icmpProps = HEADER_FETCH_PROPS(IcmpProps, headers);
FILL_BYTE_ADVANCE(hdr, &icmpProps->type); FILL_BYTE_ADVANCE(hdr, &icmpProps->type);

View File

@ -41,6 +41,6 @@ int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
* @param hdr pointer to message header * @param hdr pointer to message header
* @param headers linked list of recursively encapsulated packet headers * @param headers linked list of recursively encapsulated packet headers
*/ */
void insert_icmp_header(uint8_t * hdr, const PcktHeaderElement * headers); void insert_icmp_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf);
#endif //ETHERLIB_ICMP_PACKET_H #endif //ETHERLIB_ICMP_PACKET_H

View File

@ -25,7 +25,7 @@
// return sum16; // return sum16;
//} //}
void insert_igmp_header(uint8_t *hdr, const PcktHeaderElement *headers) { void insert_igmp_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf) {
IgmpProps *igmpProps = HEADER_FETCH_PROPS(IgmpProps, headers); IgmpProps *igmpProps = HEADER_FETCH_PROPS(IgmpProps, headers);
uint8_t * hdrBeg = hdr; uint8_t * hdrBeg = hdr;

View File

@ -33,7 +33,7 @@ typedef struct {
* @param hdr pointer to message header * @param hdr pointer to message header
* @param headers linked list of recursively encapsulated packet headers * @param headers linked list of recursively encapsulated packet headers
*/ */
void insert_igmp_header(uint8_t * hdr, const PcktHeaderElement * headers); void insert_igmp_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf);
/** /**
* Parse IGMP packet. * Parse IGMP packet.

View File

@ -11,11 +11,11 @@
#define ETH_IP_HEADER_LENGTH (20) #define ETH_IP_HEADER_LENGTH (20)
static bool check_ipv4_validity(const uint8_t *hdr, const IPv4Props *ipProps) { static bool check_ipv4_validity(const uint8_t *hdr, const IPv4Props *ipProps, bool dontVerifyChecksum) {
bool valid = bool valid =
(ipProps->Version == 4) && (ipProps->Version == 4) &&
(ipProps->IHL == (ETH_IP_HEADER_LENGTH / 4)) && (ipProps->IHL == (ETH_IP_HEADER_LENGTH / 4)) &&
(chksum(hdr, ETH_IPv4_HEADER_SIZE, false) == 0); /*&& (dontVerifyChecksum || (chksum(hdr, ETH_IPv4_HEADER_SIZE, false) == 0)); /*&&
(ipProps->FragmentOffset == 0) && !(ipProps->Flags & 0x02 << 4); // TODO: discard if fragmented*/ (ipProps->FragmentOffset == 0) && !(ipProps->Flags & 0x02 << 4); // TODO: discard if fragmented*/
return valid; return valid;
} }
@ -41,7 +41,7 @@ int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
FETCH_ADVANCE(&ipProps->DestIPAddr, hdr, 4); FETCH_ADVANCE(&ipProps->DestIPAddr, hdr, 4);
// fill-in common packet header fields // fill-in common packet header fields
ipProps->validityOK = check_ipv4_validity(hdrBegin, ipProps); ipProps->validityOK = check_ipv4_validity(hdrBegin, ipProps, (intf->capabilities & ETHINF_CAP_RX_IPCHKSUM_OFFLOAD)); // don't verify checksum if done in hardware
ipProps->containedPacketClass = ipProps->Protocol; ipProps->containedPacketClass = ipProps->Protocol;
ipProps->headerSize = ETH_IP_HEADER_LENGTH; ipProps->headerSize = ETH_IP_HEADER_LENGTH;
@ -78,7 +78,7 @@ int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
static uint16_t nextIpIdentification = 0; static uint16_t nextIpIdentification = 0;
void insert_ipv4_header(uint8_t *hdr, const PcktHeaderElement *headers) { void insert_ipv4_header(uint8_t *hdr, const PcktHeaderElement *headers, EthInterface *intf) {
uint8_t *hdrOrig = hdr; uint8_t *hdrOrig = hdr;
IPv4Props *ipProps = (IPv4Props *) &headers->props; IPv4Props *ipProps = (IPv4Props *) &headers->props;
ipProps->Identification = nextIpIdentification++; // auto-insert identification ipProps->Identification = nextIpIdentification++; // auto-insert identification
@ -96,9 +96,11 @@ void insert_ipv4_header(uint8_t *hdr, const PcktHeaderElement *headers) {
FILL_ADVANCE(hdr, &ipProps->SourceIPAddr, 4); FILL_ADVANCE(hdr, &ipProps->SourceIPAddr, 4);
FILL_ADVANCE(hdr, &ipProps->DestIPAddr, 4); FILL_ADVANCE(hdr, &ipProps->DestIPAddr, 4);
// calculate checksum after filling header // calculate checksum after filling header if needed
if (!(intf->capabilities & ETHINF_CAP_TX_IPCHKSUM_OFFLOAD)) {
ipProps->HeaderChecksum = chksum(hdrOrig, ETH_IPv4_HEADER_SIZE, false); ipProps->HeaderChecksum = chksum(hdrOrig, ETH_IPv4_HEADER_SIZE, false);
memcpy(ChkSumPtr, &ipProps->HeaderChecksum, 2); memcpy(ChkSumPtr, &ipProps->HeaderChecksum, 2);
}
} }
void ethmc_from_ipmc(uint8_t *hwa, ip4_addr ipa) { void ethmc_from_ipmc(uint8_t *hwa, ip4_addr ipa) {

View File

@ -57,7 +57,7 @@ int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
* @param hdr space where the header is to be inserted * @param hdr space where the header is to be inserted
* @param headers linked list of header, top is always relevant * @param headers linked list of header, top is always relevant
*/ */
void insert_ipv4_header(uint8_t * hdr, const PcktHeaderElement * headers); void insert_ipv4_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf);
/** /**
* Calculate Ethernet IPv4 multicast address from multicast * Calculate Ethernet IPv4 multicast address from multicast

View File

@ -6,6 +6,7 @@
#include "../../utils.h" #include "../../utils.h"
#include "ethernet_frame.h" #include "ethernet_frame.h"
#include "../../dynmem.h" #include "../../dynmem.h"
#include "../../eth_interface.h"
#include "tcp_udp_common.h" #include "tcp_udp_common.h"
#include "ipv4_packet.h" #include "ipv4_packet.h"
@ -140,20 +141,24 @@ int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
} }
// verify checksum // verify checksum
if (!(intf->capabilities & ETHINF_CAP_RX_TCPUDPCHKSUM_OFFLOAD)) { // TODO
const IPv4Props *ipProps = (IPv4Props *) &pcktHdrLe->prev->props; const IPv4Props *ipProps = (IPv4Props *) &pcktHdrLe->prev->props;
uint16_t headerAndPayloadLength = ipProps->bytesToEnd; uint16_t headerAndPayloadLength = ipProps->bytesToEnd;
IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_TCP_PACKET_CLASS, htons(headerAndPayloadLength)}; IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_TCP_PACKET_CLASS, htons(headerAndPayloadLength)};
//uint16_t chkSum = tcp_udp_checksum(&ph, hdrBegin, headerAndPayloadLength); //uint16_t chkSum = tcp_udp_checksum(&ph, hdrBegin, headerAndPayloadLength);
uint16_t chkSum = 0; uint16_t chkSum = 0; // TODO ....
tcpProps->validityOK = (chkSum == 0);
} else {
tcpProps->validityOK = true;
}
tcpProps->headerSize = fullHeaderSize; tcpProps->headerSize = fullHeaderSize;
tcpProps->validityOK = (chkSum == 0);
tcpProps->containedPacketClass = 0; tcpProps->containedPacketClass = 0;
return tcpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT; return tcpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT;
} }
void insert_tcp_header(uint8_t *hdr, const PcktHeaderElement *headers) { void insert_tcp_header(uint8_t *hdr, const PcktHeaderElement *headers, EthInterface *intf) {
uint8_t * hdrBegin = hdr; uint8_t * hdrBegin = hdr;
TcpProps * tcpProps = HEADER_FETCH_PROPS(TcpProps, headers); // fetch header TcpProps * tcpProps = HEADER_FETCH_PROPS(TcpProps, headers); // fetch header
@ -181,11 +186,13 @@ void insert_tcp_header(uint8_t *hdr, const PcktHeaderElement *headers) {
tcp_insert_options(hdr, optSize, tcpProps->options); tcp_insert_options(hdr, optSize, tcpProps->options);
// calculate checksum // calculate checksum
if (!(intf->capabilities & ETHINF_CAP_TX_TCPUDPCHKSUM_OFFLOAD)) {
const IPv4Props *ipProps = (IPv4Props *) &headers->prev->props; const IPv4Props *ipProps = (IPv4Props *) &headers->prev->props;
uint16_t headerAndPayloadLength = fullHeaderSize + headers->props.bytesToEnd; uint16_t headerAndPayloadLength = fullHeaderSize + headers->props.bytesToEnd;
IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_TCP_PACKET_CLASS, htons(headerAndPayloadLength)}; IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_TCP_PACKET_CLASS, htons(headerAndPayloadLength)};
tcpProps->Checksum = tcp_udp_checksum(&ph, hdrBegin, headerAndPayloadLength); tcpProps->Checksum = tcp_udp_checksum(&ph, hdrBegin, headerAndPayloadLength);
memcpy(ChkSumPtr, &tcpProps->Checksum, 2); memcpy(ChkSumPtr, &tcpProps->Checksum, 2);
}
} }
// ---------------------------------- // ----------------------------------

View File

@ -101,7 +101,7 @@ int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
* @param hdr space where the header is to be inserted * @param hdr space where the header is to be inserted
* @param headers linked list of header, top is always relevant * @param headers linked list of header, top is always relevant
*/ */
void insert_tcp_header(uint8_t * hdr, const PcktHeaderElement * headers); void insert_tcp_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf);
/** /**
* Get the flattened size of the option chain. * Get the flattened size of the option chain.

View File

@ -5,6 +5,7 @@
#include "ethernet_frame.h" #include "ethernet_frame.h"
#include "tcp_udp_common.h" #include "tcp_udp_common.h"
#include "etherlib/eth_interface.h"
#define ETH_UDP_HEADER_SIZE (8) #define ETH_UDP_HEADER_SIZE (8)
@ -27,13 +28,17 @@ int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
// common fields... // common fields...
udpProps->headerSize = ETH_UDP_HEADER_SIZE; udpProps->headerSize = ETH_UDP_HEADER_SIZE;
if (!(intf->capabilities & ETHINF_CAP_RX_TCPUDPCHKSUM_OFFLOAD)) {
udpProps->validityOK = check_udp_validity(hdrBegin, pcktHdrLe); udpProps->validityOK = check_udp_validity(hdrBegin, pcktHdrLe);
} else {
udpProps->validityOK = true;
}
udpProps->containedPacketClass = 0; udpProps->containedPacketClass = 0;
return udpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT; return udpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT;
} }
void insert_udp_header(uint8_t *hdr, const PcktHeaderElement *headers) { void insert_udp_header(uint8_t *hdr, const PcktHeaderElement *headers, EthInterface *intf) {
uint8_t *hdrBegin = hdr; uint8_t *hdrBegin = hdr;
UdpProps *udpProps = (UdpProps *) &headers->props; UdpProps *udpProps = (UdpProps *) &headers->props;
FILL_WORD_H2N_ADVANCE(hdr, udpProps->SourcePort); FILL_WORD_H2N_ADVANCE(hdr, udpProps->SourcePort);
@ -43,11 +48,13 @@ void insert_udp_header(uint8_t *hdr, const PcktHeaderElement *headers) {
udpProps->Checksum = 0; udpProps->Checksum = 0;
FILL_WORD_H2N_ADVANCE(hdr, udpProps->Checksum); FILL_WORD_H2N_ADVANCE(hdr, udpProps->Checksum);
// calculate checksum // calculate checksum if needed
if (!(intf->capabilities & ETHINF_CAP_TX_TCPUDPCHKSUM_OFFLOAD)) {
const IPv4Props *ipProps = (IPv4Props *) &headers->prev->props; const IPv4Props *ipProps = (IPv4Props *) &headers->prev->props;
IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_UDP_PACKET_CLASS, htons(udpProps->Length)}; IPv4PseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_UDP_PACKET_CLASS, htons(udpProps->Length)};
udpProps->Checksum = tcp_udp_checksum(&ph, hdrBegin, udpProps->Length); udpProps->Checksum = tcp_udp_checksum(&ph, hdrBegin, udpProps->Length);
memcpy(ChkSumPtr, &udpProps->Checksum, 2); memcpy(ChkSumPtr, &udpProps->Checksum, 2);
}
} }

View File

@ -37,6 +37,6 @@ int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
* @param hdr space where the header is to be inserted * @param hdr space where the header is to be inserted
* @param headers linked list of header, top is always relevant * @param headers linked list of header, top is always relevant
*/ */
void insert_udp_header(uint8_t * hdr, const PcktHeaderElement * headers); void insert_udp_header(uint8_t *hdr, const PcktHeaderElement *headers, struct EthInterface_ *intf);
#endif //ETHERLIB_UDP_PACKET_H #endif //ETHERLIB_UDP_PACKET_H

19
timestamping.c Normal file
View File

@ -0,0 +1,19 @@
//
// Created by epagris on 2023.04.22..
//
#include "timestamping.h"
#include "global_state.h"
#include "utils.h"
void ts_set_tx_callback(cbd d, void (*cb)(uint32_t, uint32_t, uint32_t)) {
ConnBlock connb;
if (!cbdt_get_connection_block(E.cbdt, d, &connb)) { // try to fetch connection block
ERROR("Unknown CBD: %u\n", d); // if not found, then do nothing
return;
}
// if found...
connb.sieveLayer->txTsCb = cb;
}

13
timestamping.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef ETHERLIB_TIMESTAMPING_H
#define ETHERLIB_TIMESTAMPING_H
#include "cbd_table.h"
/**
* Assign callback funtion to specific connection block.
* @param d CBD to existing connection
* @param cb pointer to callback function
*/
void ts_set_tx_callback(cbd d, void(*cb)(uint32_t ts_s, uint32_t ts_ns, uint32_t tag));
#endif //ETHERLIB_TIMESTAMPING_H

View File

@ -5,6 +5,8 @@
#ifndef ETHERLIB_UTILS_H #ifndef ETHERLIB_UTILS_H
#define ETHERLIB_UTILS_H #define ETHERLIB_UTILS_H
#include <etherlib_options.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <memory.h> #include <memory.h>
@ -35,8 +37,6 @@
#define WARNING(...) MSG(__VA_ARGS__) #define WARNING(...) MSG(__VA_ARGS__)
#define INFO(...) MSG(__VA_ARGS__) #define INFO(...) MSG(__VA_ARGS__)
#define SNPRINTF(s,n,...) snprintf(s,n,__VA_ARGS__)
#define IPv4(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24)) #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 PRINT_IPv4(ip) MSG("%u.%u.%u.%u", (ip & 0xFF), ((ip >> 8) & 0xFF), ((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF))
#define PRINT_HWADDR(hwaddr) MSG("%02x:%02x:%02x:%02x:%02x:%02x", (hwaddr)[0], (hwaddr)[1], (hwaddr)[2], (hwaddr)[3], (hwaddr)[4], (hwaddr)[5]); #define PRINT_HWADDR(hwaddr) MSG("%02x:%02x:%02x:%02x:%02x:%02x", (hwaddr)[0], (hwaddr)[1], (hwaddr)[2], (hwaddr)[3], (hwaddr)[4], (hwaddr)[5]);
@ -66,8 +66,12 @@
#define FILL_DWORD_H2N_ADVANCE(dst,dw) { uint32_t du = htonl(dw); memcpy(dst, &du, 4); (dst) += 4; } #define FILL_DWORD_H2N_ADVANCE(dst,dw) { uint32_t du = htonl(dw); memcpy(dst, &du, 4); (dst) += 4; }
#define FILL_DWORD_ADVANCE(dst,dw) { memcpy(dst, &(dw), 4); (dst) += 4; } #define FILL_DWORD_ADVANCE(dst,dw) { memcpy(dst, &(dw), 4); (dst) += 4; }
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
// ------------------ // ------------------