diff --git a/arp_cache.c b/arp_cache.c index 829351b..63f0bd8 100644 --- a/arp_cache.c +++ b/arp_cache.c @@ -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; diff --git a/arp_cache.h b/arp_cache.h index e00ef94..3aefd4e 100644 --- a/arp_cache.h +++ b/arp_cache.h @@ -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 diff --git a/cbd_table.h b/cbd_table.h index 99712f5..919fb05 100644 --- a/cbd_table.h +++ b/cbd_table.h @@ -1,5 +1,5 @@ -#ifndef ETHERLIB_TEST_CBD_TABLE_H -#define ETHERLIB_TEST_CBD_TABLE_H +#ifndef ETHERLIB_CBD_TABLE_H +#define ETHERLIB_CBD_TABLE_H #include #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 diff --git a/docs/customdoxygen.css b/docs/customdoxygen.css index e19998a..e1a7be0 100644 --- a/docs/customdoxygen.css +++ b/docs/customdoxygen.css @@ -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 { diff --git a/dynmem.h b/dynmem.h index 9aca29e..b4b4d79 100644 --- a/dynmem.h +++ b/dynmem.h @@ -3,6 +3,10 @@ #include +#ifdef DYNMEM_DEBUG +#include +#endif + /** * Initialize EtherLib dynamic memory management subsystem, * based on heap pointer and size given in etherlib_options.h diff --git a/eth_interface.c b/eth_interface.c index 5ba8658..b6410ba 100644 --- a/eth_interface.c +++ b/eth_interface.c @@ -32,6 +32,8 @@ EthInterface *ethintf_new(EthIODef * io) { ethIntf->txQ = mq_create(ETHLIB_DEF_MQ_SIZE); + ethIntf->ipra = ipra_new(); + return ethIntf; } diff --git a/eth_interface.h b/eth_interface.h index a905652..43d0f86 100644 --- a/eth_interface.h +++ b/eth_interface.h @@ -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; /** diff --git a/msg_queue.h b/msg_queue.h index dcdc163..fbeb38c 100644 --- a/msg_queue.h +++ b/msg_queue.h @@ -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 #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 diff --git a/packet_registry.h b/packet_registry.h index 0255fd1..c337587 100644 --- a/packet_registry.h +++ b/packet_registry.h @@ -44,6 +44,17 @@ typedef struct { PcktPropsHeader } PcktProps; +// special processing function returns +#define PROC_FN_RET_OK (0) // OK, go ahead! +#define PROC_FN_RET_ABORT (-1) // abort further processing +#define PROC_FN_RET_REPRST (-2) // replace packet and restart packet processing + +typedef struct { + void * p; + uint32_t u; + bool8_t b; +} PcktProcFnPassbackData; + /** * @typedef int (*PcktProcFn)(const uint8_t *pHdr, uint32_t size, uint8_t *pPcktProps); * @brief Pckt processing function template. @@ -52,11 +63,9 @@ typedef struct { * @param props: pointer to existing structure to store * packet properties to (e.g. source address, port etc.) * @param intf associeated Ethernet interface - * @return packet class of contained packet, or -1 on failure or - * 0 if no more standard packet contained (e.g. UDP packet contains - * user data) + * @return one of the special processing function return values */ -typedef int (*PcktProcFn)(const uint8_t *hdr, uint32_t size, struct PcktHeaderElement_ * pcktHdrLe, struct EthInterface_ * intf); +typedef int (*PcktProcFn)(const uint8_t *hdr, uint32_t size, struct PcktHeaderElement_ * pcktHdrLe, struct EthInterface_ * intf, PcktProcFnPassbackData * pb); /** * @struct PcktClassDesc diff --git a/packet_sieve.c b/packet_sieve.c index ea0b74b..f755d39 100644 --- a/packet_sieve.c +++ b/packet_sieve.c @@ -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); diff --git a/packet_sieve.h b/packet_sieve.h index a7c7687..1559c4e 100644 --- a/packet_sieve.h +++ b/packet_sieve.h @@ -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. diff --git a/pckt_assembler.h b/pckt_assembler.h index 7d97ea8..0e4711d 100644 --- a/pckt_assembler.h +++ b/pckt_assembler.h @@ -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 diff --git a/prefab/conn_blocks/arp_connblock.c b/prefab/conn_blocks/arp_connblock.c index 8d995d8..987ffca 100644 --- a/prefab/conn_blocks/arp_connblock.c +++ b/prefab/conn_blocks/arp_connblock.c @@ -2,10 +2,8 @@ #include -#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; diff --git a/prefab/conn_blocks/arp_connblock.h b/prefab/conn_blocks/arp_connblock.h index 2d06a07..b0b9416 100644 --- a/prefab/conn_blocks/arp_connblock.h +++ b/prefab/conn_blocks/arp_connblock.h @@ -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 #include "../../connection_block.h" diff --git a/prefab/conn_blocks/ethernet_info.h b/prefab/conn_blocks/ethernet_info.h index ac8117a..7c9b343 100644 --- a/prefab/conn_blocks/ethernet_info.h +++ b/prefab/conn_blocks/ethernet_info.h @@ -1,8 +1,8 @@ -#ifndef ETHERLIB_TEST_ETHERNET_INFO_H -#define ETHERLIB_TEST_ETHERNET_INFO_H +#ifndef ETHERLIB_ETHERNET_INFO_H +#define ETHERLIB_ETHERNET_INFO_H -#include "etherlib/connection_block.h" +#include "../../connection_block.h" /** * Print Ethernet sieve layer info. @@ -10,4 +10,4 @@ */ void ethernet_print_report(const ConnBlock* connBlock); -#endif //ETHERLIB_TEST_ETHERNET_INFO_H +#endif //ETHERLIB_ETHERNET_INFO_H diff --git a/prefab/conn_blocks/icmp_connblock.h b/prefab/conn_blocks/icmp_connblock.h index b501a80..c78bca4 100644 --- a/prefab/conn_blocks/icmp_connblock.h +++ b/prefab/conn_blocks/icmp_connblock.h @@ -1,5 +1,5 @@ -#ifndef ETHERLIB_TEST_ICMP_CONNBLOCK_H -#define ETHERLIB_TEST_ICMP_CONNBLOCK_H +#ifndef ETHERLIB_ICMP_CONNBLOCK_H +#define ETHERLIB_ICMP_CONNBLOCK_H #include "../../connection_block.h" @@ -18,4 +18,4 @@ ConnBlock icmp_new_connblock(struct EthInterface_ * intf); */ void icmp_print_report(const ConnBlock* connBlock); -#endif //ETHERLIB_TEST_ICMP_CONNBLOCK_H +#endif //ETHERLIB_ICMP_CONNBLOCK_H diff --git a/prefab/conn_blocks/igmp_connblock.h b/prefab/conn_blocks/igmp_connblock.h index fa06ba6..a8ba178 100644 --- a/prefab/conn_blocks/igmp_connblock.h +++ b/prefab/conn_blocks/igmp_connblock.h @@ -1,5 +1,5 @@ -#ifndef ETHERLIB_TEST_IGMP_CONNBLOCK_H -#define ETHERLIB_TEST_IGMP_CONNBLOCK_H +#ifndef ETHERLIB_IGMP_CONNBLOCK_H +#define ETHERLIB_IGMP_CONNBLOCK_H #include "../../connection_block.h" #include "../packet_parsers/ipv4_types.h" @@ -33,4 +33,4 @@ void igmp_leave_group(ConnBlock * connBlock, ip4_addr ga); */ void igmp_print_report(const ConnBlock* connBlock); -#endif //ETHERLIB_TEST_IGMP_CONNBLOCK_H +#endif //ETHERLIB_IGMP_CONNBLOCK_H diff --git a/prefab/conn_blocks/ipv4/ip_assembler.c b/prefab/conn_blocks/ipv4/ip_assembler.c new file mode 100644 index 0000000..48e8299 --- /dev/null +++ b/prefab/conn_blocks/ipv4/ip_assembler.c @@ -0,0 +1,196 @@ +#include +#include + +#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; +} \ No newline at end of file diff --git a/prefab/conn_blocks/ipv4/ip_assembler.h b/prefab/conn_blocks/ipv4/ip_assembler.h new file mode 100644 index 0000000..8f49965 --- /dev/null +++ b/prefab/conn_blocks/ipv4/ip_assembler.h @@ -0,0 +1,54 @@ +#ifndef ETHERLIB_IP_ASSEMBLER_H +#define ETHERLIB_IP_ASSEMBLER_H + +#include +#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 diff --git a/prefab/conn_blocks/ipv4_connblock.c b/prefab/conn_blocks/ipv4_connblock.c index df342c3..a607ab9 100644 --- a/prefab/conn_blocks/ipv4_connblock.c +++ b/prefab/conn_blocks/ipv4_connblock.c @@ -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) { diff --git a/prefab/conn_blocks/tcp/tcp_window.c b/prefab/conn_blocks/tcp/tcp_window.c index 835a438..cd6735c 100644 --- a/prefab/conn_blocks/tcp/tcp_window.c +++ b/prefab/conn_blocks/tcp/tcp_window.c @@ -5,7 +5,7 @@ #include #include #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 { diff --git a/prefab/conn_blocks/tcp/tcp_window.h b/prefab/conn_blocks/tcp/tcp_window.h index dcba1e6..52918c7 100644 --- a/prefab/conn_blocks/tcp/tcp_window.h +++ b/prefab/conn_blocks/tcp/tcp_window.h @@ -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 -#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 diff --git a/prefab/conn_blocks/tcp_connblock.c b/prefab/conn_blocks/tcp_connblock.c index 517c255..3af95e5 100644 --- a/prefab/conn_blocks/tcp_connblock.c +++ b/prefab/conn_blocks/tcp_connblock.c @@ -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)); } \ No newline at end of file diff --git a/prefab/conn_blocks/tcp_connblock.h b/prefab/conn_blocks/tcp_connblock.h index 8a3519f..862f254 100644 --- a/prefab/conn_blocks/tcp_connblock.h +++ b/prefab/conn_blocks/tcp_connblock.h @@ -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 diff --git a/prefab/conn_blocks/udp_connblock.c b/prefab/conn_blocks/udp_connblock.c index 15cb359..306bc36 100644 --- a/prefab/conn_blocks/udp_connblock.c +++ b/prefab/conn_blocks/udp_connblock.c @@ -6,11 +6,10 @@ #include -#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); diff --git a/prefab/conn_blocks/udp_connblock.h b/prefab/conn_blocks/udp_connblock.h index ae47909..0f8724d 100644 --- a/prefab/conn_blocks/udp_connblock.h +++ b/prefab/conn_blocks/udp_connblock.h @@ -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)) diff --git a/prefab/packet_parsers/arp_packet.c b/prefab/packet_parsers/arp_packet.c index dc54ade..2a069ea 100644 --- a/prefab/packet_parsers/arp_packet.c +++ b/prefab/packet_parsers/arp_packet.c @@ -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) { diff --git a/prefab/packet_parsers/arp_packet.h b/prefab/packet_parsers/arp_packet.h index e108789..74ee4a8 100644 --- a/prefab/packet_parsers/arp_packet.h +++ b/prefab/packet_parsers/arp_packet.h @@ -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 #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 diff --git a/prefab/packet_parsers/dhcp.c b/prefab/packet_parsers/dhcp.c index 351b5b1..530b76a 100644 --- a/prefab/packet_parsers/dhcp.c +++ b/prefab/packet_parsers/dhcp.c @@ -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; diff --git a/prefab/packet_parsers/dhcp.h b/prefab/packet_parsers/dhcp.h index 957b878..388957a 100644 --- a/prefab/packet_parsers/dhcp.h +++ b/prefab/packet_parsers/dhcp.h @@ -1,5 +1,5 @@ -#ifndef ETHERLIB_TEST_DHCP_H -#define ETHERLIB_TEST_DHCP_H +#ifndef ETHERLIB_DHCP_H +#define ETHERLIB_DHCP_H #include #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 diff --git a/prefab/packet_parsers/ethernet_frame.c b/prefab/packet_parsers/ethernet_frame.c index fb5a46b..aba9627 100644 --- a/prefab/packet_parsers/ethernet_frame.c +++ b/prefab/packet_parsers/ethernet_frame.c @@ -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 diff --git a/prefab/packet_parsers/ethernet_frame.h b/prefab/packet_parsers/ethernet_frame.h index abc7051..17028a5 100644 --- a/prefab/packet_parsers/ethernet_frame.h +++ b/prefab/packet_parsers/ethernet_frame.h @@ -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. diff --git a/prefab/packet_parsers/icmp_packet.c b/prefab/packet_parsers/icmp_packet.c index 00a9a35..d81d7dd 100644 --- a/prefab/packet_parsers/icmp_packet.c +++ b/prefab/packet_parsers/icmp_packet.c @@ -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) { diff --git a/prefab/packet_parsers/icmp_packet.h b/prefab/packet_parsers/icmp_packet.h index f1dbc16..4c49d55 100644 --- a/prefab/packet_parsers/icmp_packet.h +++ b/prefab/packet_parsers/icmp_packet.h @@ -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 #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 diff --git a/prefab/packet_parsers/igmp_packet.c b/prefab/packet_parsers/igmp_packet.c index 0f7c3cb..a6f189d 100644 --- a/prefab/packet_parsers/igmp_packet.c +++ b/prefab/packet_parsers/igmp_packet.c @@ -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; } diff --git a/prefab/packet_parsers/igmp_packet.h b/prefab/packet_parsers/igmp_packet.h index 3e9c6ea..562ffe2 100644 --- a/prefab/packet_parsers/igmp_packet.h +++ b/prefab/packet_parsers/igmp_packet.h @@ -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 #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 diff --git a/prefab/packet_parsers/ipv4_packet.c b/prefab/packet_parsers/ipv4_packet.c index 9d24888..96a3fd1 100644 --- a/prefab/packet_parsers/ipv4_packet.c +++ b/prefab/packet_parsers/ipv4_packet.c @@ -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; diff --git a/prefab/packet_parsers/ipv4_packet.h b/prefab/packet_parsers/ipv4_packet.h index 986c0bb..7362ed3 100644 --- a/prefab/packet_parsers/ipv4_packet.h +++ b/prefab/packet_parsers/ipv4_packet.h @@ -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. diff --git a/prefab/packet_parsers/ipv4_types.h b/prefab/packet_parsers/ipv4_types.h index 9b8c063..05ecd5b 100644 --- a/prefab/packet_parsers/ipv4_types.h +++ b/prefab/packet_parsers/ipv4_types.h @@ -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 @@ -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 diff --git a/prefab/packet_parsers/packet_parsers.h b/prefab/packet_parsers/packet_parsers.h index 942d541..5a0ae3a 100644 --- a/prefab/packet_parsers/packet_parsers.h +++ b/prefab/packet_parsers/packet_parsers.h @@ -3,6 +3,11 @@ #include "ethernet_frame.h" #include "ipv4_packet.h" +#include "arp_packet.h" +#include "icmp_packet.h" +#include "igmp_packet.h" +#include "tcp_segment.h" #include "udp_packet.h" +#include "dhcp.h" #endif //ETHERLIB_PACKET_PARSERS_H diff --git a/prefab/packet_parsers/tcp_segment.c b/prefab/packet_parsers/tcp_segment.c index ee6760e..e2f788b 100644 --- a/prefab/packet_parsers/tcp_segment.c +++ b/prefab/packet_parsers/tcp_segment.c @@ -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) { diff --git a/prefab/packet_parsers/tcp_segment.h b/prefab/packet_parsers/tcp_segment.h index 1071502..ecf853b 100644 --- a/prefab/packet_parsers/tcp_segment.h +++ b/prefab/packet_parsers/tcp_segment.h @@ -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 #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 diff --git a/prefab/packet_parsers/tcp_udp_common.h b/prefab/packet_parsers/tcp_udp_common.h index b8d609a..12f7b74 100644 --- a/prefab/packet_parsers/tcp_udp_common.h +++ b/prefab/packet_parsers/tcp_udp_common.h @@ -1,5 +1,5 @@ -#ifndef ETHERLIB_TEST_TCP_UDP_COMMON_H -#define ETHERLIB_TEST_TCP_UDP_COMMON_H +#ifndef ETHERLIB_TCP_UDP_COMMON_H +#define ETHERLIB_TCP_UDP_COMMON_H #include @@ -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 diff --git a/prefab/packet_parsers/udp_packet.c b/prefab/packet_parsers/udp_packet.c index 694764a..fbfd69b 100644 --- a/prefab/packet_parsers/udp_packet.c +++ b/prefab/packet_parsers/udp_packet.c @@ -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) { diff --git a/prefab/packet_parsers/udp_packet.h b/prefab/packet_parsers/udp_packet.h index ae136d6..c3b863a 100644 --- a/prefab/packet_parsers/udp_packet.h +++ b/prefab/packet_parsers/udp_packet.h @@ -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. diff --git a/timer.h b/timer.h index 0e3f507..7e25c93 100644 --- a/timer.h +++ b/timer.h @@ -1,5 +1,5 @@ -#ifndef ETHERLIB_TEST_TIMER_H -#define ETHERLIB_TEST_TIMER_H +#ifndef ETHERLIB_TIMER_H +#define ETHERLIB_TIMER_H #include #include @@ -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