-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:
parent
8676a392e5
commit
ac5fc9c529
@ -42,6 +42,10 @@ void arpc_free(ArpCache *aprc) {
|
||||
}
|
||||
|
||||
void arpc_learn(ArpCache *arpc, const ArpEntry *newEntry) {
|
||||
if (newEntry->eth[0] & 0x01) { // don't learn multicast addresses
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: nagyon dummy...
|
||||
for (uint16_t i = 0; i < arpc->fill; i++) {
|
||||
ArpEntry * entry = arpc->entries + i;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_ARP_CACHE_H
|
||||
#define ETHERLIB_TEST_ARP_CACHE_H
|
||||
#ifndef ETHERLIB_ARP_CACHE_H
|
||||
#define ETHERLIB_ARP_CACHE_H
|
||||
|
||||
#include "prefab/packet_parsers/ethernet_frame.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);
|
||||
|
||||
#endif //ETHERLIB_TEST_ARP_CACHE_H
|
||||
#endif //ETHERLIB_ARP_CACHE_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_CBD_TABLE_H
|
||||
#define ETHERLIB_TEST_CBD_TABLE_H
|
||||
#ifndef ETHERLIB_CBD_TABLE_H
|
||||
#define ETHERLIB_CBD_TABLE_H
|
||||
|
||||
#include <stdint.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);
|
||||
|
||||
#endif //ETHERLIB_TEST_CBD_TABLE_H
|
||||
#endif //ETHERLIB_CBD_TABLE_H
|
||||
|
@ -62,6 +62,41 @@ p.reference, p.definition {
|
||||
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 */
|
||||
|
||||
h1.groupheader {
|
||||
|
4
dynmem.h
4
dynmem.h
@ -3,6 +3,10 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef DYNMEM_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize EtherLib dynamic memory management subsystem,
|
||||
* based on heap pointer and size given in etherlib_options.h
|
||||
|
@ -32,6 +32,8 @@ EthInterface *ethintf_new(EthIODef * io) {
|
||||
|
||||
ethIntf->txQ = mq_create(ETHLIB_DEF_MQ_SIZE);
|
||||
|
||||
ethIntf->ipra = ipra_new();
|
||||
|
||||
return ethIntf;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "arp_cache.h"
|
||||
#include "connection_block.h"
|
||||
#include "msg_queue.h"
|
||||
#include "prefab/conn_blocks/ipv4/ip_assembler.h"
|
||||
|
||||
/**
|
||||
* Ethernet interface low level definition.
|
||||
@ -35,6 +36,7 @@ typedef struct EthInterface_ {
|
||||
ArpCache * arpc; ///< ARP cache
|
||||
ConnBlock arpCb; ///< ARP connection block
|
||||
MsgQueue * txQ; ///< Transmit queue
|
||||
IPv4Assembler * ipra; ///< IPv4 reassembler
|
||||
} EthInterface;
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_MSG_QUEUE_H
|
||||
#define ETHERLIB_TEST_MSG_QUEUE_H
|
||||
#ifndef ETHERLIB_MSG_QUEUE_H
|
||||
#define ETHERLIB_MSG_QUEUE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "packet.h"
|
||||
@ -52,4 +52,4 @@ RawPckt mq_top(MsgQueue * mq);
|
||||
*/
|
||||
void mq_pop(MsgQueue * mq);
|
||||
|
||||
#endif //ETHERLIB_TEST_MSG_QUEUE_H
|
||||
#endif //ETHERLIB_MSG_QUEUE_H
|
||||
|
@ -44,6 +44,17 @@ typedef struct {
|
||||
PcktPropsHeader
|
||||
} 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);
|
||||
* @brief Pckt processing function template.
|
||||
@ -52,11 +63,9 @@ typedef struct {
|
||||
* @param props: pointer to existing structure to store
|
||||
* packet properties to (e.g. source address, port etc.)
|
||||
* @param intf associeated Ethernet interface
|
||||
* @return packet class of contained packet, or -1 on failure or
|
||||
* 0 if no more standard packet contained (e.g. UDP packet contains
|
||||
* user data)
|
||||
* @return one of the special processing function return values
|
||||
*/
|
||||
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
|
||||
|
@ -24,15 +24,18 @@ PcktSieve *packsieve_new(EthInterface * intf) {
|
||||
return sieve;
|
||||
}
|
||||
|
||||
void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
|
||||
void packsieve_input(PcktSieve *sieve, const RawPckt *rawPckt) {
|
||||
// extract fields
|
||||
uint8_t *data = rawPckt->payload;
|
||||
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.
|
||||
uint16_t ownClass = 0, containerClass = 0; // Ethernet...
|
||||
uint16_t offset = 0;
|
||||
PcktHeaderElement *lastHeader = NULL, *outermostHeader = NULL;
|
||||
int procRet;
|
||||
|
||||
do {
|
||||
// get packet descriptor
|
||||
@ -56,7 +59,22 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (containedClass != 0) {
|
||||
containerClass = ownClass;
|
||||
@ -83,7 +101,7 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
|
||||
|
||||
// lookup headers in the sieve
|
||||
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
|
||||
while (found && headerIter) {
|
||||
const PcktSieveLayer *nodeIter = layer->nodes;
|
||||
@ -99,7 +117,16 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
|
||||
packet.payload = data + offset;
|
||||
packet.headerSize = 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;
|
||||
} else {
|
||||
@ -123,6 +150,13 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt) {
|
||||
dynmem_free(iter);
|
||||
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) {
|
||||
@ -214,7 +248,7 @@ bool packsieve_remove_layer(PcktSieveLayer *layer) {
|
||||
void packsieve_report(const PcktSieve * sieve, const PcktSieveLayer *layer, uint32_t indent) {
|
||||
if (layer->connBReportFn != NULL) {
|
||||
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);
|
||||
INFO("├───\n");
|
||||
} else {
|
||||
@ -231,7 +265,7 @@ void packsieve_layer_info(const PcktSieve * sieve, const PcktSieveLayer * layer)
|
||||
const PcktSieveLayer *iter = layer;
|
||||
while (iter != NULL) { // climb up to the top in the sieve tree
|
||||
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);
|
||||
} else {
|
||||
INFO("[%d]", layer->packetClass);
|
||||
|
@ -64,6 +64,9 @@ typedef union {
|
||||
uint32_t u;
|
||||
} PcktSieveLayerTag;
|
||||
|
||||
// actions triggered by callback function returns
|
||||
#define SIEVE_LAYER_REMOVE_THIS (-100)
|
||||
|
||||
/**
|
||||
* Callback function type for packet sieve match.
|
||||
*/
|
||||
@ -114,7 +117,7 @@ PcktSieve * packsieve_new();
|
||||
* @param data
|
||||
* @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.
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_PCKT_ASSEMBLER_H
|
||||
#define ETHERLIB_TEST_PCKT_ASSEMBLER_H
|
||||
#ifndef ETHERLIB_PCKT_ASSEMBLER_H
|
||||
#define ETHERLIB_PCKT_ASSEMBLER_H
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
@ -15,4 +15,4 @@ struct EthInterface_;
|
||||
*/
|
||||
int pckt_assemble(RawPckt *raw, Pckt *cooked);
|
||||
|
||||
#endif //ETHERLIB_TEST_PCKT_ASSEMBLER_H
|
||||
#endif //ETHERLIB_PCKT_ASSEMBLER_H
|
||||
|
@ -2,10 +2,8 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../packet_parsers/packet_parsers.h"
|
||||
#include "../../utils.h"
|
||||
#include "../../dynmem.h"
|
||||
#include "../packet_parsers/arp_packet.h"
|
||||
|
||||
static bool filtArp(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps, EthInterface * intf) {
|
||||
EthernetProps * ethProps = (EthernetProps *) contProps;
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef ETHERLIB_TEST_ARP_CONNBLOCK_H
|
||||
#define ETHERLIB_TEST_ARP_CONNBLOCK_H
|
||||
#ifndef ETHERLIB_ARP_CONNBLOCK_H
|
||||
#define ETHERLIB_ARP_CONNBLOCK_H
|
||||
|
||||
#endif //ETHERLIB_TEST_ARP_CONNBLOCK_H
|
||||
#endif //ETHERLIB_ARP_CONNBLOCK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../../connection_block.h"
|
||||
|
@ -1,8 +1,8 @@
|
||||
#ifndef ETHERLIB_TEST_ETHERNET_INFO_H
|
||||
#define ETHERLIB_TEST_ETHERNET_INFO_H
|
||||
#ifndef ETHERLIB_ETHERNET_INFO_H
|
||||
#define ETHERLIB_ETHERNET_INFO_H
|
||||
|
||||
|
||||
#include "etherlib/connection_block.h"
|
||||
#include "../../connection_block.h"
|
||||
|
||||
/**
|
||||
* Print Ethernet sieve layer info.
|
||||
@ -10,4 +10,4 @@
|
||||
*/
|
||||
void ethernet_print_report(const ConnBlock* connBlock);
|
||||
|
||||
#endif //ETHERLIB_TEST_ETHERNET_INFO_H
|
||||
#endif //ETHERLIB_ETHERNET_INFO_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_ICMP_CONNBLOCK_H
|
||||
#define ETHERLIB_TEST_ICMP_CONNBLOCK_H
|
||||
#ifndef ETHERLIB_ICMP_CONNBLOCK_H
|
||||
#define ETHERLIB_ICMP_CONNBLOCK_H
|
||||
|
||||
#include "../../connection_block.h"
|
||||
|
||||
@ -18,4 +18,4 @@ ConnBlock icmp_new_connblock(struct EthInterface_ * intf);
|
||||
*/
|
||||
void icmp_print_report(const ConnBlock* connBlock);
|
||||
|
||||
#endif //ETHERLIB_TEST_ICMP_CONNBLOCK_H
|
||||
#endif //ETHERLIB_ICMP_CONNBLOCK_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_IGMP_CONNBLOCK_H
|
||||
#define ETHERLIB_TEST_IGMP_CONNBLOCK_H
|
||||
#ifndef ETHERLIB_IGMP_CONNBLOCK_H
|
||||
#define ETHERLIB_IGMP_CONNBLOCK_H
|
||||
|
||||
#include "../../connection_block.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);
|
||||
|
||||
#endif //ETHERLIB_TEST_IGMP_CONNBLOCK_H
|
||||
#endif //ETHERLIB_IGMP_CONNBLOCK_H
|
||||
|
196
prefab/conn_blocks/ipv4/ip_assembler.c
Normal file
196
prefab/conn_blocks/ipv4/ip_assembler.c
Normal 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;
|
||||
}
|
54
prefab/conn_blocks/ipv4/ip_assembler.h
Normal file
54
prefab/conn_blocks/ipv4/ip_assembler.h
Normal 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
|
@ -4,15 +4,17 @@
|
||||
|
||||
#include "ipv4_connblock.h"
|
||||
|
||||
#include "../packet_parsers/packet_parsers.h"
|
||||
#include "../../utils.h"
|
||||
#include "../../global_state.h"
|
||||
|
||||
static bool filtIPv4(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface * intf) {
|
||||
EthernetProps *etherProps = (EthernetProps *) contProps;
|
||||
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)));
|
||||
return headerOK;
|
||||
}
|
||||
|
||||
ConnBlock ipv4_new_connblock(EthInterface *intf, ip4_addr ipAddr, SieveCallBackFn cbFn) {
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <memory.h>
|
||||
#include <stdbool.h>
|
||||
#include "tcp_window.h"
|
||||
#include "etherlib/dynmem.h"
|
||||
#include "../../../dynmem.h"
|
||||
|
||||
TcpWindow *tcpw_create(uint32_t 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;
|
||||
}
|
||||
|
||||
mp_report(tcpw->mp);
|
||||
//mp_report(tcpw->mp);
|
||||
|
||||
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_report(tcpw->mp);
|
||||
//mp_report(tcpw->mp);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
@ -1,8 +1,8 @@
|
||||
#ifndef ETHERLIB_TEST_TCP_WINDOW_H
|
||||
#define ETHERLIB_TEST_TCP_WINDOW_H
|
||||
#ifndef ETHERLIB_TCP_WINDOW_H
|
||||
#define ETHERLIB_TCP_WINDOW_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "etherlib/memory_pool.h"
|
||||
#include "../../../memory_pool.h"
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
#endif //ETHERLIB_TEST_TCP_WINDOW_H
|
||||
#endif //ETHERLIB_TCP_WINDOW_H
|
||||
|
@ -6,14 +6,13 @@
|
||||
#include "../packet_parsers/packet_parsers.h"
|
||||
#include "../../utils.h"
|
||||
#include "../../dynmem.h"
|
||||
#include "etherlib/pckt_assembler.h"
|
||||
#include "etherlib/eth_interface.h"
|
||||
#include "../../pckt_assembler.h"
|
||||
#include "../../eth_interface.h"
|
||||
#include "ipv4_connblock.h"
|
||||
#include "etherlib/prefab/packet_parsers/tcp_segment.h"
|
||||
#include "etherlib/gen_queue.h"
|
||||
#include "../../gen_queue.h"
|
||||
#include "etherlib_options.h"
|
||||
#include "etherlib/prefab/conn_blocks/tcp/tcp_window.h"
|
||||
#include "etherlib/global_state.h"
|
||||
#include "../../prefab/conn_blocks/tcp/tcp_window.h"
|
||||
#include "../../global_state.h"
|
||||
|
||||
static char *TCP_STATE_NAMES[] = {
|
||||
"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 ackNumber; // ack. number sent to the remote side (seq. num of next expected octet)
|
||||
uint16_t window;
|
||||
TcpWindow * txWin;
|
||||
TcpWindow *txWin;
|
||||
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;
|
||||
} TcpState;
|
||||
|
||||
#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) {
|
||||
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->txWin = 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->userCb = NULL;
|
||||
}
|
||||
@ -68,8 +76,8 @@ void tcps_init(TcpState *tcps, uint16_t localPort) {
|
||||
|
||||
void tcp_init_connection(ConnBlock *connBlock);
|
||||
|
||||
static void retry_to_connect_cb(Timer * timer, AlarmUserData user) {
|
||||
ConnBlock * connBlock = (ConnBlock *) user.ptr;
|
||||
static void retry_to_connect_cb(Timer *timer, AlarmUserData user) {
|
||||
ConnBlock *connBlock = (ConnBlock *) user.ptr;
|
||||
tcp_init_connection(connBlock);
|
||||
}
|
||||
|
||||
@ -79,9 +87,12 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
||||
|
||||
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
|
||||
|
||||
int ret = 0;
|
||||
bool willRetry = false; // latest operation is going to be reattempted
|
||||
|
||||
// process incoming packet
|
||||
switch (tcps->connState) {
|
||||
case TCP_STATE_SYN_SENT: {
|
||||
@ -95,13 +106,15 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
||||
// get MSS
|
||||
TcpOption *mss = tcp_get_option_by_kind(tcpProps->options, TCP_OPT_KIND_MSS);
|
||||
if (mss == NULL) {
|
||||
tcps->connState = TCP_STATE_CLOSED; // TODO: not this way...
|
||||
tcps->connState = TCP_STATE_CLOSED;
|
||||
if (tcps->retries < tcps->retryLimit) {
|
||||
AlarmUserData alarmData;
|
||||
alarmData.ptr = &tcps->connBlock;
|
||||
timer_sched_rel(E.tmr, 1000000, retry_to_connect_cb, alarmData);
|
||||
timer_sched_rel(E.tmr, tcps->retryTO * 10000, retry_to_connect_cb, alarmData);
|
||||
willRetry = true; // indicate that operation is going to be reattempted
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
FETCH_WORD_H2N(&tcps->remoteMSS, mss->value);
|
||||
|
||||
// send ACK
|
||||
@ -130,7 +143,7 @@ int tcp_receive_segment_cb(const Pckt *pckt, PcktSieveLayerTag tag) {
|
||||
|
||||
// process data
|
||||
if (tcps->userCb != NULL) {
|
||||
PcktSieveLayerTag userTag = { 0 }; // TODO...
|
||||
PcktSieveLayerTag userTag = {0}; // TODO...
|
||||
tcps->userCb(pckt, userTag);
|
||||
}
|
||||
} 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:
|
||||
if (tcpProps->Flags & TCP_FLAG_ACK) {
|
||||
tcps->connState = TCP_STATE_CLOSED;
|
||||
ret = SIEVE_LAYER_REMOVE_THIS; // if peer closed the connection, remove sieve layer
|
||||
}
|
||||
break;
|
||||
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]);
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@ -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
|
||||
packsieve_remove_layer(tcpConnB.sieveLayer);
|
||||
}
|
||||
tcpState->d = d; // save descriptor
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -286,6 +309,10 @@ int tcp_send_segment(const struct ConnBlock_ *connBlock, TcpFlag flags, TcpOptio
|
||||
if (tcpState->remoteAddr != 0xFFFFFFFF) {
|
||||
ArpCache *arpc = connBlock->sieve->intf->arpc;
|
||||
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->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);
|
||||
|
||||
// advance TCP sequence number
|
||||
tcpState->sequenceNumber += size;
|
||||
|
||||
// free headers
|
||||
release_resources:
|
||||
dynmem_free(tcpHeader);
|
||||
dynmem_free(ipHeader);
|
||||
dynmem_free(ethHeader);
|
||||
|
||||
// advance TCP sequence number
|
||||
tcpState->sequenceNumber += size;
|
||||
|
||||
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;
|
||||
if (!cbdt_get_connection_block(E.cbdt, d, &connBlock)) {
|
||||
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
|
||||
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
|
||||
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);
|
||||
return txSize;
|
||||
} 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) {
|
||||
const PcktSieveLayer * sl = connBlock->sieveLayer;
|
||||
void tcp_print_report(const ConnBlock *connBlock) {
|
||||
const PcktSieveLayer *sl = connBlock->sieveLayer;
|
||||
INFO("TCP port: %d", TCP_PORT_FROM_FILTCOND(&sl->filtCond));
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_TCP_CONNBLOCK_H
|
||||
#define ETHERLIB_TEST_TCP_CONNBLOCK_H
|
||||
#ifndef ETHERLIB_TCP_CONNBLOCK_H
|
||||
#define ETHERLIB_TCP_CONNBLOCK_H
|
||||
|
||||
#define TCP_PORT_FROM_FILTCOND(fc) ((fc)->uw[7])
|
||||
#define TCP_PORT_TO_FILTCOND(fc,port) (((fc)->uw[7]) = (port))
|
||||
@ -8,7 +8,7 @@
|
||||
#include "../packet_parsers/ipv4_types.h"
|
||||
#include "../../connection_block.h"
|
||||
#include "../packet_parsers/tcp_segment.h"
|
||||
#include "etherlib/cbd_table.h"
|
||||
#include "../../cbd_table.h"
|
||||
|
||||
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);
|
||||
|
||||
#endif //ETHERLIB_TEST_TCP_CONNBLOCK_H
|
||||
#endif //ETHERLIB_TCP_CONNBLOCK_H
|
||||
|
@ -6,11 +6,10 @@
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../packet_parsers/packet_parsers.h"
|
||||
#include "../../utils.h"
|
||||
#include "../../dynmem.h"
|
||||
#include "etherlib/pckt_assembler.h"
|
||||
#include "etherlib/global_state.h"
|
||||
#include "../../pckt_assembler.h"
|
||||
#include "../../global_state.h"
|
||||
|
||||
static bool filtUdp(const PcktSieveFilterCondition *filtCond, const PcktProps *contProps, const PcktProps *ownProps, EthInterface *intf) {
|
||||
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) {
|
||||
ArpCache *arpc = connBlock.sieve->intf->arpc;
|
||||
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);
|
||||
} else {
|
||||
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);
|
||||
|
||||
release_resources:
|
||||
// free headers
|
||||
dynmem_free(udpHeader);
|
||||
dynmem_free(ipHeader);
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "../../connection_block.h"
|
||||
#include "../../eth_interface.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_TO_FILTCOND(fc,port) (((fc)->uw[0]) = (port))
|
||||
|
@ -3,7 +3,6 @@
|
||||
//
|
||||
|
||||
#include "arp_packet.h"
|
||||
#include "../../packet_registry.h"
|
||||
#include "ethernet_frame.h"
|
||||
#include "../../utils.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
|
||||
ArpProps *arpProps = HEADER_FETCH_PROPS(ArpProps, pcktHdrLe);
|
||||
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
|
||||
|
||||
// fill-in common packet header fields
|
||||
arpProps->validityOK = true;
|
||||
arpProps->validityOK = true; // TODO!
|
||||
arpProps->containedPacketClass = 0;
|
||||
arpProps->headerSize = ETH_ARP_HEADER_SIZE;
|
||||
|
||||
// learn new mapping
|
||||
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) {
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Created by epagris on 2022.12.08..
|
||||
//
|
||||
|
||||
#ifndef ETHERLIB_TEST_ARP_PACKET_H
|
||||
#define ETHERLIB_TEST_ARP_PACKET_H
|
||||
#ifndef ETHERLIB_ARP_PACKET_H
|
||||
#define ETHERLIB_ARP_PACKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ipv4_types.h"
|
||||
@ -51,7 +51,7 @@ typedef struct {
|
||||
* @param intf Ethernet interface
|
||||
* @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.
|
||||
@ -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);
|
||||
|
||||
#endif //ETHERLIB_TEST_ARP_PACKET_H
|
||||
#endif //ETHERLIB_ARP_PACKET_H
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "../../utils.h"
|
||||
#include "../../connection_block.h"
|
||||
#include "../conn_blocks/udp_connblock.h"
|
||||
#include "etherlib/global_state.h"
|
||||
#include "../../global_state.h"
|
||||
|
||||
static struct {
|
||||
DhcpState state;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_DHCP_H
|
||||
#define ETHERLIB_TEST_DHCP_H
|
||||
#ifndef ETHERLIB_DHCP_H
|
||||
#define ETHERLIB_DHCP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../../eth_interface.h"
|
||||
@ -58,4 +58,4 @@ void dhcp_initiate(EthInterface * intf);
|
||||
*/
|
||||
void dhcp_start();
|
||||
|
||||
#endif //ETHERLIB_TEST_DHCP_H
|
||||
#endif //ETHERLIB_DHCP_H
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
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;
|
||||
FETCH_ADVANCE(frameProps->destAddr, hdr, ETH_HW_ADDR_LEN); // copy destination address
|
||||
FETCH_ADVANCE(frameProps->sourceAddr, hdr, ETH_HW_ADDR_LEN); // copy destination address
|
||||
|
@ -42,7 +42,7 @@ struct EthInterface_;
|
||||
* @param pcktHdrLe pointer to property storage
|
||||
* @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.
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "../../utils.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;
|
||||
|
||||
// parse header
|
||||
@ -23,7 +23,7 @@ int parse_icmp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
|
||||
icmpProps->containedPacketClass = 0;
|
||||
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) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_ICMP_PACKET_H
|
||||
#define ETHERLIB_TEST_ICMP_PACKET_H
|
||||
#ifndef ETHERLIB_ICMP_PACKET_H
|
||||
#define ETHERLIB_ICMP_PACKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ipv4_types.h"
|
||||
@ -34,7 +34,7 @@ typedef struct {
|
||||
* @param intf Ethernet interface through which transmission and reception is carried out
|
||||
* @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.
|
||||
@ -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);
|
||||
|
||||
#endif //ETHERLIB_TEST_ICMP_PACKET_H
|
||||
#endif //ETHERLIB_ICMP_PACKET_H
|
||||
|
@ -40,7 +40,7 @@ void insert_igmp_header(uint8_t *hdr, const PcktHeaderElement *headers) {
|
||||
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
|
||||
IgmpProps *igmpProps = HEADER_FETCH_PROPS(IgmpProps, pcktHdrLe);
|
||||
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->headerSize = ETH_IGMP_HEADER_SIZE;
|
||||
|
||||
return 0;
|
||||
return igmpProps->validityOK ? PROC_FN_RET_OK : PROC_FN_RET_ABORT;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_IGMP_PACKET_H
|
||||
#define ETHERLIB_TEST_IGMP_PACKET_H
|
||||
#ifndef ETHERLIB_IGMP_PACKET_H
|
||||
#define ETHERLIB_IGMP_PACKET_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "ipv4_types.h"
|
||||
@ -43,6 +43,6 @@ void insert_igmp_header(uint8_t * hdr, const PcktHeaderElement * headers);
|
||||
* @param intf Ethernet interface
|
||||
* @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
|
||||
|
@ -15,12 +15,12 @@ static bool check_ipv4_validity(const uint8_t *hdr, const IPv4Props *ipProps) {
|
||||
bool valid =
|
||||
(ipProps->Version == 4) &&
|
||||
(ipProps->IHL == (ETH_IP_HEADER_LENGTH / 4)) &&
|
||||
(chksum(hdr, ETH_IPv4_HEADER_SIZE, false) == 0) &&
|
||||
(ipProps->FragmentOffset == 0) && !(ipProps->Flags & 0x02 << 4); // TODO: discard if fragmented
|
||||
(chksum(hdr, ETH_IPv4_HEADER_SIZE, false) == 0); /*&&
|
||||
(ipProps->FragmentOffset == 0) && !(ipProps->Flags & 0x02 << 4); // TODO: discard if fragmented*/
|
||||
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;
|
||||
IPv4Props *ipProps = HEADER_FETCH_PROPS(IPv4Props, pcktHdrLe);
|
||||
uint8_t version_length;
|
||||
@ -33,7 +33,7 @@ int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe,
|
||||
uint16_t flags_fragOffset;
|
||||
FETCH_WORD_H2N_ADVANCE(&flags_fragOffset, hdr);
|
||||
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->Protocol, hdr, 1);
|
||||
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
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -9,6 +9,11 @@
|
||||
#define ETH_IPv4_PACKET_CLASS (0x0800)
|
||||
#define ETH_IPv4_HEADER_SIZE (20)
|
||||
|
||||
typedef enum {
|
||||
IP_FLAG_DNF = 0x02,
|
||||
IP_FLAG_MF = 0x01
|
||||
} IPv4Flags;
|
||||
|
||||
/**
|
||||
* IPv4 header structure
|
||||
*/
|
||||
@ -45,7 +50,7 @@ struct EthInterface_;
|
||||
* @param pcktHdrLe pointer to property storage
|
||||
* @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.
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_IPV4_TYPES_H
|
||||
#define ETHERLIB_TEST_IPV4_TYPES_H
|
||||
#ifndef ETHERLIB_IPV4_TYPES_H
|
||||
#define ETHERLIB_IPV4_TYPES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -8,4 +8,4 @@ typedef uint32_t ip4_addr;
|
||||
#define IPv4_ANY_ADDR (0xFFFFFFFF)
|
||||
#define IPv4_IF_ADDR (0x00000000)
|
||||
|
||||
#endif //ETHERLIB_TEST_IPV4_TYPES_H
|
||||
#endif //ETHERLIB_IPV4_TYPES_H
|
||||
|
@ -3,6 +3,11 @@
|
||||
|
||||
#include "ethernet_frame.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 "dhcp.h"
|
||||
|
||||
#endif //ETHERLIB_PACKET_PARSERS_H
|
||||
|
@ -3,9 +3,9 @@
|
||||
//
|
||||
|
||||
#include "tcp_segment.h"
|
||||
#include "etherlib/utils.h"
|
||||
#include "../../utils.h"
|
||||
#include "ethernet_frame.h"
|
||||
#include "etherlib/dynmem.h"
|
||||
#include "../../dynmem.h"
|
||||
|
||||
#include "tcp_udp_common.h"
|
||||
#include "ipv4_packet.h"
|
||||
@ -112,7 +112,7 @@ TcpOption * tcp_get_option_by_kind(TcpOption * opt, uint16_t kind) {
|
||||
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;
|
||||
|
||||
// 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->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) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_TCP_SEGMENT_H
|
||||
#define ETHERLIB_TEST_TCP_SEGMENT_H
|
||||
#ifndef ETHERLIB_TCP_SEGMENT_H
|
||||
#define ETHERLIB_TCP_SEGMENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "../../packet_sieve.h"
|
||||
@ -94,7 +94,7 @@ struct EthInterface_;
|
||||
* @param pcktHdrLe pointer to property storage
|
||||
* @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.
|
||||
@ -118,4 +118,4 @@ uint32_t tcp_get_options_size(TcpOption * optLe);
|
||||
*/
|
||||
TcpOption * tcp_get_option_by_kind(TcpOption * opt, uint16_t kind);
|
||||
|
||||
#endif //ETHERLIB_TEST_TCP_SEGMENT_H
|
||||
#endif //ETHERLIB_TCP_SEGMENT_H
|
||||
|
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_TCP_UDP_COMMON_H
|
||||
#define ETHERLIB_TEST_TCP_UDP_COMMON_H
|
||||
#ifndef ETHERLIB_TCP_UDP_COMMON_H
|
||||
#define ETHERLIB_TCP_UDP_COMMON_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);
|
||||
|
||||
#endif //ETHERLIB_TEST_TCP_UDP_COMMON_H
|
||||
#endif //ETHERLIB_TCP_UDP_COMMON_H
|
||||
|
@ -17,7 +17,7 @@ static bool check_udp_validity(const uint8_t * hdr, const PcktHeaderElement *pck
|
||||
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;
|
||||
UdpProps *udpProps = HEADER_FETCH_PROPS(UdpProps, pcktHdrLe);
|
||||
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->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) {
|
||||
|
@ -30,7 +30,7 @@ struct EthInterface_;
|
||||
* @param pcktHdrLe pointer to property storage
|
||||
* @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.
|
||||
|
8
timer.h
8
timer.h
@ -1,5 +1,5 @@
|
||||
#ifndef ETHERLIB_TEST_TIMER_H
|
||||
#define ETHERLIB_TEST_TIMER_H
|
||||
#ifndef ETHERLIB_TIMER_H
|
||||
#define ETHERLIB_TIMER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
@ -40,7 +40,7 @@ struct Timer_;
|
||||
/**
|
||||
* Alarm user data.
|
||||
*/
|
||||
typedef union {
|
||||
typedef struct {
|
||||
void * ptr;
|
||||
uint32_t u;
|
||||
} AlarmUserData;
|
||||
@ -136,4 +136,4 @@ void timer_tick(Timer * tmr, int64_t us);
|
||||
*/
|
||||
void timer_report(const Timer * tmr);
|
||||
|
||||
#endif //ETHERLIB_TEST_TIMER_H
|
||||
#endif //ETHERLIB_TIMER_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user