-IP reassembler added

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

View File

@ -42,6 +42,10 @@ void arpc_free(ArpCache *aprc) {
}
void arpc_learn(ArpCache *arpc, const ArpEntry *newEntry) {
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;

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

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

View File

@ -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;
/**

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

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

View File

@ -4,15 +4,17 @@
#include "ipv4_connblock.h"
#include "../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) {

View File

@ -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 {

View File

@ -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

View File

@ -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...
AlarmUserData alarmData;
alarmData.ptr = &tcps->connBlock;
timer_sched_rel(E.tmr, 1000000, retry_to_connect_cb, alarmData);
tcps->connState = TCP_STATE_CLOSED;
if (tcps->retries < tcps->retryLimit) {
AlarmUserData 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;
}
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));
}

View File

@ -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

View File

@ -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);

View File

@ -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))

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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) {

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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.

View File

@ -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