-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) {
|
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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
4
dynmem.h
4
dynmem.h
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
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 "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) {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
}
|
}
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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))
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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.
|
||||||
|
8
timer.h
8
timer.h
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user