-IP reassembler added

-PcktSieve special return functionality added
-ARP multicast learning bug fixed
-include guards have been refactored
-Doxygen style tweaked
This commit is contained in:
Wiesner András 2023-02-04 11:04:26 +01:00
parent 8676a392e5
commit ac5fc9c529
46 changed files with 536 additions and 132 deletions

View File

@ -42,6 +42,10 @@ void arpc_free(ArpCache *aprc) {
} }
void arpc_learn(ArpCache *arpc, const ArpEntry *newEntry) { void arpc_learn(ArpCache *arpc, const ArpEntry *newEntry) {
if (newEntry->eth[0] & 0x01) { // don't learn multicast addresses
return;
}
// TODO: nagyon dummy... // TODO: nagyon dummy...
for (uint16_t i = 0; i < arpc->fill; i++) { for (uint16_t i = 0; i < arpc->fill; i++) {
ArpEntry * entry = arpc->entries + i; ArpEntry * entry = arpc->entries + i;

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_ARP_CACHE_H #ifndef ETHERLIB_ARP_CACHE_H
#define ETHERLIB_TEST_ARP_CACHE_H #define ETHERLIB_ARP_CACHE_H
#include "prefab/packet_parsers/ethernet_frame.h" #include "prefab/packet_parsers/ethernet_frame.h"
#include "prefab/packet_parsers/ipv4_types.h" #include "prefab/packet_parsers/ipv4_types.h"
@ -68,4 +68,4 @@ const ArpEntry *arpc_get_ask(ArpCache *arpc, ip4_addr ip);
*/ */
void arpc_dump(ArpCache * arpc); void arpc_dump(ArpCache * arpc);
#endif //ETHERLIB_TEST_ARP_CACHE_H #endif //ETHERLIB_ARP_CACHE_H

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_CBD_TABLE_H #ifndef ETHERLIB_CBD_TABLE_H
#define ETHERLIB_TEST_CBD_TABLE_H #define ETHERLIB_CBD_TABLE_H
#include <stdint.h> #include <stdint.h>
#include "connection_block.h" #include "connection_block.h"
@ -58,4 +58,4 @@ bool cbdt_get_connection_block(CbdTable * cbdt, cbd d, ConnBlock * connBlock);
*/ */
void cbdt_report(const CbdTable * cbdt); void cbdt_report(const CbdTable * cbdt);
#endif //ETHERLIB_TEST_CBD_TABLE_H #endif //ETHERLIB_CBD_TABLE_H

View File

@ -62,6 +62,41 @@ p.reference, p.definition {
font: 400 14px/22px 'Crimson Text',Roboto,sans-serif; font: 400 14px/22px 'Crimson Text',Roboto,sans-serif;
} }
#nav-tree {
background-color: var(--light-green-yellow-crayola);
background-image: none;
}
div#nav-path ul {
background-image: none;
}
#nav-tree .selected {
background-image: none;
background-color: var(--eggplant);
}
span.arrow {
color: var(--ebony);
font-size: 120%;
}
div.item span.label {
font-size: 13px !important;
font-family: 'Fira Code', Roboto, sans-serif !important;
}
.ui-resizable-handle {
background-image: none;
background-color: var(--ebony);
}
.ui-resizable-e {
width: 3px;
}
/* @group Heading Levels */ /* @group Heading Levels */
h1.groupheader { h1.groupheader {

View File

@ -3,6 +3,10 @@
#include <stdint.h> #include <stdint.h>
#ifdef DYNMEM_DEBUG
#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

View File

@ -32,6 +32,8 @@ EthInterface *ethintf_new(EthIODef * io) {
ethIntf->txQ = mq_create(ETHLIB_DEF_MQ_SIZE); ethIntf->txQ = mq_create(ETHLIB_DEF_MQ_SIZE);
ethIntf->ipra = ipra_new();
return ethIntf; return ethIntf;
} }

View File

@ -7,6 +7,7 @@
#include "arp_cache.h" #include "arp_cache.h"
#include "connection_block.h" #include "connection_block.h"
#include "msg_queue.h" #include "msg_queue.h"
#include "prefab/conn_blocks/ipv4/ip_assembler.h"
/** /**
* Ethernet interface low level definition. * Ethernet interface low level definition.
@ -35,6 +36,7 @@ typedef struct EthInterface_ {
ArpCache * arpc; ///< ARP cache ArpCache * arpc; ///< ARP cache
ConnBlock arpCb; ///< ARP connection block ConnBlock arpCb; ///< ARP connection block
MsgQueue * txQ; ///< Transmit queue MsgQueue * txQ; ///< Transmit queue
IPv4Assembler * ipra; ///< IPv4 reassembler
} EthInterface; } EthInterface;
/** /**

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_MSG_QUEUE_H #ifndef ETHERLIB_MSG_QUEUE_H
#define ETHERLIB_TEST_MSG_QUEUE_H #define ETHERLIB_MSG_QUEUE_H
#include <stdint.h> #include <stdint.h>
#include "packet.h" #include "packet.h"
@ -52,4 +52,4 @@ RawPckt mq_top(MsgQueue * mq);
*/ */
void mq_pop(MsgQueue * mq); void mq_pop(MsgQueue * mq);
#endif //ETHERLIB_TEST_MSG_QUEUE_H #endif //ETHERLIB_MSG_QUEUE_H

View File

@ -44,6 +44,17 @@ typedef struct {
PcktPropsHeader PcktPropsHeader
} PcktProps; } PcktProps;
// special processing function returns
#define PROC_FN_RET_OK (0) // OK, go ahead!
#define PROC_FN_RET_ABORT (-1) // abort further processing
#define PROC_FN_RET_REPRST (-2) // replace packet and restart packet processing
typedef struct {
void * p;
uint32_t u;
bool8_t b;
} PcktProcFnPassbackData;
/** /**
* @typedef int (*PcktProcFn)(const uint8_t *pHdr, uint32_t size, uint8_t *pPcktProps); * @typedef int (*PcktProcFn)(const uint8_t *pHdr, uint32_t size, uint8_t *pPcktProps);
* @brief Pckt processing function template. * @brief Pckt processing function template.
@ -52,11 +63,9 @@ typedef struct {
* @param props: pointer to existing structure to store * @param props: pointer to existing structure to store
* packet properties to (e.g. source address, port etc.) * packet properties to (e.g. source address, port etc.)
* @param intf associeated Ethernet interface * @param intf associeated Ethernet interface
* @return packet class of contained packet, or -1 on failure or * @return one of the special processing function return values
* 0 if no more standard packet contained (e.g. UDP packet contains
* user data)
*/ */
typedef int (*PcktProcFn)(const uint8_t *hdr, uint32_t size, struct PcktHeaderElement_ * pcktHdrLe, struct EthInterface_ * intf); typedef int (*PcktProcFn)(const uint8_t *hdr, uint32_t size, struct PcktHeaderElement_ * pcktHdrLe, struct EthInterface_ * intf, PcktProcFnPassbackData * pb);
/** /**
* @struct PcktClassDesc * @struct PcktClassDesc

View File

@ -24,15 +24,18 @@ PcktSieve *packsieve_new(EthInterface * intf) {
return sieve; return sieve;
} }
void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) { void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
// extract fields // extract fields
uint8_t *data = rawPckt->payload; uint8_t *data = rawPckt->payload;
uint32_t size = rawPckt->size; uint32_t size = rawPckt->size;
bool mrd = false; // 'Must Release Data': at the end of processing not only release headers but data buffer as well
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;
PcktHeaderElement *lastHeader = NULL, *outermostHeader = NULL; PcktHeaderElement *lastHeader = NULL, *outermostHeader = NULL;
int procRet;
do { do {
// get packet descriptor // get packet descriptor
@ -56,7 +59,22 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
} }
// call parsing function // call parsing function
cdesc->procFun(data + offset, size - offset, header, sieve->intf); PcktProcFnPassbackData pb;
procRet = cdesc->procFun(data + offset, size - offset, header, sieve->intf, &pb);
switch (procRet) {
case PROC_FN_RET_REPRST:
data = pb.p; // store new packet data
size = pb.u;
mrd = pb.b;
// NO BREAK!
case PROC_FN_RET_ABORT:
goto header_release; // GOTO :D!
break;
case PROC_FN_RET_OK:
default:
break;
}
uint16_t containedClass = header->props.containedPacketClass; uint16_t containedClass = header->props.containedPacketClass;
if (containedClass != 0) { if (containedClass != 0) {
containerClass = ownClass; containerClass = ownClass;
@ -83,7 +101,7 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
// lookup headers in the sieve // lookup headers in the sieve
const PcktHeaderElement *headerIter = outermostHeader; const PcktHeaderElement *headerIter = outermostHeader;
const PcktSieveLayer *layer = &sieve->layer0; // innermost matched sieve layer PcktSieveLayer *layer = &sieve->layer0; // innermost matched sieve layer
bool found = true; // first structure is always an Ethernet-frame bool found = true; // first structure is always an Ethernet-frame
while (found && headerIter) { while (found && headerIter) {
const PcktSieveLayer *nodeIter = layer->nodes; const PcktSieveLayer *nodeIter = layer->nodes;
@ -99,7 +117,16 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
packet.payload = data + offset; packet.payload = data + offset;
packet.headerSize = offset; packet.headerSize = offset;
packet.payloadSize = size - offset; packet.payloadSize = size - offset;
layer->cbFn(&packet, layer->tag); int action = layer->cbFn(&packet, layer->tag);
// execute special return action
switch (action) {
case SIEVE_LAYER_REMOVE_THIS:
packsieve_remove_layer(layer);
break;
default:
break;
}
} }
headerIter = containedHeader; headerIter = containedHeader;
} else { } else {
@ -123,6 +150,13 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
dynmem_free(iter); dynmem_free(iter);
iter = next; iter = next;
} }
if (procRet == PROC_FN_RET_REPRST) { // if a restart was requested, then run everything again!
goto restart;
}
data_release:;
if (mrd) {
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) {
@ -214,7 +248,7 @@ bool packsieve_remove_layer(PcktSieveLayer *layer) {
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->intf, layer, NULL }; // tag not required const ConnBlock connBlock = { sieve, layer, NULL }; // tag not required
layer->connBReportFn(&connBlock); layer->connBReportFn(&connBlock);
INFO("├───\n"); INFO("├───\n");
} else { } else {
@ -231,7 +265,7 @@ 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->intf, iter, NULL}; // tag not required const ConnBlock connBlock = {sieve, iter, NULL}; // tag not required
iter->connBReportFn(&connBlock); iter->connBReportFn(&connBlock);
} else { } else {
INFO("[%d]", layer->packetClass); INFO("[%d]", layer->packetClass);

View File

@ -64,6 +64,9 @@ typedef union {
uint32_t u; uint32_t u;
} PcktSieveLayerTag; } PcktSieveLayerTag;
// actions triggered by callback function returns
#define SIEVE_LAYER_REMOVE_THIS (-100)
/** /**
* Callback function type for packet sieve match. * Callback function type for packet sieve match.
*/ */
@ -114,7 +117,7 @@ PcktSieve * packsieve_new();
* @param data * @param data
* @param size * @param size
*/ */
void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt); void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt);
/** /**
* Create a new sieve filter layer. * Create a new sieve filter layer.

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_PCKT_ASSEMBLER_H #ifndef ETHERLIB_PCKT_ASSEMBLER_H
#define ETHERLIB_TEST_PCKT_ASSEMBLER_H #define ETHERLIB_PCKT_ASSEMBLER_H
#include "packet.h" #include "packet.h"
@ -15,4 +15,4 @@ struct EthInterface_;
*/ */
int pckt_assemble(RawPckt *raw, Pckt *cooked); int pckt_assemble(RawPckt *raw, Pckt *cooked);
#endif //ETHERLIB_TEST_PCKT_ASSEMBLER_H #endif //ETHERLIB_PCKT_ASSEMBLER_H

View File

@ -2,10 +2,8 @@
#include <stddef.h> #include <stddef.h>
#include "../packet_parsers/packet_parsers.h"
#include "../../utils.h" #include "../../utils.h"
#include "../../dynmem.h" #include "../../dynmem.h"
#include "../packet_parsers/arp_packet.h"
static bool filtArp(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps, EthInterface * intf) { static bool filtArp(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps, EthInterface * intf) {
EthernetProps * ethProps = (EthernetProps *) contProps; EthernetProps * ethProps = (EthernetProps *) contProps;

View File

@ -1,7 +1,7 @@
#ifndef ETHERLIB_TEST_ARP_CONNBLOCK_H #ifndef ETHERLIB_ARP_CONNBLOCK_H
#define ETHERLIB_TEST_ARP_CONNBLOCK_H #define ETHERLIB_ARP_CONNBLOCK_H
#endif //ETHERLIB_TEST_ARP_CONNBLOCK_H #endif //ETHERLIB_ARP_CONNBLOCK_H
#include <stdint.h> #include <stdint.h>
#include "../../connection_block.h" #include "../../connection_block.h"

View File

@ -1,8 +1,8 @@
#ifndef ETHERLIB_TEST_ETHERNET_INFO_H #ifndef ETHERLIB_ETHERNET_INFO_H
#define ETHERLIB_TEST_ETHERNET_INFO_H #define ETHERLIB_ETHERNET_INFO_H
#include "etherlib/connection_block.h" #include "../../connection_block.h"
/** /**
* Print Ethernet sieve layer info. * Print Ethernet sieve layer info.
@ -10,4 +10,4 @@
*/ */
void ethernet_print_report(const ConnBlock* connBlock); void ethernet_print_report(const ConnBlock* connBlock);
#endif //ETHERLIB_TEST_ETHERNET_INFO_H #endif //ETHERLIB_ETHERNET_INFO_H

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_ICMP_CONNBLOCK_H #ifndef ETHERLIB_ICMP_CONNBLOCK_H
#define ETHERLIB_TEST_ICMP_CONNBLOCK_H #define ETHERLIB_ICMP_CONNBLOCK_H
#include "../../connection_block.h" #include "../../connection_block.h"
@ -18,4 +18,4 @@ ConnBlock icmp_new_connblock(struct EthInterface_ * intf);
*/ */
void icmp_print_report(const ConnBlock* connBlock); void icmp_print_report(const ConnBlock* connBlock);
#endif //ETHERLIB_TEST_ICMP_CONNBLOCK_H #endif //ETHERLIB_ICMP_CONNBLOCK_H

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_IGMP_CONNBLOCK_H #ifndef ETHERLIB_IGMP_CONNBLOCK_H
#define ETHERLIB_TEST_IGMP_CONNBLOCK_H #define ETHERLIB_IGMP_CONNBLOCK_H
#include "../../connection_block.h" #include "../../connection_block.h"
#include "../packet_parsers/ipv4_types.h" #include "../packet_parsers/ipv4_types.h"
@ -33,4 +33,4 @@ void igmp_leave_group(ConnBlock * connBlock, ip4_addr ga);
*/ */
void igmp_print_report(const ConnBlock* connBlock); void igmp_print_report(const ConnBlock* connBlock);
#endif //ETHERLIB_TEST_IGMP_CONNBLOCK_H #endif //ETHERLIB_IGMP_CONNBLOCK_H

View File

@ -0,0 +1,196 @@
#include <stddef.h>
#include <memory.h>
#include "ip_assembler.h"
#include "../../../dynmem.h"
#include "../../../global_state.h"
IPv4Assembler *ipra_new() {
IPv4Assembler *ipra = (IPv4Assembler *) dynmem_alloc(sizeof(IPv4Assembler));
ipra->chains = NULL;
return ipra;
}
static IPv4Fragment *ipra_all_frags_recvd(IPv4Assembler *ipra) {
IPv4Fragment *fullChain = NULL;
FragChainDesc *chainIter = ipra->chains;
while ((chainIter != NULL) && (fullChain == NULL)) { // iter over all chains
IPv4Fragment *fragIter = chainIter->fragChain;
uint16_t expectedOffset = 0; // check that all fragments corresponding to the same IP packet have been received
bool continuityOK = true; // we have possessed each fragments contiguously so far
while ((fragIter != NULL) && continuityOK) { // iterate over all segments
if (fragIter->offset == expectedOffset) {
if ((fragIter->next == NULL) && (fragIter->lastFrag)) { // if last stored segment is not the chain's end, then the packet is not full
continuityOK = false;
}
expectedOffset += fragIter->size;
} else {
continuityOK = false;
}
fragIter = fragIter->next;
}
if (continuityOK) { // if we have a full chain, then return with the pointer to it
fullChain = chainIter->fragChain;
}
}
return fullChain;
}
static FragChainDesc *ipra_frag_chain_by_id(IPv4Assembler *ipra, uint16_t id) {
FragChainDesc *fragChain = NULL, *iter = ipra->chains;
while ((iter != NULL) && (fragChain == NULL)) {
if (iter->id == id) {
fragChain = iter;
}
iter = iter->next;
}
return fragChain;
}
static void ipra_remove_chain(IPv4Assembler * ipra, uint16_t id) {
FragChainDesc * chainDesc = ipra_frag_chain_by_id(ipra, id);
if (chainDesc == NULL) {
return;
}
timer_unsched(E.tmr, chainDesc->id); // remove timeout schedule
IPv4Fragment * iter = chainDesc->fragChain; // unlink and release fragment chain
while (iter != NULL) {
IPv4Fragment * oldIter = iter;
iter = iter->next;
dynmem_free(oldIter);
}
FragChainDesc * chainIter = ipra->chains;
while (chainIter != NULL) { // unlink chain from chain list
if (chainIter->next == chainDesc) { // if element is found
chainIter->next = chainDesc->next; // skip by looked up element by setting next properly
break; // break the loop
}
chainIter = chainIter->next;
}
// replace root element with the next one
if (ipra->chains == chainDesc) {
ipra->chains = chainDesc->next;
}
dynmem_free(chainDesc); // release chain descriptor
}
#define IP_REASSEMBLY_TIMEOUT_US (1000000)
static void ipra_timeout(Timer * tmr, AlarmUserData user) {
IPv4Assembler * ipra = user.ptr;
uint16_t id = user.u;
ipra_remove_chain(ipra, id);
}
// insert into chain, without checking ID!
static void ipra_insert_into_chain(FragChainDesc *chainDesc, const IPv4Props *ipProps, const uint8_t *payload, uint32_t size) {
IPv4Fragment *frag = (IPv4Fragment *) dynmem_alloc(sizeof(IPv4Fragment) + size); // allocate fragment
frag->size = size;
frag->lastFrag = !(ipProps->Flags & IP_FLAG_MF);
frag->offset = ipProps->FragmentOffset;
memcpy(frag->payload, payload, size);
frag->next = NULL;
IPv4Fragment *iter = chainDesc->fragChain;
if (iter != NULL) { // if there are some segments present
while (iter != NULL) {
if (((iter->offset + iter->size) <= frag->offset) && // normal, sorted insertion
((iter->next == NULL) || (iter->next->offset >= (frag->offset + frag->size)))) {
frag->next = iter->next;
iter->next = frag;
} else if ((iter == chainDesc->fragChain) && (frag->offset < iter->offset)) { // insert before the firstly received segment
frag->next = iter;
chainDesc->fragChain = frag;
}
iter = iter->next;
}
} else {
chainDesc->fragChain = frag;
}
chainDesc->fullSize += size;
}
void ipra_input(IPv4Assembler *ipra, const IPv4Props *ipProps, const uint8_t *payload, uint32_t size) {
uint16_t id = ipProps->Identification;
FragChainDesc *chainDesc = ipra_frag_chain_by_id(ipra, id);
if (chainDesc == NULL) { // if chain was found, allocate new one
chainDesc = (FragChainDesc *) dynmem_alloc(sizeof(FragChainDesc));
chainDesc->id = ipProps->Identification;
chainDesc->alarmID = 0;
chainDesc->fullSize = 0;
chainDesc->fragChain = NULL;
// link-in newly allocated fragment chain (position does not carry meaning, that's why insertion at the beginning is the simplest)
chainDesc->next = ipra->chains;
ipra->chains = chainDesc;
}
// insert segment into chain
ipra_insert_into_chain(chainDesc, ipProps, payload, size);
// reschedule timeout
if (chainDesc->alarmID != 0) {
timer_unsched(E.tmr, chainDesc->alarmID);
}
AlarmUserData aud;
aud.ptr = ipra;
aud.u = chainDesc->id;
timer_sched_rel(E.tmr, IP_REASSEMBLY_TIMEOUT_US, ipra_timeout, aud);
}
bool ipra_try_reassemble(IPv4Assembler *ipra, uint16_t id, uint8_t **payload, uint16_t *size, PcktHeaderElement *pcktHdrLe) {
FragChainDesc *chainDesc = ipra_frag_chain_by_id(ipra, id);
if (chainDesc == NULL) { // chain not found
return false;
}
// check fragment continuity
IPv4Fragment *fragIter = chainDesc->fragChain;
uint16_t expectedOffset = 0; // check that all fragments corresponding to the same IP packet have been received
bool continuityOK = true; // we have possessed each fragments contiguously so far
while ((fragIter != NULL) && continuityOK) { // iterate over all segments
if (fragIter->offset == expectedOffset) {
if ((fragIter->next == NULL) && !(fragIter->lastFrag)) { // if last stored segment is not the chain's end, then the packet is not full
continuityOK = false;
}
expectedOffset += fragIter->size;
} else {
continuityOK = false;
}
fragIter = fragIter->next;
}
if (continuityOK) { // if we have a full chain, then reassemble
uint16_t offset = ETH_ETHERNET_HEADER_SIZE + ETH_IPv4_HEADER_SIZE; // offset for Ethernet and IPv4 header
*payload = dynmem_alloc(chainDesc->fullSize + offset); // allocate space for the whole packet
*size = chainDesc->fullSize;
uint8_t * p = (*payload);
IPv4Fragment * iter = chainDesc->fragChain;
while (iter != NULL) { // assemble packet
memcpy(p + iter->offset + offset, iter->payload, iter->size);
iter = iter->next;
}
// release chain
ipra_remove_chain(ipra, id);
// insert headers and change fields to obfuscate defragmentation
IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, pcktHdrLe);
ipProps->Flags = 0;
ipProps->FragmentOffset = 0;
ipProps->TotalLength = chainDesc->fullSize + ETH_IPv4_HEADER_SIZE;
insert_ethernet_header(p, pcktHdrLe->prev);
insert_ipv4_header(p + ETH_ETHERNET_HEADER_SIZE, pcktHdrLe);
return true;
}
return false;
}

View File

@ -0,0 +1,54 @@
#ifndef ETHERLIB_IP_ASSEMBLER_H
#define ETHERLIB_IP_ASSEMBLER_H
#include <stdint.h>
#include "../../packet_parsers/ipv4_packet.h"
typedef struct IPv4Fragment_ {
uint16_t offset; ///< Address offset of this segment
uint16_t size; ///< Size of this segment
struct IPv4Fragment_ * next; ///< Pointer to next segment
bool8_t lastFrag; ///< It's the last fragment from a packet
uint8_t payload[]; ///< Fragment payload
} IPv4Fragment;
/**
* Fragment chain descriptor
*/
typedef struct FragChainDesc_ {
IPv4Fragment * fragChain; ///< Fragment chain
uint32_t alarmID; ///< Alarm ID for reassembly timeout
uint16_t id; ///< IP packet identification
uint16_t fullSize; ///< Reassembled IP packet size
struct FragChainDesc_ * next; ///< Next fragment chain
} FragChainDesc;
typedef struct {
FragChainDesc * chains; ///< Linked list of fragment chains
} IPv4Assembler;
/**
* Create new IPv4 packet reassembler.
* @return pointer to newly allocated assembler
*/
IPv4Assembler * ipra_new();
/**
* Input packet packet fragment.
* @param ipra pointer to IP reassembler
* @param ipProps pointer to IP properties structure
*/
void ipra_input(IPv4Assembler * ipra, const IPv4Props * ipProps, const uint8_t * payload, uint32_t size);
/**
* Try to reassembly packet.
* @param ipra pointer to IPv4 reassembly object
* @param id packet sequence identification
* @param payload pointer to uint8_t* pointer; filled only on successful reassembly
* @param size pointer to uint16_t field; filled only on successful reassembly
* @return reassembly was successful
*/
bool ipra_try_reassemble(IPv4Assembler *ipra, uint16_t id, uint8_t **payload, uint16_t *size, PcktHeaderElement *pcktHdrLe);
#endif //ETHERLIB_IP_ASSEMBLER_H

View File

@ -4,15 +4,17 @@
#include "ipv4_connblock.h" #include "ipv4_connblock.h"
#include "../packet_parsers/packet_parsers.h"
#include "../../utils.h" #include "../../utils.h"
#include "../../global_state.h"
static bool filtIPv4(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface * intf) { static bool filtIPv4(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface * intf) {
EthernetProps *etherProps = (EthernetProps *) contProps; EthernetProps *etherProps = (EthernetProps *) contProps;
IPv4Props *ipProps = (IPv4Props *) ownProps; IPv4Props *ipProps = (IPv4Props *) ownProps;
return etherProps->length_type == ETH_IPv4_PACKET_CLASS && ((IP_ADDR_FROM_FILTCOND(filtCond) == ipProps->DestIPAddr) || // check header
bool headerOK = (etherProps->length_type == ETH_IPv4_PACKET_CLASS) && ((IP_ADDR_FROM_FILTCOND(filtCond) == ipProps->DestIPAddr) ||
((IP_ADDR_FROM_FILTCOND(filtCond) == IPv4_IF_ADDR) && (ipProps->DestIPAddr == intf->ip) && (intf->ip != 0))); ((IP_ADDR_FROM_FILTCOND(filtCond) == IPv4_IF_ADDR) && (ipProps->DestIPAddr == intf->ip) && (intf->ip != 0)));
return headerOK;
} }
ConnBlock ipv4_new_connblock(EthInterface *intf, ip4_addr ipAddr, SieveCallBackFn cbFn) { ConnBlock ipv4_new_connblock(EthInterface *intf, ip4_addr ipAddr, SieveCallBackFn cbFn) {

View File

@ -5,7 +5,7 @@
#include <memory.h> #include <memory.h>
#include <stdbool.h> #include <stdbool.h>
#include "tcp_window.h" #include "tcp_window.h"
#include "etherlib/dynmem.h" #include "../../../dynmem.h"
TcpWindow *tcpw_create(uint32_t size) { TcpWindow *tcpw_create(uint32_t size) {
uint32_t allocSize = sizeof(TcpWindow) + size; // calculate full allocation size uint32_t allocSize = sizeof(TcpWindow) + size; // calculate full allocation size
@ -41,7 +41,7 @@ TcpWindowSegment * tcpw_store_segment(TcpWindow * tcpw, const uint8_t * data, ui
tcpw->lastSeg->next = seg; tcpw->lastSeg->next = seg;
} }
mp_report(tcpw->mp); //mp_report(tcpw->mp);
return seg; return seg;
} }
@ -60,7 +60,7 @@ bool tcpw_acknowledge(TcpWindow * tcpw, uint32_t ackNum) {
} }
mp_free(tcpw->mp, (uint8_t *) oldFirst); // release old first segment mp_free(tcpw->mp, (uint8_t *) oldFirst); // release old first segment
mp_report(tcpw->mp); //mp_report(tcpw->mp);
return true; return true;
} else { } else {

View File

@ -1,8 +1,8 @@
#ifndef ETHERLIB_TEST_TCP_WINDOW_H #ifndef ETHERLIB_TCP_WINDOW_H
#define ETHERLIB_TEST_TCP_WINDOW_H #define ETHERLIB_TCP_WINDOW_H
#include <stdint.h> #include <stdint.h>
#include "etherlib/memory_pool.h" #include "../../../memory_pool.h"
/** /**
* TCP segment descriptor * TCP segment descriptor
@ -57,4 +57,4 @@ TcpWindowSegment * tcpw_store_segment(TcpWindow * tcpw, const uint8_t * data, ui
*/ */
bool tcpw_acknowledge(TcpWindow * tcpw, uint32_t ackNum); bool tcpw_acknowledge(TcpWindow * tcpw, uint32_t ackNum);
#endif //ETHERLIB_TEST_TCP_WINDOW_H #endif //ETHERLIB_TCP_WINDOW_H

View File

@ -6,14 +6,13 @@
#include "../packet_parsers/packet_parsers.h" #include "../packet_parsers/packet_parsers.h"
#include "../../utils.h" #include "../../utils.h"
#include "../../dynmem.h" #include "../../dynmem.h"
#include "etherlib/pckt_assembler.h" #include "../../pckt_assembler.h"
#include "etherlib/eth_interface.h" #include "../../eth_interface.h"
#include "ipv4_connblock.h" #include "ipv4_connblock.h"
#include "etherlib/prefab/packet_parsers/tcp_segment.h" #include "../../gen_queue.h"
#include "etherlib/gen_queue.h"
#include "etherlib_options.h" #include "etherlib_options.h"
#include "etherlib/prefab/conn_blocks/tcp/tcp_window.h" #include "../../prefab/conn_blocks/tcp/tcp_window.h"
#include "etherlib/global_state.h" #include "../../global_state.h"
static char *TCP_STATE_NAMES[] = { static char *TCP_STATE_NAMES[] = {
"CLOSED", "LISTEN", "SYN_RCVD", "SYN_SENT", "ESTAB", "FIN_WAIT_1", "CLOSED", "LISTEN", "SYN_RCVD", "SYN_SENT", "ESTAB", "FIN_WAIT_1",
@ -42,13 +41,19 @@ typedef struct {
uint32_t sequenceNumber; // seq. num of next transmitted octet uint32_t sequenceNumber; // seq. num of next transmitted octet
uint32_t ackNumber; // ack. number sent to the remote side (seq. num of next expected octet) uint32_t ackNumber; // ack. number sent to the remote side (seq. num of next expected octet)
uint16_t window; uint16_t window;
TcpWindow * txWin; TcpWindow *txWin;
ConnBlock connBlock; ConnBlock connBlock;
bool debug; cbd d; // connection block descriptor
uint8_t retryLimit;
uint8_t retries;
uint8_t retryTO; // retry timeout
bool8_t debug;
SieveCallBackFn userCb; SieveCallBackFn userCb;
} TcpState; } TcpState;
#define TCP_DEFAULT_MSS (1200) #define TCP_DEFAULT_MSS (1200)
#define TCP_DEFAULT_RETRY_LIMIT (5)
#define TCP_DEFAULT_RETRY_TO_HS (100)
void tcps_init(TcpState *tcps, uint16_t localPort) { void tcps_init(TcpState *tcps, uint16_t localPort) {
tcps->sequenceNumber = (uint32_t) rand(); tcps->sequenceNumber = (uint32_t) rand();
@ -60,6 +65,9 @@ void tcps_init(TcpState *tcps, uint16_t localPort) {
tcps->window = ETHLIB_DEF_TCP_WINDOW_SIZE; tcps->window = ETHLIB_DEF_TCP_WINDOW_SIZE;
tcps->txWin = tcpw_create(ETHLIB_DEF_TCP_WINDOW_SIZE); tcps->txWin = tcpw_create(ETHLIB_DEF_TCP_WINDOW_SIZE);
//tcps->rxWin = tcpw_create(ETHLIB_DEF_TCP_WINDOW_SIZE); //tcps->rxWin = tcpw_create(ETHLIB_DEF_TCP_WINDOW_SIZE);
tcps->retryLimit = TCP_DEFAULT_RETRY_LIMIT;
tcps->retryTO = TCP_DEFAULT_RETRY_TO_HS;
tcps->retries = 0;
tcps->debug = false; tcps->debug = false;
tcps->userCb = NULL; tcps->userCb = NULL;
} }
@ -68,8 +76,8 @@ void tcps_init(TcpState *tcps, uint16_t localPort) {
void tcp_init_connection(ConnBlock *connBlock); void tcp_init_connection(ConnBlock *connBlock);
static void retry_to_connect_cb(Timer * timer, AlarmUserData user) { static void retry_to_connect_cb(Timer *timer, AlarmUserData user) {
ConnBlock * connBlock = (ConnBlock *) user.ptr; ConnBlock *connBlock = (ConnBlock *) user.ptr;
tcp_init_connection(connBlock); tcp_init_connection(connBlock);
} }
@ -79,9 +87,12 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
TcpConnectionState beginState = tcps->connState; TcpConnectionState beginState = tcps->connState;
IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, pckt->header->prev); IPv4Props *ipProps = HEADER_FETCH_PROPS(IPv4Props, pckt->header->prev);
uint16_t dataSize = ipProps->TotalLength - tcpProps->DataOffset - ETH_IPv4_HEADER_SIZE; // extract data size uint16_t dataSize = ipProps->TotalLength - tcpProps->DataOffset - ETH_IPv4_HEADER_SIZE; // extract data size
int ret = 0;
bool willRetry = false; // latest operation is going to be reattempted
// process incoming packet // process incoming packet
switch (tcps->connState) { switch (tcps->connState) {
case TCP_STATE_SYN_SENT: { case TCP_STATE_SYN_SENT: {
@ -95,13 +106,15 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
// get MSS // get MSS
TcpOption *mss = tcp_get_option_by_kind(tcpProps->options, TCP_OPT_KIND_MSS); TcpOption *mss = tcp_get_option_by_kind(tcpProps->options, TCP_OPT_KIND_MSS);
if (mss == NULL) { if (mss == NULL) {
tcps->connState = TCP_STATE_CLOSED; // TODO: not this way... tcps->connState = TCP_STATE_CLOSED;
AlarmUserData alarmData; if (tcps->retries < tcps->retryLimit) {
alarmData.ptr = &tcps->connBlock; AlarmUserData alarmData;
timer_sched_rel(E.tmr, 1000000, retry_to_connect_cb, alarmData); alarmData.ptr = &tcps->connBlock;
timer_sched_rel(E.tmr, tcps->retryTO * 10000, retry_to_connect_cb, alarmData);
willRetry = true; // indicate that operation is going to be reattempted
}
break; break;
} }
FETCH_WORD_H2N(&tcps->remoteMSS, mss->value); FETCH_WORD_H2N(&tcps->remoteMSS, mss->value);
// send ACK // send ACK
@ -130,7 +143,7 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
// process data // process data
if (tcps->userCb != NULL) { if (tcps->userCb != NULL) {
PcktSieveLayerTag userTag = { 0 }; // TODO... PcktSieveLayerTag userTag = {0}; // TODO...
tcps->userCb(pckt, userTag); tcps->userCb(pckt, userTag);
} }
} else if ((dataSize == 0) && (tcps->sequenceNumber == tcpProps->AcknowledgementNumber)) { // outgoing segment was acknowledged by peer } else if ((dataSize == 0) && (tcps->sequenceNumber == tcpProps->AcknowledgementNumber)) { // outgoing segment was acknowledged by peer
@ -141,6 +154,7 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
case TCP_STATE_LAST_ACK: case TCP_STATE_LAST_ACK:
if (tcpProps->Flags & TCP_FLAG_ACK) { if (tcpProps->Flags & TCP_FLAG_ACK) {
tcps->connState = TCP_STATE_CLOSED; tcps->connState = TCP_STATE_CLOSED;
ret = SIEVE_LAYER_REMOVE_THIS; // if peer closed the connection, remove sieve layer
} }
break; break;
case TCP_STATE_CLOSED: case TCP_STATE_CLOSED:
@ -153,6 +167,14 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
MSG("%s -> %s\n", TCP_STATE_NAMES[beginState], TCP_STATE_NAMES[tcps->connState]); MSG("%s -> %s\n", TCP_STATE_NAMES[beginState], TCP_STATE_NAMES[tcps->connState]);
} }
// maintain retry counter
tcps->retries = willRetry ? (tcps->retries + 1) : 0;
// release descriptor if not meaningful anymore
if (ret == SIEVE_LAYER_REMOVE_THIS) {
cbdt_release(E.cbdt, tcps->d); // release descriptor
}
return 0; // TODO return 0; // TODO
} }
@ -235,6 +257,7 @@ cbd tcp_new_connblock(EthInterface *intf, ip4_addr ipAddr, uint16_t port, SieveC
if (d == CBDT_ERR) { // on error free everything we have allocated before if (d == CBDT_ERR) { // on error free everything we have allocated before
packsieve_remove_layer(tcpConnB.sieveLayer); packsieve_remove_layer(tcpConnB.sieveLayer);
} }
tcpState->d = d; // save descriptor
return d; return d;
} }
@ -286,6 +309,10 @@ int tcp_send_segment(const struct ConnBlock_ *connBlock, TcpFlag flags, TcpOptio
if (tcpState->remoteAddr != 0xFFFFFFFF) { if (tcpState->remoteAddr != 0xFFFFFFFF) {
ArpCache *arpc = connBlock->sieve->intf->arpc; ArpCache *arpc = connBlock->sieve->intf->arpc;
const ArpEntry *entry = arpc_get_ask(arpc, tcpState->remoteAddr); const ArpEntry *entry = arpc_get_ask(arpc, tcpState->remoteAddr);
if (entry == NULL) {
INFO("HW address cannot be ARP-ed, cannot send TCP segment!\n");
goto release_resources; // YEAH, goto HERE!
}
memcpy(ethProps->destAddr, entry, ETH_HW_ADDR_LEN); memcpy(ethProps->destAddr, entry, ETH_HW_ADDR_LEN);
} }
memcpy(ethProps->sourceAddr, connBlock->sieve->intf->mac, ETH_HW_ADDR_LEN); memcpy(ethProps->sourceAddr, connBlock->sieve->intf->mac, ETH_HW_ADDR_LEN);
@ -312,18 +339,19 @@ int tcp_send_segment(const struct ConnBlock_ *connBlock, TcpFlag flags, TcpOptio
ethinf_transmit(connBlock->sieve->intf, &raw); ethinf_transmit(connBlock->sieve->intf, &raw);
// advance TCP sequence number
tcpState->sequenceNumber += size;
// free headers // free headers
release_resources:
dynmem_free(tcpHeader); dynmem_free(tcpHeader);
dynmem_free(ipHeader); dynmem_free(ipHeader);
dynmem_free(ethHeader); dynmem_free(ethHeader);
// advance TCP sequence number
tcpState->sequenceNumber += size;
return 0; return 0;
} }
uint32_t tcp_send(cbd d, const uint8_t * data, uint32_t size) { uint32_t tcp_send(cbd d, const uint8_t *data, uint32_t size) {
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);
@ -334,7 +362,7 @@ uint32_t tcp_send(cbd d, const uint8_t * data, uint32_t size) {
if (tcps->connState == TCP_STATE_ESTAB) { // can send only data if connection is ESTABLISHED if (tcps->connState == TCP_STATE_ESTAB) { // can send only data if connection is ESTABLISHED
uint32_t maxWinSize = tcpw_get_max_window_size(tcps->txWin); uint32_t maxWinSize = tcpw_get_max_window_size(tcps->txWin);
uint32_t txSize = MIN(maxWinSize, size); // limit size to the allocable size of the retransmit buffer uint32_t txSize = MIN(maxWinSize, size); // limit size to the allocable size of the retransmit buffer
TcpWindowSegment * winSeg = tcpw_store_segment(tcps->txWin, data, txSize, tcps->sequenceNumber); // store segment for possible retransmission TcpWindowSegment *winSeg = tcpw_store_segment(tcps->txWin, data, txSize, tcps->sequenceNumber); // store segment for possible retransmission
tcp_send_segment(&connBlock, TCP_FLAG_ACK, NULL, winSeg->data, winSeg->size); tcp_send_segment(&connBlock, TCP_FLAG_ACK, NULL, winSeg->data, winSeg->size);
return txSize; return txSize;
} else { } else {
@ -342,7 +370,7 @@ uint32_t tcp_send(cbd d, const uint8_t * data, uint32_t size) {
} }
} }
void tcp_print_report(const ConnBlock* connBlock) { void tcp_print_report(const ConnBlock *connBlock) {
const PcktSieveLayer * sl = connBlock->sieveLayer; const PcktSieveLayer *sl = connBlock->sieveLayer;
INFO("TCP port: %d", TCP_PORT_FROM_FILTCOND(&sl->filtCond)); INFO("TCP port: %d", TCP_PORT_FROM_FILTCOND(&sl->filtCond));
} }

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_TCP_CONNBLOCK_H #ifndef ETHERLIB_TCP_CONNBLOCK_H
#define ETHERLIB_TEST_TCP_CONNBLOCK_H #define ETHERLIB_TCP_CONNBLOCK_H
#define TCP_PORT_FROM_FILTCOND(fc) ((fc)->uw[7]) #define TCP_PORT_FROM_FILTCOND(fc) ((fc)->uw[7])
#define TCP_PORT_TO_FILTCOND(fc,port) (((fc)->uw[7]) = (port)) #define TCP_PORT_TO_FILTCOND(fc,port) (((fc)->uw[7]) = (port))
@ -8,7 +8,7 @@
#include "../packet_parsers/ipv4_types.h" #include "../packet_parsers/ipv4_types.h"
#include "../../connection_block.h" #include "../../connection_block.h"
#include "../packet_parsers/tcp_segment.h" #include "../packet_parsers/tcp_segment.h"
#include "etherlib/cbd_table.h" #include "../../cbd_table.h"
struct EthInterface_; struct EthInterface_;
@ -54,4 +54,4 @@ void tcp_print_report(const ConnBlock* connBlock);
//int tcp_send_segment(const struct ConnBlock_ *connBlock, TcpFlag flags, TcpOption * opts, const uint8_t *data, uint32_t size); //int tcp_send_segment(const struct ConnBlock_ *connBlock, TcpFlag flags, TcpOption * opts, const uint8_t *data, uint32_t size);
#endif //ETHERLIB_TEST_TCP_CONNBLOCK_H #endif //ETHERLIB_TCP_CONNBLOCK_H

View File

@ -6,11 +6,10 @@
#include <stddef.h> #include <stddef.h>
#include "../packet_parsers/packet_parsers.h"
#include "../../utils.h" #include "../../utils.h"
#include "../../dynmem.h" #include "../../dynmem.h"
#include "etherlib/pckt_assembler.h" #include "../../pckt_assembler.h"
#include "etherlib/global_state.h" #include "../../global_state.h"
static bool filtUdp(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface *intf) { static bool filtUdp(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface *intf) {
IPv4Props *ipProps = (IPv4Props *) contProps; IPv4Props *ipProps = (IPv4Props *) contProps;
@ -86,6 +85,10 @@ int udp_sendto(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_
if (addr != 0xFFFFFFFF) { if (addr != 0xFFFFFFFF) {
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) {
INFO("HW address cannot be ARP-ed, cannot send UDP datagram!\n");
goto release_resources; // YEAH, goto HERE!
}
memcpy(ethProps->destAddr, entry, ETH_HW_ADDR_LEN); memcpy(ethProps->destAddr, entry, ETH_HW_ADDR_LEN);
} else { } else {
memset(ethProps->destAddr, 0xFF, ETH_HW_ADDR_LEN); memset(ethProps->destAddr, 0xFF, ETH_HW_ADDR_LEN);
@ -112,6 +115,7 @@ int udp_sendto(cbd d, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_
ethinf_transmit(connBlock.sieve->intf, &raw); ethinf_transmit(connBlock.sieve->intf, &raw);
release_resources:
// free headers // free headers
dynmem_free(udpHeader); dynmem_free(udpHeader);
dynmem_free(ipHeader); dynmem_free(ipHeader);

View File

@ -5,7 +5,7 @@
#include "../../connection_block.h" #include "../../connection_block.h"
#include "../../eth_interface.h" #include "../../eth_interface.h"
#include "ipv4_connblock.h" #include "ipv4_connblock.h"
#include "etherlib/cbd_table.h" #include "../../cbd_table.h"
#define UDP_PORT_FROM_FILTCOND(fc) ((fc)->uw[0]) #define UDP_PORT_FROM_FILTCOND(fc) ((fc)->uw[0])
#define UDP_PORT_TO_FILTCOND(fc,port) (((fc)->uw[0]) = (port)) #define UDP_PORT_TO_FILTCOND(fc,port) (((fc)->uw[0]) = (port))

View File

@ -3,7 +3,6 @@
// //
#include "arp_packet.h" #include "arp_packet.h"
#include "../../packet_registry.h"
#include "ethernet_frame.h" #include "ethernet_frame.h"
#include "../../utils.h" #include "../../utils.h"
#include "../../eth_interface.h" #include "../../eth_interface.h"
@ -24,7 +23,7 @@ static void arp_fetch_mapping(const ArpProps * arpProps, ArpCache * arpc) {
} }
} }
int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb) {
// parse ARP packet // parse ARP packet
ArpProps *arpProps = HEADER_FETCH_PROPS(ArpProps, pcktHdrLe); ArpProps *arpProps = HEADER_FETCH_PROPS(ArpProps, pcktHdrLe);
FETCH_WORD_H2N_ADVANCE(&arpProps->HTYPE, hdr); // hardware type FETCH_WORD_H2N_ADVANCE(&arpProps->HTYPE, hdr); // hardware type
@ -38,13 +37,14 @@ int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
FETCH_ADVANCE(&arpProps->TPA, hdr, sizeof(ip4_addr)); // target protocol address FETCH_ADVANCE(&arpProps->TPA, hdr, sizeof(ip4_addr)); // target protocol address
// fill-in common packet header fields // fill-in common packet header fields
arpProps->validityOK = true; arpProps->validityOK = true; // TODO!
arpProps->containedPacketClass = 0; arpProps->containedPacketClass = 0;
arpProps->headerSize = ETH_ARP_HEADER_SIZE; arpProps->headerSize = ETH_ARP_HEADER_SIZE;
// learn new mapping // learn new mapping
arp_fetch_mapping(arpProps, intf->arpc); arp_fetch_mapping(arpProps, intf->arpc);
return 0;
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) {

View File

@ -2,8 +2,8 @@
// Created by epagris on 2022.12.08.. // Created by epagris on 2022.12.08..
// //
#ifndef ETHERLIB_TEST_ARP_PACKET_H #ifndef ETHERLIB_ARP_PACKET_H
#define ETHERLIB_TEST_ARP_PACKET_H #define ETHERLIB_ARP_PACKET_H
#include <stdint.h> #include <stdint.h>
#include "ipv4_types.h" #include "ipv4_types.h"
@ -51,7 +51,7 @@ typedef struct {
* @param intf Ethernet interface * @param intf Ethernet interface
* @return always 0 OR -1 on failure * @return always 0 OR -1 on failure
*/ */
int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb);
/** /**
* Insert ARP header into packet. * Insert ARP header into packet.
@ -60,5 +60,5 @@ int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
*/ */
void insert_arp_header(uint8_t *hdr, const PcktHeaderElement *headers); void insert_arp_header(uint8_t *hdr, const PcktHeaderElement *headers);
#endif //ETHERLIB_TEST_ARP_PACKET_H #endif //ETHERLIB_ARP_PACKET_H

View File

@ -8,7 +8,7 @@
#include "../../utils.h" #include "../../utils.h"
#include "../../connection_block.h" #include "../../connection_block.h"
#include "../conn_blocks/udp_connblock.h" #include "../conn_blocks/udp_connblock.h"
#include "etherlib/global_state.h" #include "../../global_state.h"
static struct { static struct {
DhcpState state; DhcpState state;

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_DHCP_H #ifndef ETHERLIB_DHCP_H
#define ETHERLIB_TEST_DHCP_H #define ETHERLIB_DHCP_H
#include <stdint.h> #include <stdint.h>
#include "../../eth_interface.h" #include "../../eth_interface.h"
@ -58,4 +58,4 @@ void dhcp_initiate(EthInterface * intf);
*/ */
void dhcp_start(); void dhcp_start();
#endif //ETHERLIB_TEST_DHCP_H #endif //ETHERLIB_DHCP_H

View File

@ -12,7 +12,7 @@
EthernetAddress ETH_ETHERNET_IPMC_HWADDR = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 }; EthernetAddress ETH_ETHERNET_IPMC_HWADDR = { 0x01, 0x00, 0x5E, 0x00, 0x00, 0x00 };
int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData * pb) {
EthernetProps * frameProps = (EthernetProps *) &pcktHdrLe->props; EthernetProps * frameProps = (EthernetProps *) &pcktHdrLe->props;
FETCH_ADVANCE(frameProps->destAddr, hdr, ETH_HW_ADDR_LEN); // copy destination address 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_ADVANCE(frameProps->sourceAddr, hdr, ETH_HW_ADDR_LEN); // copy destination address

View File

@ -42,7 +42,7 @@ struct EthInterface_;
* @param pcktHdrLe pointer to property storage * @param pcktHdrLe pointer to property storage
* @return EtherType or 0 (if size is less than 1500) on success or -1 on error * @return EtherType or 0 (if size is less than 1500) on success or -1 on error
*/ */
int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData * pb);
/** /**
* Insert Ethernet header to specified address. * Insert Ethernet header to specified address.

View File

@ -6,7 +6,7 @@
#include "../../utils.h" #include "../../utils.h"
#include "ipv4_packet.h" #include "ipv4_packet.h"
int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb) {
const uint8_t * hdrStart = hdr; const uint8_t * hdrStart = hdr;
// parse header // parse header
@ -23,7 +23,7 @@ int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
icmpProps->containedPacketClass = 0; icmpProps->containedPacketClass = 0;
icmpProps->headerSize = ETH_ICMP_HEADER_SIZE; icmpProps->headerSize = ETH_ICMP_HEADER_SIZE;
return 0; 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) {

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_ICMP_PACKET_H #ifndef ETHERLIB_ICMP_PACKET_H
#define ETHERLIB_TEST_ICMP_PACKET_H #define ETHERLIB_ICMP_PACKET_H
#include <stdint.h> #include <stdint.h>
#include "ipv4_types.h" #include "ipv4_types.h"
@ -34,7 +34,7 @@ typedef struct {
* @param intf Ethernet interface through which transmission and reception is carried out * @param intf Ethernet interface through which transmission and reception is carried out
* @return always 0 * @return always 0
*/ */
int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb);
/** /**
* Insert ICMP header. * Insert ICMP header.
@ -43,4 +43,4 @@ int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
*/ */
void insert_icmp_header(uint8_t * hdr, const PcktHeaderElement * headers); void insert_icmp_header(uint8_t * hdr, const PcktHeaderElement * headers);
#endif //ETHERLIB_TEST_ICMP_PACKET_H #endif //ETHERLIB_ICMP_PACKET_H

View File

@ -40,7 +40,7 @@ void insert_igmp_header(uint8_t *hdr, const PcktHeaderElement *headers) {
memcpy(ChkSumPtr, &igmpProps->checksum, 2); memcpy(ChkSumPtr, &igmpProps->checksum, 2);
} }
int parse_igmp(const uint8_t * hdr, uint32_t size, PcktHeaderElement * pcktHdrLe, struct EthInterface_ * intf) { int parse_igmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb) {
// parse header // parse header
IgmpProps *igmpProps = HEADER_FETCH_PROPS(IgmpProps, pcktHdrLe); IgmpProps *igmpProps = HEADER_FETCH_PROPS(IgmpProps, pcktHdrLe);
FETCH_BYTE_ADVANCE(&igmpProps->type, hdr); FETCH_BYTE_ADVANCE(&igmpProps->type, hdr);
@ -54,5 +54,5 @@ int parse_igmp(const uint8_t * hdr, uint32_t size, PcktHeaderElement * pcktHdrLe
igmpProps->containedPacketClass = 0; igmpProps->containedPacketClass = 0;
igmpProps->headerSize = ETH_IGMP_HEADER_SIZE; igmpProps->headerSize = ETH_IGMP_HEADER_SIZE;
return 0; return igmpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT;
} }

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_IGMP_PACKET_H #ifndef ETHERLIB_IGMP_PACKET_H
#define ETHERLIB_TEST_IGMP_PACKET_H #define ETHERLIB_IGMP_PACKET_H
#include <stdint.h> #include <stdint.h>
#include "ipv4_types.h" #include "ipv4_types.h"
@ -43,6 +43,6 @@ void insert_igmp_header(uint8_t * hdr, const PcktHeaderElement * headers);
* @param intf Ethernet interface * @param intf Ethernet interface
* @return always 0 * @return always 0
*/ */
int parse_igmp(const uint8_t * hdr, uint32_t size, PcktHeaderElement * pcktHdrLe, struct EthInterface_ * intf); int parse_igmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb);
#endif //ETHERLIB_TEST_IGMP_PACKET_H #endif //ETHERLIB_IGMP_PACKET_H

View File

@ -15,12 +15,12 @@ static bool check_ipv4_validity(const uint8_t *hdr, const IPv4Props *ipProps) {
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) && (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;
} }
int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData * pb) {
const uint8_t *hdrBegin = hdr; const uint8_t *hdrBegin = hdr;
IPv4Props *ipProps = HEADER_FETCH_PROPS(IPv4Props, pcktHdrLe); IPv4Props *ipProps = HEADER_FETCH_PROPS(IPv4Props, pcktHdrLe);
uint8_t version_length; uint8_t version_length;
@ -33,7 +33,7 @@ int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
uint16_t flags_fragOffset; uint16_t flags_fragOffset;
FETCH_WORD_H2N_ADVANCE(&flags_fragOffset, hdr); FETCH_WORD_H2N_ADVANCE(&flags_fragOffset, hdr);
ipProps->Flags = (flags_fragOffset >> 13) & 0x07; ipProps->Flags = (flags_fragOffset >> 13) & 0x07;
ipProps->FragmentOffset = (flags_fragOffset & ~(0x07 << 13)); ipProps->FragmentOffset = (flags_fragOffset & ~(0x07 << 13)) << 3;
FETCH_ADVANCE(&ipProps->TTL, hdr, 1); FETCH_ADVANCE(&ipProps->TTL, hdr, 1);
FETCH_ADVANCE(&ipProps->Protocol, hdr, 1); FETCH_ADVANCE(&ipProps->Protocol, hdr, 1);
FETCH_WORD_H2N_ADVANCE(&ipProps->HeaderChecksum, hdr); FETCH_WORD_H2N_ADVANCE(&ipProps->HeaderChecksum, hdr);
@ -54,7 +54,26 @@ int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
arpc_learn(intf->arpc, &entry); // learn new assignment arpc_learn(intf->arpc, &entry); // learn new assignment
} }
return ipProps->validityOK ? ipProps->Protocol : -1; // check whether it is a fragmented packet
bool isAFragment = (ipProps->FragmentOffset != 0) || (ipProps->Flags & IP_FLAG_MF);
if (isAFragment) {
const uint8_t * payloadStart = hdr;
ipra_input(intf->ipra, ipProps, payloadStart, size - ETH_IP_HEADER_LENGTH); // input fragment into assembler
uint8_t * raPload;
uint16_t raSize;
bool raOK = ipra_try_reassemble(intf->ipra, ipProps->Identification, &raPload, &raSize, pcktHdrLe);
if (raOK) {
pb->p = raPload;
pb->u = raSize;
pb->b = true; // MRD!
return PROC_FN_RET_REPRST; // replace buffer and restart processing (with the assembled packet)
} else {
ipProps->containedPacketClass = 0; // no contained packet if not assembled yet
return PROC_FN_RET_ABORT; // stop further processing
}
}
return ipProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT;
} }
static uint16_t nextIpIdentification = 0; static uint16_t nextIpIdentification = 0;

View File

@ -9,6 +9,11 @@
#define ETH_IPv4_PACKET_CLASS (0x0800) #define ETH_IPv4_PACKET_CLASS (0x0800)
#define ETH_IPv4_HEADER_SIZE (20) #define ETH_IPv4_HEADER_SIZE (20)
typedef enum {
IP_FLAG_DNF = 0x02,
IP_FLAG_MF = 0x01
} IPv4Flags;
/** /**
* IPv4 header structure * IPv4 header structure
*/ */
@ -45,7 +50,7 @@ struct EthInterface_;
* @param pcktHdrLe pointer to property storage * @param pcktHdrLe pointer to property storage
* @return Protocol on success or -1 on failure * @return Protocol on success or -1 on failure
*/ */
int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData * pb);
/** /**
* Insert IPv4 header. * Insert IPv4 header.

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_IPV4_TYPES_H #ifndef ETHERLIB_IPV4_TYPES_H
#define ETHERLIB_TEST_IPV4_TYPES_H #define ETHERLIB_IPV4_TYPES_H
#include <stdint.h> #include <stdint.h>
@ -8,4 +8,4 @@ typedef uint32_t ip4_addr;
#define IPv4_ANY_ADDR (0xFFFFFFFF) #define IPv4_ANY_ADDR (0xFFFFFFFF)
#define IPv4_IF_ADDR (0x00000000) #define IPv4_IF_ADDR (0x00000000)
#endif //ETHERLIB_TEST_IPV4_TYPES_H #endif //ETHERLIB_IPV4_TYPES_H

View File

@ -3,6 +3,11 @@
#include "ethernet_frame.h" #include "ethernet_frame.h"
#include "ipv4_packet.h" #include "ipv4_packet.h"
#include "arp_packet.h"
#include "icmp_packet.h"
#include "igmp_packet.h"
#include "tcp_segment.h"
#include "udp_packet.h" #include "udp_packet.h"
#include "dhcp.h"
#endif //ETHERLIB_PACKET_PARSERS_H #endif //ETHERLIB_PACKET_PARSERS_H

View File

@ -3,9 +3,9 @@
// //
#include "tcp_segment.h" #include "tcp_segment.h"
#include "etherlib/utils.h" #include "../../utils.h"
#include "ethernet_frame.h" #include "ethernet_frame.h"
#include "etherlib/dynmem.h" #include "../../dynmem.h"
#include "tcp_udp_common.h" #include "tcp_udp_common.h"
#include "ipv4_packet.h" #include "ipv4_packet.h"
@ -112,7 +112,7 @@ TcpOption * tcp_get_option_by_kind(TcpOption * opt, uint16_t kind) {
return res; return res;
} }
int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb) {
const uint8_t * hdrBegin = hdr; const uint8_t * hdrBegin = hdr;
// fetch fixed portion of the segment header // fetch fixed portion of the segment header
@ -150,7 +150,7 @@ int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
tcpProps->validityOK = (chkSum == 0); tcpProps->validityOK = (chkSum == 0);
tcpProps->containedPacketClass = 0; tcpProps->containedPacketClass = 0;
return tcpProps->validityOK ? 0 : -1; 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) {

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_TCP_SEGMENT_H #ifndef ETHERLIB_TCP_SEGMENT_H
#define ETHERLIB_TEST_TCP_SEGMENT_H #define ETHERLIB_TCP_SEGMENT_H
#include <stdint.h> #include <stdint.h>
#include "../../packet_sieve.h" #include "../../packet_sieve.h"
@ -94,7 +94,7 @@ struct EthInterface_;
* @param pcktHdrLe pointer to property storage * @param pcktHdrLe pointer to property storage
* @return 0 on success or -1 on failure * @return 0 on success or -1 on failure
*/ */
int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); int parse_tcp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb);
/** /**
* Insert TCP header. * Insert TCP header.
@ -118,4 +118,4 @@ uint32_t tcp_get_options_size(TcpOption * optLe);
*/ */
TcpOption * tcp_get_option_by_kind(TcpOption * opt, uint16_t kind); TcpOption * tcp_get_option_by_kind(TcpOption * opt, uint16_t kind);
#endif //ETHERLIB_TEST_TCP_SEGMENT_H #endif //ETHERLIB_TCP_SEGMENT_H

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_TCP_UDP_COMMON_H #ifndef ETHERLIB_TCP_UDP_COMMON_H
#define ETHERLIB_TEST_TCP_UDP_COMMON_H #define ETHERLIB_TCP_UDP_COMMON_H
#include <stdint.h> #include <stdint.h>
@ -20,4 +20,4 @@ typedef struct {
*/ */
uint16_t tcp_udp_checksum(const IPv4PseudoHeader *pseudoHeader, const uint8_t * hdr, uint32_t size); uint16_t tcp_udp_checksum(const IPv4PseudoHeader *pseudoHeader, const uint8_t * hdr, uint32_t size);
#endif //ETHERLIB_TEST_TCP_UDP_COMMON_H #endif //ETHERLIB_TCP_UDP_COMMON_H

View File

@ -17,7 +17,7 @@ static bool check_udp_validity(const uint8_t * hdr, const PcktHeaderElement *pck
return valid; return valid;
} }
int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb) {
const uint8_t * hdrBegin = hdr; const uint8_t * hdrBegin = hdr;
UdpProps *udpProps = HEADER_FETCH_PROPS(UdpProps, pcktHdrLe); UdpProps *udpProps = HEADER_FETCH_PROPS(UdpProps, pcktHdrLe);
FETCH_WORD_H2N_ADVANCE(&udpProps->SourcePort, hdr); FETCH_WORD_H2N_ADVANCE(&udpProps->SourcePort, hdr);
@ -30,7 +30,7 @@ int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, s
udpProps->validityOK = check_udp_validity(hdrBegin, pcktHdrLe); udpProps->validityOK = check_udp_validity(hdrBegin, pcktHdrLe);
udpProps->containedPacketClass = 0; udpProps->containedPacketClass = 0;
return udpProps->validityOK ? 0 : -1; 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) {

View File

@ -30,7 +30,7 @@ struct EthInterface_;
* @param pcktHdrLe pointer to property storage * @param pcktHdrLe pointer to property storage
* @return 0 on success or -1 on failure * @return 0 on success or -1 on failure
*/ */
int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf, PcktProcFnPassbackData *pb);
/** /**
* Insert UDP header. * Insert UDP header.

View File

@ -1,5 +1,5 @@
#ifndef ETHERLIB_TEST_TIMER_H #ifndef ETHERLIB_TIMER_H
#define ETHERLIB_TEST_TIMER_H #define ETHERLIB_TIMER_H
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
@ -40,7 +40,7 @@ struct Timer_;
/** /**
* Alarm user data. * Alarm user data.
*/ */
typedef union { typedef struct {
void * ptr; void * ptr;
uint32_t u; uint32_t u;
} AlarmUserData; } AlarmUserData;
@ -136,4 +136,4 @@ void timer_tick(Timer * tmr, int64_t us);
*/ */
void timer_report(const Timer * tmr); void timer_report(const Timer * tmr);
#endif //ETHERLIB_TEST_TIMER_H #endif //ETHERLIB_TIMER_H