diff --git a/arp_cache.c b/arp_cache.c new file mode 100644 index 0000000..a32a89d --- /dev/null +++ b/arp_cache.c @@ -0,0 +1,42 @@ +// +// Created by epagris on 2022.12.10.. +// + +#include +#include "arp_cache.h" +#include "dynmem.h" + +ArpCache *arpc_new(uint16_t size) { + ArpCache * arcp = (ArpCache *) dynmem_alloc(2 * sizeof(uint16_t) + size * sizeof(ArpEntry)); + arcp->size = size; + arcp->fill = 0; + return arcp; +} + +void arpc_free(ArpCache *aprc) { + dynmem_free(aprc); +} + +void arpc_learn(ArpCache *arpc, const ArpEntry *newEntry) { + // TODO: nagyon dummy... + for (uint16_t i = 0; i < arpc->fill; i++) { + ArpEntry * entry = arpc->entries + i; + if (!memcmp(entry->eth, newEntry->eth, ETH_HW_ADDR_LEN) && (entry->ip == newEntry->ip)) { + return; + } + } + + // if not found... + arpc->entries[arpc->fill++] = *newEntry; +} + +const ArpEntry *arpc_get(ArpCache *arpc, ip4_addr ip) { + for (uint16_t i = 0; i < arpc->fill; i++) { + ArpEntry * entry = arpc->entries + i; + if (entry->ip == ip) { + return entry; + } + } + + return NULL; +} diff --git a/arp_cache.h b/arp_cache.h new file mode 100644 index 0000000..d1fc6ea --- /dev/null +++ b/arp_cache.h @@ -0,0 +1,51 @@ +#ifndef ETHERLIB_TEST_ARP_CACHE_H +#define ETHERLIB_TEST_ARP_CACHE_H + +#include "prefab/packet_parsers/ethernet_frame.h" +#include "prefab/packet_parsers/ipv4_types.h" + +/** + * ARP cache entry record. + */ +typedef struct { + EthernetAddress eth; ///< Ethernet address + ip4_addr ip; ///< IPv4 address +} ArpEntry; + +/** + * ARP cache class. + */ +typedef struct { + uint16_t size; ///< Number of cache entries + uint16_t fill; ///< Fill level + ArpEntry entries[]; ///< Cache entries +} ArpCache; + +/** + * Create new ARP cache table. + * @param size Number of available entries + * @return Pointer to newly allocated ARP cache + */ +ArpCache * arpc_new(uint16_t size); + +/** + * Learn new assignment. + * @param arpc Pointer to ARP cache + * @param newEntry Pointer to map newEntry + */ +void arpc_learn(ArpCache * arpc, const ArpEntry * newEntry); + +/** + * Get entry by IP-address. + * @param ip IP address + * @return Pointer to matching entry OR NULL if not found + */ +const ArpEntry *arpc_get(ArpCache *arpc, ip4_addr ip); + +/** + * Free ARP cache. + * @param aprc Pointer to existing ARP cache. + */ +void arpc_free(ArpCache * aprc); + +#endif //ETHERLIB_TEST_ARP_CACHE_H diff --git a/connection_block.h b/connection_block.h index 65c2200..94a1d82 100644 --- a/connection_block.h +++ b/connection_block.h @@ -8,6 +8,9 @@ struct ConnBlock_; typedef int (*ConnBlockTransmitFn)(EthInterface * intf, const uint8_t * data, uint32_t size, const struct ConnBlock_ * connBlock); +/** + * Connection block. + */ typedef struct ConnBlock_ { EthInterface * intf; ///< Ethernet interface PcktSieveLayer * sieveLayer; ///< Sieve layer diff --git a/docs/.$PacketSieve.bkp b/docs/.$PacketSieve.bkp new file mode 100644 index 0000000..1a485c6 --- /dev/null +++ b/docs/.$PacketSieve.bkp @@ -0,0 +1 @@ +7Vpbk6I4FP41PrYFCTcfu217LtUz27tWz8w+bSEEYTYQK8bb/voNEgRMWmlFdBy7qyzOITfOd75zTggd2I+XH6g7Cb8QH+EO0PxlBz52AHB0yH9TxSpTmKaeKcY08jNVSTGM/kNCqQntLPLRtNKQEYJZNKkqPZIkyGMVnUspWVSbBQRXZ524YyQphp6LZe33yGeheCxTK/QfUTQO85l1TdyJ3byxUExD1yeLkgoOOrBPCWHZVbzsI5zaLrdL1u/pjbubhVGUsDod/rj7q0fiAXz+TO694bdXr0eHd7oYZu7imXhisVq2yk2AfG4RIRLKQjImiYsHhfbBm9E5SqfRuUDJLPHXksalosMzIRPR5CdibCWwdmeMcFXIYizuBiRhT24c4dRl+mRGI0T5ir6ihbgpejpclI0gHmjK+3lo15MLZ3LpGLEd7aysXWqE0gTCxB8QiRGjK96AIuyyaF51G1d433jTrgCIXwiM3oOXBNeAhYgm/BG2YVuEEUPDibu2woKT8z1WjjDuE0zoeijou8gJPK6fMkr+RaU7luegUbALiDmiDC13mi6/CwVTRKgAmpnJi4J4tmgSljiXdzvG2NOf375+fg6I9sw0a/DnP7BnvN7p4PLIofTGwxhgyAxQm+GsHm9IGHx6mRsn9XYTOb6h8nYHjKBlNePt0Kh6u5679h5vBw14uzq0yEZt27m5Nenqh+i/Fv5Oha6Zi4/L8s3HlZDekzHQMmI/8vn4dTYDMIVYzJAK+QSHk8yqmWaMc6UZNeUPcIXj0VciY+9G5lCXqThug0G1Lt66ec6gaklBVe+Brm45Xb2bVt4W5mt/GHESWeP0CgCjq/F/2S94tGNVGKtRMyEJ2gqxQuXiaJxwkWax7SENnREvvO+FPo58f+1YqtBedbb38J8Sxg1Mkn3Mrh/JgVS3WF3HqRfMrTTynAbj3uUVL+1U9nZdCl5UZW9LcD1FmCHK7Q20UboOskj4b1Hva1/u+3eu71M0naYrStKW8QynLJrK+4HjmepxKDhgvzBVt5iq9+xuvT2G0QBLlZn2AlnaYDbUzZp7DOuc1MtXefV7DGCAmv7exC5DCbS8pX59fDmlpYMgAJ7y3YVvjSyzsLRkVoXx37S00bs4S8M9NV7j6QGj4Nx13FEYSjtyq96OXD8VgvKrj1PW4dcGH4B1KXgyAPOBf/3s/nbSrpHcQUvJfdciSxBA3b7RR85gUq2gqo1Bq/SRA+A10Sc/e9v/Ah6ek0CKI0JD024FxH4K6bZMINgqgeQa8Cqr7TbPTtSGlneQN47Ug05RZLfLkVuBcOAWV1lft1sgyC9N5QIh8e/T74AKQHx3Gm4KghKgVWMfdEAkG69kGlNhmlxXO5WLGV5IlLACmw2LtgNiPkRWjIhehdX3DuRsjZPVKtI4a/Q2T30EoM4N0CwE2UbX1rXiz6jiax6IL8xLkjPhW+d19++Arwmq+MJm4DXBWeHNg790iNURR1ifXtLF5EdWjafYJg6oGsiUYAuFzTehJd9yFL51sg/ZgLyFq+Iy4Tvh68XD0FvDg4vFF70ZrYrPouHgfw== \ No newline at end of file diff --git a/docs/PacketSieve b/docs/PacketSieve new file mode 100644 index 0000000..12dca50 --- /dev/null +++ b/docs/PacketSieve @@ -0,0 +1 @@ +7Vpbk6I6EP41Po5FEoj4OOM4e6nZ3TnHmr08bSEEYReIFePt/PoTJAxiMsooous6U2XRTW701193h9BCvXjxjjnj4BP1SNSChrdoofsWhF0biN9UscwUGONMMWKhl6lAoRiE/xGpNKR2GnpkUmrIKY14OC4rXZokxOUlncMYnZeb+TQqzzp2RkRRDFwnUrXfQo8Hmda2jEL/noSjIJ8ZGPJO7OSNpWISOB6dr6lQv4V6jFKeXcWLHolS2+V2yfo9vHL3ZWGMJLxKhy83/3Zp3EePH+mtO/j67HbZ4AbIYWZONJVPLFfLl7kJiCcsIkXKeEBHNHGifqG9c6dsRtJpgBAYnSbeSjKEVHR4pHQsm/winC8l1s6UU6EKeBzJuz5N+IMTh1HqMj06ZSFhYkWfyVzelD1tIapGkA80Ef1csu3JpTM5bET4lnbSXVMjrE0gTfyO0JhwthQNGIkcHs7KbuNI7xu9tCsAEhcSo7fgpcDV5wFhiXiETdjmQcjJYOysrDAX5HyLlcMo6tGIstVQyHOI7btCP+GM/iZrd7Brk6G/DYgZYZwstppO3oU5qWSoECzL5HlBvI5sEqxxDhmHG3vy6+vnj48+NR65gfv//ERd8/kGwPMjh9Yb92OAqTJAb4aTerypYPDhaWYe1dstYnumztttOEQif9Xi7Sbe8Pbc+3d4O6zB2/WhRTVq084trMmW32X/lfAjFdpWLt4v1m/eL6X0loxBFiH/ns8nrrMZoCXFYoZUyCfYn2S4YpoxT5Vm9JTfwxUOR1+LTGc7Mvu6TMlxawyqVfEG1imDKlaCKujCNsB2G7TTyhtHYu13Q0EiPEqvRLhqG+Jf9QsR7XgZxnLUTGhCNkKsVDlROEqEyLLYdpeGzlAU3rdSH4eet3IsXWgvO9tb+M8oFwamyS5mV4/kSKlbcNu2qwVznEae42DcPb/ipZnKvlOVgmdV2XcUuB7CiBMm7A2NYboOOk/Eb1HvG59uezeO5zEymaQrStKW8TRKWTRR9wOHM9UVUAjA/mCqgk2qdjrtapsMswaaalPtGdK0xnQIrIqbDHxK7uWrvPhNBoKwor/Xsc3QAq3uqZ/vn45pad/3oat9eeHhIbYKSytm1Rj/VUtjcHaWRjuKvNrzQ0T8UxdyB2GobMnNaltycCwE1XcfxyzELw0+BKpS8GgA5gP/+dn99aRdIbnDhpL7tkWuQYBA50ofhT6WUivoamPYKH3UAHhJ9MkP33a/gUenJJDmjNA0jGsBsZtC0FIJhBolkFoDXmS13eThid7Q6g7yypFq0GmK7GY5ci0Q9tziauvrZgsE9a2pWiAk3m36IVABiOdMgpeCYA3QsrH3OiFSjbdmGktjmlxXOZXLGZ5omPACG2i/EhDzIbJiRPYqrL5zIIA3BsqKFWWgFXwvj30AovYV0Sx9dM12BxjFn1kGePOrl6oAm13rtABXeeH9NwCMzTLAqB58sXlafPP4rxxkteQx1oendDH5sVXtWbaOQ6oakiXahMFWyxxb41xH+5gNqru4Mi5jsRm+XDws1BgeQiy+6s1oVXwajfr/Aw== \ No newline at end of file diff --git a/eth_interface.c b/eth_interface.c index a244b6b..3693dcf 100644 --- a/eth_interface.c +++ b/eth_interface.c @@ -5,6 +5,7 @@ #include "eth_interface.h" #include "dynmem.h" #include "utils.h" +#include "etherlib_options.h" static int ethintf_llrecv(EthIODef * io, const RawPckt * pckt) { ethinf_receive((EthInterface *) io->tag, pckt); @@ -21,14 +22,17 @@ EthInterface *ethintf_new(EthIODef * io) { ASSERT_NULL(ethIntf); memset(ðIntf->sieve.layer0, 0, sizeof(PcktSieveLayer)); ethIntf->ioDef = io; + ethIntf->ip = 0; + ethIntf->arpc = arpc_new(ETHLIB_ARPCACHE_SIZE); + ASSERT_NULL(ethIntf->arpc); ethintf_register(ethIntf); return ethIntf; } void ethinf_receive(EthInterface *intf, const RawPckt *rawPckt) { - packsieve_input(&intf->sieve, rawPckt); + packsieve_input(&intf->sieve, rawPckt, intf); } void ethinf_transmit(EthInterface *intf, const RawPckt *rawPckt) { - intf->ioDef->llTx(&(intf->ioDef), rawPckt); + intf->ioDef->llTx(intf->ioDef, rawPckt); } diff --git a/eth_interface.h b/eth_interface.h index fcbe18f..2b66c0f 100644 --- a/eth_interface.h +++ b/eth_interface.h @@ -3,7 +3,12 @@ #include "packet_sieve.h" #include "prefab/packet_parsers/packet_parsers.h" +#include "prefab/packet_parsers/ipv4_types.h" +#include "arp_cache.h" +/** + * Ethernet interface low level definition. + */ typedef struct EthIODef_ { int (*llTx)(struct EthIODef_ * io, const RawPckt * rawPckt); ///< Function pointer to low-level transmit function int (*llTxDone)(struct EthIODef_ * io, const RawPckt * rawPckt); ///< Transmission done (interrupt) callback @@ -14,10 +19,15 @@ typedef struct EthIODef_ { } EthIODef; +/** + * Ethernet interface representation. + */ typedef struct EthInterface_ { PcktSieve sieve; ///< Packet sieve EthIODef * ioDef; ///< Low-level IO definitions EthernetAddress mac; ///< Ethernet address + ip4_addr ip; ///< IP address + ArpCache * arpc; ///< ARP cache } EthInterface; /** diff --git a/packet_registry.c b/packet_registry.c index 3facbe5..4cc884b 100644 --- a/packet_registry.c +++ b/packet_registry.c @@ -3,6 +3,8 @@ #include "dynmem.h" #include "utils.h" +#include "packet_sieve.h" + #include #include diff --git a/packet_registry.h b/packet_registry.h index 7a0bed8..2d0cb2a 100644 --- a/packet_registry.h +++ b/packet_registry.h @@ -14,7 +14,7 @@ typedef uint8_t bool8_t; * * Every packet property structure must extend this base structure, * so that, must begin with fields defined here. PcktProps is guaranteed - * to be aligned to 32-bit boundary and so must be guaranteed by extending + * to be aligned to 32-bit boundary and so must be kept so by extending * as well. (The size of the packet is divisible by 4.) */ @@ -33,6 +33,9 @@ typedef struct { PcktPropsHeader } PcktProps; +struct EthInterface_; +struct PcktHeaderElement_; + /** * @typedef int (*PcktProcFn)(const uint8_t *pHdr, uint32_t size, uint8_t *pPcktProps); * @brief Pckt processing function template. @@ -40,11 +43,12 @@ typedef struct { * @param size: remaining packet size counted from pHdr * @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) */ -typedef int (*PcktProcFn)(const uint8_t *hdr, uint32_t size, PcktProps *props); +typedef int (*PcktProcFn)(const uint8_t *hdr, uint32_t size, struct PcktHeaderElement_ * pcktHdrLe, struct EthInterface_ * intf); /** * @struct PcktClassDesc diff --git a/packet_sieve.c b/packet_sieve.c index 6743eca..d0249f2 100644 --- a/packet_sieve.c +++ b/packet_sieve.c @@ -23,7 +23,7 @@ PcktSieve *packsieve_new() { return sieve; } -void packsieve_input(const PcktSieve *sieve, const RawPckt * rawPckt) { +void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt, struct EthInterface_ *intf) { // extract fields uint8_t * data = rawPckt->payload; uint32_t size = rawPckt->size; @@ -53,7 +53,7 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt * rawPckt) { } // call parsing function - cdesc->procFun(data + offset, size - offset, &header->props); + cdesc->procFun(data + offset, size - offset, header, intf); uint16_t containedClass = header->props.containedPacketClass; if (containedClass != 0) { containerClass = ownClass; @@ -80,7 +80,7 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt * rawPckt) { const PcktSieveLayer * nodeIter = layer->nodes; found = false; while (nodeIter && !found) { - found |= nodeIter->filtFn(&nodeIter->filtCond, &headerIter->props, &headerIter->next->props); + found |= nodeIter->matchAny || nodeIter->filtFn(&nodeIter->filtCond, &headerIter->props, &headerIter->next->props); // specific or general match if (found) { layer = nodeIter; // advance in the sieve tree const PcktHeaderElement * containedHeader = headerIter->next; // advance on headers @@ -108,12 +108,12 @@ void packsieve_input(const PcktSieve *sieve, const RawPckt * rawPckt) { return; } -PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag, uint16_t pcktClass) { +PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, bool matchAny, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag, uint16_t pcktClass) { // search for matching layer PcktSieveLayer * nodeIter = parent->nodes; bool alreadyExists = false; while (nodeIter != NULL && !alreadyExists) { - if (packfiltcond_cmp(&nodeIter->filtCond, filtCond) && (nodeIter->filtFn == filtFn)) { // if matching... + if ((packfiltcond_cmp(&nodeIter->filtCond, filtCond) || (nodeIter->matchAny && matchAny)) && (nodeIter->filtFn == filtFn)) { // if matching... [search for specific match OR any match] alreadyExists = true; } else { nodeIter = nodeIter->next; @@ -128,19 +128,33 @@ PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilte ASSERT_NULL(layer); PcktSieveLayer *oldListFirst = parent->nodes; - parent->nodes = layer; // replace first element (it's the fastest way of new element insertion, since element position does not carry any meaning this case) layer->packetClass = pcktClass; layer->parent = parent; - layer->prev = NULL; - layer->next = oldListFirst; - if (oldListFirst != NULL) { - layer->prev = layer; + + if (!matchAny || (oldListFirst == NULL)) { // for specific match or on first node insertion... + layer->prev = NULL; + parent->nodes = layer; // ...replace first element (it's the fastest way of new element insertion, since element position does not carry any meaning in general case) + layer->next = oldListFirst; + if (oldListFirst != NULL) { + layer->prev = layer; + } + } else { // for 'any' match if at least a single node is already present + PcktSieveLayer * iter = parent->nodes; + while (iter->next != NULL) { // find the last node + iter = iter->next; + } + iter->next = layer; + layer->prev = iter; + layer->next = NULL; } + layer->nodes = NULL; layer->filtCond = *filtCond; + layer->matchAny = matchAny; layer->filtFn = filtFn; layer->cbFn = cbFn; layer->tag = tag; + layer->infoTag[0] = '\0'; return layer; } } @@ -181,7 +195,11 @@ bool packsieve_remove_layer(PcktSieveLayer * layer) { #define ETH_SIEVE_LAYER_INDENT_PER_LEVEL (4) void packsieve_report(const PcktSieveLayer *layer, uint32_t indent) { - INFO("%*c\\--|%d|---\n", indent, ' ', layer->packetClass); + if (*layer->infoTag != '\0') { + INFO("%*c\\--|%s|---\n", indent, ' ', layer->infoTag); + } else { + INFO("%*c\\--|%d|---\n", indent, ' ', layer->packetClass); + } const PcktSieveLayer * nodeIter = layer->nodes; while(nodeIter) { packsieve_report(nodeIter, indent + ETH_SIEVE_LAYER_INDENT_PER_LEVEL); diff --git a/packet_sieve.h b/packet_sieve.h index f2565d7..c359bef 100644 --- a/packet_sieve.h +++ b/packet_sieve.h @@ -6,6 +6,9 @@ #include "packet_registry.h" #include "packet.h" +/** + * Packet header information. + */ typedef struct PcktHeaderElement_ { struct PcktHeaderElement_ * next, * prev; ///< Next and previous header in the linked list PcktProps props; ///< Properties (allocated to appropriate size) @@ -41,10 +44,16 @@ bool packfiltcond_cmp(const PcktSieveFilterCondition * c1, const PcktSieveFilter */ void packfiltcond_zero(PcktSieveFilterCondition * cond); +/** + * Sieve filter function type. + */ typedef bool (*SieveFilterFn)(const PcktSieveFilterCondition * filtCond, const PcktProps * contProps, const PcktProps * ownProps); struct PcktSieveLayer_; +/** + * Callback function type for packet sieve match. + */ typedef int (*SieveCallBackFn)(const Pckt * pckt); typedef union { @@ -52,17 +61,29 @@ typedef union { uint32_t u; } PcktSieveLayerTag; +#define PCKT_SIEVE_INFOTAG_LEN (24) + +/** + * Packet sieve layer structure. + */ typedef struct PcktSieveLayer_ { uint16_t packetClass; ///< Packet class (e.g. IP) PcktSieveFilterCondition filtCond; ///< Filter condition, arbitrary type (e.g. destination IP-address) + bool matchAny; ///< Match any packet, don't test against filter condition SieveFilterFn filtFn; ///< Filter function pointer SieveCallBackFn cbFn; ///< Associated callback function PcktSieveLayerTag tag; ///< Layer tag (arbitrary information) struct PcktSieveLayer_ * parent; ///< Pointer to parent node in the sieve tree struct PcktSieveLayer_ * next, * prev; ///< Next and previous sieve layer on the same level - struct PcktSieveLayer_ * nodes; ///< Subnodes on the sieve tree + struct PcktSieveLayer_ * nodes; ///< Subnodes in the sieve tree + char infoTag[PCKT_SIEVE_INFOTAG_LEN]; ///< Info tag length } PcktSieveLayer; +struct EthInterface_; + +/** + * Packet sieve class. + */ typedef struct { PcktSieveLayer layer0; ///< Top of sieve tree } PcktSieve; @@ -79,14 +100,14 @@ PcktSieve * packsieve_new(); * @param data * @param size */ -void packsieve_input(const PcktSieve * sieve, const RawPckt * rawPckt); +void packsieve_input(const PcktSieve *sieve, const RawPckt *rawPckt, struct EthInterface_ *intf); /** * Create a new sieve filter layer. * @param parent parent layer * @return pointer to new layer object or NULL on failure */ -PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag, uint16_t pcktClass); +PcktSieveLayer *packsieve_new_layer(PcktSieveLayer *parent, const PcktSieveFilterCondition *filtCond, bool matchAny, SieveFilterFn filtFn, SieveCallBackFn cbFn, PcktSieveLayerTag tag, uint16_t pcktClass); /** * Remove sieve layer from packet sieve. diff --git a/prefab/conn_blocks/ipv4_connblock.c b/prefab/conn_blocks/ipv4_connblock.c index 2a2263e..bd3895c 100644 --- a/prefab/conn_blocks/ipv4_connblock.c +++ b/prefab/conn_blocks/ipv4_connblock.c @@ -11,17 +11,28 @@ static bool filtIPv4(const PcktSieveFilterCondition * filtCond, const PcktProps EthernetProps * etherProps = (EthernetProps *) contProps; IPv4Props * ipProps = (IPv4Props *) ownProps; - return etherProps->length_type == ETH_IPv4_PACKET_CLASS && filtCond->u[0] == ipProps->DestIPAddr; + return etherProps->length_type == ETH_IPv4_PACKET_CLASS && IP_ADDR_FROM_FILTCOND(filtCond) == ipProps->DestIPAddr; } ConnBlock ipv4_new_connblock(EthInterface *intf, ip4_addr ipAddr, SieveCallBackFn cbFn) { ConnBlock connb; PcktSieveFilterCondition filtCond; packfiltcond_zero(&filtCond); - filtCond.u[0] = ipAddr; + IP_ADDR_TO_FILTCOND(&filtCond, ipAddr); PcktSieveLayerTag tag; tag.u = 0; - connb.sieveLayer = packsieve_new_layer(&intf->sieve.layer0, &filtCond, filtIPv4, cbFn, tag, ETH_IPv4_PACKET_CLASS); + bool matchAny = ipAddr == IPv4_ANY_ADDR; + connb.sieveLayer = packsieve_new_layer(&intf->sieve.layer0, &filtCond, matchAny, filtIPv4, cbFn, tag, ETH_IPv4_PACKET_CLASS); ASSERT_NULL(connb.sieveLayer); + + connb.intf = intf; + + if (!matchAny) { + SNPRINTF(connb.sieveLayer->infoTag, PCKT_SIEVE_INFOTAG_LEN, "IP: %u.%u.%u.%u", + (ipAddr & 0xFF), ((ipAddr >> 8) & 0xFF), ((ipAddr >> 16) & 0xFF), ((ipAddr >> 24) & 0xFF)); + } else { + SNPRINTF(connb.sieveLayer->infoTag, PCKT_SIEVE_INFOTAG_LEN, "IP: ANY"); + } + return connb; } diff --git a/prefab/conn_blocks/ipv4_connblock.h b/prefab/conn_blocks/ipv4_connblock.h index f69e039..9a670fa 100644 --- a/prefab/conn_blocks/ipv4_connblock.h +++ b/prefab/conn_blocks/ipv4_connblock.h @@ -4,8 +4,10 @@ #include #include "../../connection_block.h" #include "../../eth_interface.h" +#include "../packet_parsers/ipv4_types.h" -typedef uint32_t ip4_addr; +#define IP_ADDR_FROM_FILTCOND(fc) ((fc)->u[0]) +#define IP_ADDR_TO_FILTCOND(fc,addr) (((fc)->u[0]) = (addr)) /** * Create new IPv4 connection block. diff --git a/prefab/conn_blocks/udp_connblock.c b/prefab/conn_blocks/udp_connblock.c index 3781e4b..c14ccb3 100644 --- a/prefab/conn_blocks/udp_connblock.c +++ b/prefab/conn_blocks/udp_connblock.c @@ -14,7 +14,7 @@ static bool filtUdp(const PcktSieveFilterCondition * filtCond, const PcktProps * IPv4Props * ipProps = (IPv4Props *) contProps; UdpProps * udpProps = (UdpProps *) ownProps; - return ipProps->Protocol == ETH_UDP_PACKET_CLASS && filtCond->uw[0] == udpProps->DestinationPort; + return ipProps->Protocol == ETH_UDP_PACKET_CLASS && (UDP_PORT_FROM_FILTCOND(filtCond) == udpProps->DestinationPort); } ConnBlock udp_new_connblock(EthInterface * intf, ip4_addr ipAddr, uint16_t port, SieveCallBackFn cbFn) { @@ -23,18 +23,22 @@ ConnBlock udp_new_connblock(EthInterface * intf, ip4_addr ipAddr, uint16_t port, PcktSieveFilterCondition filtCond; packfiltcond_zero(&filtCond); - filtCond.uw[0] = port; + UDP_PORT_TO_FILTCOND(&filtCond, port); PcktSieveLayerTag tag; tag.u = 0; - udpConnB.sieveLayer = packsieve_new_layer(ipConnB.sieveLayer, &filtCond, filtUdp, cbFn, tag, ETH_UDP_PACKET_CLASS); + udpConnB.sieveLayer = packsieve_new_layer(ipConnB.sieveLayer, &filtCond, false, filtUdp, cbFn, tag, ETH_UDP_PACKET_CLASS); ASSERT_NULL(udpConnB.sieveLayer); + + udpConnB.intf = intf; + + SNPRINTF(udpConnB.sieveLayer->infoTag, PCKT_SIEVE_INFOTAG_LEN, "UDP port: %d", port); + return udpConnB; } #define ALLOC_HEADER_ELEMENT(T) (PcktHeaderElement *) dynmem_alloc(ETH_PCKT_HEADER_ELEMENT_HEAD_SIZE + sizeof(T)) -#define HEADER_FETCH_PROPS(T,h) (T *)(&h->props) -int udp_send(const struct ConnBlock_ * connBlock, const uint8_t *data, uint32_t size) { +int udp_sendto(const struct ConnBlock_ * connBlock, const uint8_t *data, uint32_t size, ip4_addr addr, uint16_t port) { // allocate headers PcktHeaderElement * udpHeader = ALLOC_HEADER_ELEMENT(UdpProps); PcktHeaderElement * ipHeader = ALLOC_HEADER_ELEMENT(IPv4Props); @@ -46,12 +50,71 @@ int udp_send(const struct ConnBlock_ * connBlock, const uint8_t *data, uint32_t ethHeader->next = ipHeader; ethHeader->prev = NULL; + // prepare headers UdpProps * udpProps = HEADER_FETCH_PROPS(UdpProps, udpHeader); IPv4Props * ipProps = HEADER_FETCH_PROPS(IPv4Props, ipHeader); EthernetProps * ethProps = HEADER_FETCH_PROPS(EthernetProps, ethHeader); - udpProps->Length = size; + // fetch sieve layers and fill transmit headers + PcktSieveLayer * layer = connBlock->sieveLayer; // UDP layer + udpProps->SourcePort = UDP_PORT_FROM_FILTCOND(&layer->filtCond); + udpProps->DestinationPort = port; + udpProps->Length = ETH_UDP_HEADER_SIZE + size; + udpProps->Checksum = 0; + // IP + layer = layer->parent; + ipProps->IHL = ETH_IPv4_HEADER_SIZE / 4; + ipProps->Version = 4; + ipProps->DSF = 0x00; + ipProps->TotalLength = ETH_IPv4_HEADER_SIZE + ETH_UDP_HEADER_SIZE + size; + // Identification is filled on header insertion + ipProps->Flags = 0x00; + ipProps->FragmentOffset = 0x00; + ipProps->TTL = 255; + ipProps->Protocol = ETH_UDP_PACKET_CLASS; + // HeaderChecksum is calculated on header insertion + ipProps->SourceIPAddr = connBlock->intf->ip; + ipProps->DestIPAddr = addr; + + // Ethernet + layer = layer->parent; + if (addr != 0xFFFFFFFF) { + memset(ethProps->destAddr, 0x00, ETH_HW_ADDR_LEN); // TODO... + } else { + memset(ethProps->destAddr, 0xFF, ETH_HW_ADDR_LEN); + } + memcpy(ethProps->sourceAddr, connBlock->intf->mac, ETH_HW_ADDR_LEN); + ethProps->length_type = ETH_IPv4_PACKET_CLASS; + + // allocate transmit buffer + uint32_t txHeaderSize = ETH_ETHERNET_HEADER_SIZE + ETH_IPv4_HEADER_SIZE + ETH_UDP_HEADER_SIZE; + uint32_t txBufSize = txHeaderSize + size + 4; + uint8_t * txBuf = dynmem_alloc(txBufSize); + + // copy payload + memcpy(txBuf + txHeaderSize, data, size); + + // insert UDP header + insert_udp_header(txBuf + ETH_ETHERNET_HEADER_SIZE + ETH_IPv4_HEADER_SIZE, udpHeader); + + // insert IPv4 header + insert_ipv4_header(txBuf + ETH_ETHERNET_HEADER_SIZE, ipHeader); + + // insert Ethernet header + insert_ethernet_header(txBuf, ethHeader); + + // append CRC at the end + uint32_t crc = crc32(txBuf, txBufSize - 4); + memcpy(txBuf + txBufSize - 4, &crc, 4); + + // send packet + RawPckt rpckt; + rpckt.size = txBufSize; + rpckt.payload = txBuf; + rpckt.time_s = 0; + rpckt.time_ns = 0; + ethinf_transmit(connBlock->intf, &rpckt); return 0; } diff --git a/prefab/conn_blocks/udp_connblock.h b/prefab/conn_blocks/udp_connblock.h index a88d9b2..a6c627e 100644 --- a/prefab/conn_blocks/udp_connblock.h +++ b/prefab/conn_blocks/udp_connblock.h @@ -6,6 +6,9 @@ #include "../../eth_interface.h" #include "ipv4_connblock.h" +#define UDP_PORT_FROM_FILTCOND(fc) ((fc)->uw[0]) +#define UDP_PORT_TO_FILTCOND(fc,port) (((fc)->uw[0]) = (port)) + /** * Create new IPv4 connection block. * @param intf interface to the connection block will be associated @@ -18,7 +21,12 @@ ConnBlock udp_new_connblock(EthInterface * intf, ip4_addr ipAddr, uint16_t port, /** * UDP transmit callback. + * @param connBlock UDP connection block + * @param data pointer to data buffer + * @param size data size + * @param addr remote address to send datagram to + * @param addr remote port */ -int udp_send(const struct ConnBlock_ * connBlock, const uint8_t * data, uint32_t size); +int udp_sendto(const struct ConnBlock_ * connBlock, const uint8_t * data, uint32_t size, ip4_addr addr, uint16_t port); #endif //ETHERLIB_UDP_CONNBLOCK_H diff --git a/prefab/packet_parsers/arp_packet.c b/prefab/packet_parsers/arp_packet.c index 895a943..74873b9 100644 --- a/prefab/packet_parsers/arp_packet.c +++ b/prefab/packet_parsers/arp_packet.c @@ -3,18 +3,10 @@ // #include "arp_packet.h" +#include "../../packet_registry.h" +#include "ethernet_frame.h" +#include "../../utils.h" int parse_arp_packet(const uint8_t *hdr, uint32_t size, PcktProps * props) { - EthernetProps * frameProps = (EthernetProps *)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 - FETCH_WORD_H2N_ADVANCE(&frameProps->length_type, hdr); // copy length/type field - - // fill-in packet property header fields - frameProps->validityOK = true; - frameProps->containedPacketClass = - frameProps->length_type <= ETH_ETHERTYPE_LENGTH_THRESHOLD ? 0 : frameProps->length_type; - frameProps->headerSize = ETH_ETHERNET_HEADER_SIZE; - - return frameProps->containedPacketClass; + return 0; } \ No newline at end of file diff --git a/prefab/packet_parsers/dhcp.c b/prefab/packet_parsers/dhcp.c new file mode 100644 index 0000000..d796667 --- /dev/null +++ b/prefab/packet_parsers/dhcp.c @@ -0,0 +1,113 @@ +// +// Created by epagris on 2022.12.09.. +// + +#include +#include "dhcp.h" +#include "../../dynmem.h" +#include "../../utils.h" +#include "../../connection_block.h" +#include "../conn_blocks/udp_connblock.h" + +static struct { + DhcpState state; + void * buf; + ConnBlock connb; + uint32_t tranId; +} s; + +static const uint8_t DHCP_MAGIC_COOKIE[] = { 99, 130, 83, 99 }; + +#define SNAME_LEN (64) +#define FILE_LEN (128) + +// (Exact copy of the standard.) +typedef enum { + DHCPDISCOVER = 1, + DHCPOFFER = 2, + DHCPREQUEST = 3, + DHCPDECLINE = 4, + DHCPACK = 5, + DHCPNAK = 6, + DHCPRELEASE = 7 +} DhcpMsgType; + +static void dhcp_option_insert_msg_type(uint8_t ** bufPtr, int msgType) { + (*bufPtr)[0] = 0x35; + (*bufPtr)[1] = 1; + (*bufPtr)[2] = msgType; + (*bufPtr) += 3; +} + +static void dhcp_option_insert_max_msg_size(uint8_t ** bufPtr, uint16_t maxSize) { + (*bufPtr)[0] = 0x39; + (*bufPtr)[1] = 2; + (*bufPtr)[2] = (maxSize >> 8) & 0xFF; + (*bufPtr)[3] = maxSize & 0xFF; + (*bufPtr) += 4; +} + +static void dhcp_option_insert_end(uint8_t ** bufPtr) { + (*bufPtr)[0] = 0xFF; + (*bufPtr) += 1; +} + +static void dhcp_send(EthInterface * intf, DhcpOps * ops) { + // construct message + uint8_t * buf = (uint8_t *)s.buf; + memset(buf, 0, DHCP_MIN_PACKET_SIZE); + FILL_BYTE_ADVANCE(buf, &(ops->op)); + FILL_BYTE_ADVANCE(buf, &(ops->htype)); + FILL_BYTE_ADVANCE(buf, &(ops->hlen)); + FILL_BYTE_ADVANCE(buf, &(ops->hops)); + FILL_DWORD_H2N_ADVANCE(buf, ops->xid); + FILL_WORD_H2N_ADVANCE(buf, ops->secs); + FILL_WORD_H2N_ADVANCE(buf, ops->flags); + FILL_DWORD_H2N_ADVANCE(buf, ops->ciaddr); + FILL_DWORD_H2N_ADVANCE(buf, ops->yiaddr); + FILL_DWORD_H2N_ADVANCE(buf, ops->siaddr); + FILL_DWORD_H2N_ADVANCE(buf, ops->giaddr); + FILL_ADVANCE(buf, ops->chaddr, 16); + buf += SNAME_LEN + FILE_LEN; + FILL_ADVANCE(buf, DHCP_MAGIC_COOKIE, 4); // DHCP magic cookie + + // insert options + dhcp_option_insert_msg_type(&buf, DHCPDISCOVER); + dhcp_option_insert_max_msg_size(&buf, 1500); + dhcp_option_insert_end(&buf); + + udp_sendto(&s.connb, s.buf, DHCP_MIN_PACKET_SIZE, IPv4_ANY_ADDR, DHCP_SERVER_PORT); +} + +static void dhcp_discover(EthInterface * intf) { + s.tranId = rand(); + DhcpOps ops = { 0 }; + + ops.op = DHCP_BOOTREQUEST; + ops.htype = 1; + ops.hlen = 6; + ops.hops = 0; + ops.xid = s.tranId; + ops.secs = 0; + ops.flags = 0; + ops.ciaddr = 0; + ops.yiaddr = 0; + ops.siaddr = 0; + ops.giaddr = 0; + + memcpy(ops.chaddr, intf->mac, ETH_HW_ADDR_LEN); + + dhcp_send(intf, &ops); +} + +static int dhcp_resp_cb(const Pckt * pckt) { + return 0; +} + +void dhcp_initiate(EthInterface *intf) { + s.state = DHCP_INIT_REBOOT; + s.buf = dynmem_alloc(DHCP_MIN_PACKET_SIZE); + s.connb = udp_new_connblock(intf, IPv4_ANY_ADDR, DHCP_CLIENT_PORT, dhcp_resp_cb); + + dhcp_discover(intf); +} diff --git a/prefab/packet_parsers/dhcp.h b/prefab/packet_parsers/dhcp.h new file mode 100644 index 0000000..ca9e144 --- /dev/null +++ b/prefab/packet_parsers/dhcp.h @@ -0,0 +1,56 @@ +#ifndef ETHERLIB_TEST_DHCP_H +#define ETHERLIB_TEST_DHCP_H + +#include +#include "../../eth_interface.h" + +typedef struct { + uint8_t op; ///< Operations + uint8_t htype; ///< Hardware type + uint8_t hlen; ///< Hardware address length + uint8_t hops; ///< Number of network hops + uint32_t xid; ///< Transaction ID + uint16_t secs; ///< Seconds elapsed since client started trying to boot + uint16_t flags; ///< Flags + uint32_t ciaddr; ///< Client IP address (filled in DHCPREQUEST) + uint32_t yiaddr; ///< 'Your' client IP address + uint32_t siaddr; ///< ... + uint32_t giaddr; ///< ... + uint8_t chaddr[16]; ///< Client hardware address + char * sname; ///< Optional server host name + char * file; ///< Boot file name +} DhcpOps; + +/** + * DHCP state. + */ +typedef enum { + DHCP_INIT_REBOOT, + DHCP_REBOOTING, + DHCP_INIT, + DHCP_REQUESTING, + DHCP_SELECTING, + DHCP_REBINDING, + DHCP_BOUND, + DHCP_RENEWING +} DhcpState; + +/** + * DHCP op codes. + */ +typedef enum { + DHCP_BOOTREQUEST = 1, + DHCP_BOOTREPLY = 0 +} DhcpOpCode; + +#define DHCP_MIN_PACKET_SIZE (312) +#define DHCP_CLIENT_PORT (68) +#define DHCP_SERVER_PORT (67) + +/** + * Initiate DHCP on interface + * @param intf interface + */ +void dhcp_initiate(EthInterface * intf); + +#endif //ETHERLIB_TEST_DHCP_H diff --git a/prefab/packet_parsers/ethernet_frame.c b/prefab/packet_parsers/ethernet_frame.c index 959621a..0bb23bf 100644 --- a/prefab/packet_parsers/ethernet_frame.c +++ b/prefab/packet_parsers/ethernet_frame.c @@ -10,8 +10,8 @@ #define ETH_ETHERTYPE_LENGTH_THRESHOLD (1500) #define ETH_ETHERNET_HEADER_SIZE (14) -int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktProps * props) { - EthernetProps * frameProps = (EthernetProps *)props; +int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { + 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 FETCH_WORD_H2N_ADVANCE(&frameProps->length_type, hdr); // copy length/type field diff --git a/prefab/packet_parsers/ethernet_frame.h b/prefab/packet_parsers/ethernet_frame.h index ef07732..daecbb9 100644 --- a/prefab/packet_parsers/ethernet_frame.h +++ b/prefab/packet_parsers/ethernet_frame.h @@ -12,6 +12,8 @@ #define ETH_HW_ADDR_LEN (6) #define ETH_ETHERNET_HEADER_SIZE (14) +#define HEADER_FETCH_PROPS(T,h) (T *)(&((h)->props)) + typedef uint8_t EthernetAddress[ETH_HW_ADDR_LEN]; /** @@ -25,14 +27,16 @@ typedef struct { uint16_t length_type; ///< frame length_type } EthernetProps; +struct EthInterface_; + /** * Parse raw Ethernet frames. * @param hdr pointer to the Ethernet packet header * @param size total frame size - * @param props pointer to property storage + * @param pcktHdrLe pointer to property storage * @return EtherType or 0 (if size is less than 1500) on success or -1 on error */ -int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktProps * props); +int parse_ethernet(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); /** * Insert Ethernet header to specified address. diff --git a/prefab/packet_parsers/ipv4_packet.c b/prefab/packet_parsers/ipv4_packet.c index ab76d68..7c196d9 100644 --- a/prefab/packet_parsers/ipv4_packet.c +++ b/prefab/packet_parsers/ipv4_packet.c @@ -3,28 +3,26 @@ // #include +#include "ethernet_frame.h" #include "ipv4_packet.h" #include "../../utils.h" -static uint16_t ip_checksum(const IPv4Props * ipProps) { +#include "../../eth_interface.h" + +static uint16_t ip_checksum(const uint8_t * hdr) { // sum fields uint32_t sum = 0; - const uint16_t * pField = (const uint16_t *) &ipProps; - for (uint8_t i = 0; i < ipProps->IHL * 2; i++) { - if (i != 5) { // 6. 16-bit long field is the checksum itself, do not count int - sum += pField[i]; + const uint16_t *pField = (const uint16_t *) hdr; + for (uint8_t i = 0; i < (ETH_IPv4_HEADER_SIZE / sizeof(uint16_t)); i++) { + uint16_t field = pField[i]; + if (i != 5) { // 6. 16-bit long field is the checksum itself, do not count in + sum += field; } } - // 16-31 bit carry - uint16_t carry = sum >> 16; - - // add carry - sum += carry; - - // if a new carry bit arisen, then - // add to the sum - sum = (sum & 0xFFFF) + (sum >> 16); + while (sum >> 16) { + sum = (sum & 0xFFFF) + (sum >> 16); + } // invert result uint16_t sum16 = sum ^ 0xFFFF; @@ -33,16 +31,17 @@ static uint16_t ip_checksum(const IPv4Props * ipProps) { #define ETH_IP_HEADER_LENGTH (20) -static bool check_ipv4_validity(const IPv4Props * ipProps) { +static bool check_ipv4_validity(const uint8_t * hdr, const IPv4Props *ipProps) { bool valid = - ipProps->Version != 4 && - ipProps->IHL == ETH_IP_HEADER_LENGTH && - ipProps->HeaderChecksum == ip_checksum(ipProps); + (ipProps->Version == 4) && + (ipProps->IHL == (ETH_IP_HEADER_LENGTH / 4)) && + (ntohs(ipProps->HeaderChecksum) == ip_checksum(hdr)); return valid; } -int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktProps * props) { - IPv4Props * ipProps = (IPv4Props *)props; +int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { + const uint8_t * hdrBegin = hdr; + IPv4Props *ipProps = HEADER_FETCH_PROPS(IPv4Props, pcktHdrLe); uint8_t version_length; FETCH_ADVANCE(&version_length, hdr, 1); ipProps->Version = (version_length) >> 4; @@ -57,31 +56,47 @@ int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktProps * props) { FETCH_ADVANCE(&ipProps->TTL, hdr, 1); FETCH_ADVANCE(&ipProps->Protocol, hdr, 1); FETCH_WORD_H2N_ADVANCE(&ipProps->HeaderChecksum, hdr); - //FETCH_DWORD_H2N_ADVANCE(&ipProps->SourceIPAddr, hdr); - //FETCH_DWORD_H2N_ADVANCE(&ipProps->DestIPAddr, hdr); - FETCH_ADVANCE(&ipProps->SourceIPAddr, hdr, 4); + FETCH_ADVANCE(&ipProps->SourceIPAddr, hdr, 4); // NO network -> host byte order conversion! FETCH_ADVANCE(&ipProps->DestIPAddr, hdr, 4); // fill-in common packet header fields - ipProps->validityOK = check_ipv4_validity(ipProps); + ipProps->validityOK = check_ipv4_validity(hdrBegin, ipProps); ipProps->containedPacketClass = ipProps->Protocol; ipProps->headerSize = ETH_IP_HEADER_LENGTH; + // if packet is valid, learn MAC-IP mapping + if (ipProps->validityOK) { + EthernetProps * ethProps = HEADER_FETCH_PROPS(EthernetProps, pcktHdrLe->prev); // fetch Ethernet header + ArpEntry entry; // fill entry + memcpy(&entry.eth, ethProps->sourceAddr, ETH_HW_ADDR_LEN); + entry.ip = ipProps->SourceIPAddr; + arpc_learn(intf->arpc, &entry); // learn new assignment + } + return ipProps->validityOK ? ipProps->Protocol : -1; } +static uint16_t nextIpIdentification = 0; + void insert_ipv4_header(uint8_t *hdr, const PcktHeaderElement *headers) { - IPv4Props * ipProps = (IPv4Props *)&headers->props; + uint8_t * hdrOrig = hdr; + IPv4Props *ipProps = (IPv4Props *) &headers->props; + ipProps->Identification = nextIpIdentification++; // auto-insert identification uint8_t version_length = (ipProps->Version << 4) | (ipProps->IHL & 0x0F); FILL_ADVANCE(hdr, &version_length, 1); FILL_ADVANCE(hdr, &ipProps->DSF, 1); FILL_WORD_H2N_ADVANCE(hdr, ipProps->TotalLength); FILL_WORD_H2N_ADVANCE(hdr, ipProps->Identification); uint16_t flags_fragOffset = ((ipProps->Flags & 0x07) << 13) | (ipProps->FragmentOffset & ~(0x07 << 13)); + FILL_WORD_H2N_ADVANCE(hdr, flags_fragOffset); // TODO... FILL_ADVANCE(hdr, &ipProps->TTL, 1); FILL_ADVANCE(hdr, &ipProps->Protocol, 1); - uint16_t checksum = ip_checksum(ipProps); - FILL_WORD_H2N_ADVANCE(hdr, checksum); + uint8_t * ChkSumPtr = hdr; + FILL_WORD_H2N_ADVANCE(hdr, 0x0000); FILL_ADVANCE(hdr, &ipProps->SourceIPAddr, 4); FILL_ADVANCE(hdr, &ipProps->DestIPAddr, 4); + + // calculate checksum after filling header + uint16_t checksum = ip_checksum(hdrOrig); + memcpy(ChkSumPtr, &checksum, 2); } diff --git a/prefab/packet_parsers/ipv4_packet.h b/prefab/packet_parsers/ipv4_packet.h index c30eca4..4523c0a 100644 --- a/prefab/packet_parsers/ipv4_packet.h +++ b/prefab/packet_parsers/ipv4_packet.h @@ -6,6 +6,7 @@ #include "../../packet_sieve.h" #define ETH_IPv4_PACKET_CLASS (0x0800) +#define ETH_IPv4_HEADER_SIZE (20) /** * IPv4 header structure @@ -34,14 +35,16 @@ typedef struct { uint32_t DestIPAddr; ///< destination IP-address } IPv4Props; +struct EthInterface_; + /** * Parse raw IPv4 packets. * @param hdr pointer to the IPv4 packet header * @param size total packet size - * @param props pointer to property storage + * @param pcktHdrLe pointer to property storage * @return Protocol on success or -1 on failure */ -int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktProps * props); +int parse_ipv4(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); /** * Insert IPv4 header. diff --git a/prefab/packet_parsers/ipv4_types.h b/prefab/packet_parsers/ipv4_types.h new file mode 100644 index 0000000..a639a6a --- /dev/null +++ b/prefab/packet_parsers/ipv4_types.h @@ -0,0 +1,10 @@ +#ifndef ETHERLIB_TEST_IPV4_TYPES_H +#define ETHERLIB_TEST_IPV4_TYPES_H + +#include + +typedef uint32_t ip4_addr; + +#define IPv4_ANY_ADDR (0xFFFFFFFF) + +#endif //ETHERLIB_TEST_IPV4_TYPES_H diff --git a/prefab/packet_parsers/udp_packet.c b/prefab/packet_parsers/udp_packet.c index 35715d9..31cb876 100644 --- a/prefab/packet_parsers/udp_packet.c +++ b/prefab/packet_parsers/udp_packet.c @@ -2,6 +2,7 @@ #include "udp_packet.h" #include "../../utils.h" #include "ipv4_packet.h" +#include "ethernet_frame.h" #define ETH_UDP_HEADER_SIZE (8) @@ -13,30 +14,40 @@ typedef struct { uint16_t udpLength; } UdpPseudoHeader; -static uint16_t udp_checksum(const UdpPseudoHeader * pseudoHeader, const uint8_t * headerPayload, uint32_t headerPayloadSize) { - uint16_t chksum = 0; - uint16_t i; +static uint16_t udp_checksum(const UdpPseudoHeader *pseudoHeader, const uint8_t * hdr, uint32_t size) { + uint32_t chksum = 0; // pseudoheader - for (i = 0; i < sizeof(UdpPseudoHeader) / 2; i++) { - chksum += ~((uint16_t *)pseudoHeader)[i]; + for (uint16_t i = 0; i < sizeof(UdpPseudoHeader) / 2; i++) { + uint16_t field = ((uint16_t *) pseudoHeader)[i]; + field = htons(field); + chksum += field; } - // UDP header and payload - for (i = 0; i < headerPayloadSize / 2; i++) { + // UDP header and hdr + for (uint16_t i = 0; i < size / 2; i++) { if (i != 3) { // skip Checksum field - chksum += ~((uint16_t *) headerPayload)[i]; + uint16_t field = ((uint16_t *) hdr)[i]; + field = htons(field); + chksum += field; } } // pad if packet size is odd - chksum += ~((uint16_t)headerPayload[headerPayloadSize - 1] << 8); + if (size % 2) { + chksum += ((uint16_t) (hdr[size - 1] << 8)); + } - return chksum; + while (chksum >> 16) { + chksum = (chksum & 0xFFFF) + (chksum >> 16); + } + + uint16_t sum16 = ~(chksum & 0xFFFF); + return sum16; } -int parse_udp(const uint8_t *hdr, uint32_t size, PcktProps * props) { - UdpProps * udpProps = (UdpProps *)props; +int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { + UdpProps *udpProps = HEADER_FETCH_PROPS(UdpProps, pcktHdrLe); FETCH_WORD_H2N_ADVANCE(&udpProps->SourcePort, hdr); FETCH_WORD_H2N_ADVANCE(&udpProps->DestinationPort, hdr); FETCH_WORD_H2N_ADVANCE(&udpProps->Length, hdr); @@ -44,22 +55,23 @@ int parse_udp(const uint8_t *hdr, uint32_t size, PcktProps * props) { // common fields... udpProps->headerSize = ETH_UDP_HEADER_SIZE; - udpProps->validityOK = size == udpProps->Length; // TODO UDP checksum validation! + udpProps->validityOK = (size == udpProps->Length); // TODO UDP checksum validation! udpProps->containedPacketClass = 0; return udpProps->validityOK ? 0 : -1; } void insert_udp_header(uint8_t *hdr, const PcktHeaderElement *headers) { - UdpProps * udpProps = (UdpProps *) &headers->props; + uint8_t *hdrBegin = hdr; + UdpProps *udpProps = (UdpProps *) &headers->props; FILL_WORD_H2N_ADVANCE(hdr, udpProps->SourcePort); FILL_WORD_H2N_ADVANCE(hdr, udpProps->DestinationPort); FILL_WORD_H2N_ADVANCE(hdr, udpProps->Length); // calculate checksum - const IPv4Props * ipProps = (IPv4Props *)&headers->prev->props; - UdpPseudoHeader ph = { ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_UDP_PACKET_CLASS, udpProps->Length }; - udpProps->Checksum = udp_checksum(&ph, hdr, udpProps->Length); + const IPv4Props *ipProps = (IPv4Props *) &headers->prev->props; + UdpPseudoHeader ph = {ipProps->SourceIPAddr, ipProps->DestIPAddr, 0, ETH_UDP_PACKET_CLASS, htons(udpProps->Length)}; + udpProps->Checksum = udp_checksum(&ph, hdrBegin, udpProps->Length); FILL_WORD_H2N_ADVANCE(hdr, udpProps->Checksum); } diff --git a/prefab/packet_parsers/udp_packet.h b/prefab/packet_parsers/udp_packet.h index f230bb8..ae136d6 100644 --- a/prefab/packet_parsers/udp_packet.h +++ b/prefab/packet_parsers/udp_packet.h @@ -6,6 +6,7 @@ #include "../../packet_sieve.h" #define ETH_UDP_PACKET_CLASS (17) +#define ETH_UDP_HEADER_SIZE (8) /** * @struct UdpProps @@ -20,14 +21,16 @@ typedef struct { uint16_t Checksum; ///> UDP checksum } UdpProps; +struct EthInterface_; + /** * Parse raw UDP packets. * @param hdr pointer to the UDP packet header * @param size total packet size - * @param props pointer to property storage + * @param pcktHdrLe pointer to property storage * @return 0 on success or -1 on failure */ -int parse_udp(const uint8_t *hdr, uint32_t size, PcktProps * props); +int parse_udp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); /** * Insert UDP header. diff --git a/utils.c b/utils.c index 402b911..72ace8d 100644 --- a/utils.c +++ b/utils.c @@ -54,7 +54,7 @@ uint32_t crc32(const uint8_t * data, uint32_t size) { uint32_t checksum = ~0; uint32_t i; for (i = 0; i < size; i++) { - checksum = (checksum >> 8) ^ crc32table[checksum ^ data[i]]; + checksum = (checksum >> 8) ^ crc32table[(checksum ^ data[i]) & 0xFF]; } checksum = ~checksum; return checksum; diff --git a/utils.h b/utils.h index 88381aa..d150cd0 100644 --- a/utils.h +++ b/utils.h @@ -34,6 +34,8 @@ #define ERROR(...) MSG(__VA_ARGS__) #define INFO(...) MSG(__VA_ARGS__) +#define SNPRINTF(s,n,...) snprintf(s,n,__VA_ARGS__) + #define IPv4(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24)) #define PRINT_IPv4(ip) MSG("%u.%u.%u.%u", (ip & 0xFF), ((ip >> 8) & 0xFF), ((ip >> 16) & 0xFF), ((ip >> 24) & 0xFF)) @@ -44,10 +46,12 @@ #define FETCH_ADVANCE(dst,src,n) memcpy((dst), (src), n), (src) += n #define FILL_ADVANCE(dst,src,n) memcpy((dst), (src), n), (dst) += n +#define FETCH_BYTE_ADVANCE(dst,src) FETCH_ADVANCE(dst,src,1) +#define FILL_BYTE_ADVANCE(dst,src) FILL_ADVANCE(dst,src,1) #define FETCH_WORD_H2N_ADVANCE(dst,w) { uint16_t u; memcpy(&u, w, 2); u = htons(u); memcpy((dst), &u, 2); (w) += 2; } #define FILL_WORD_H2N_ADVANCE(dst,w) { uint16_t u = htons(w); memcpy((dst), &u, 2); (dst) += 2; } #define FETCH_DWORD_H2N_ADVANCE(dst,dw) { uint32_t du; memcpy(&du, dw, 4); du = htonl(du); memcpy((dst), &du, 4); (dw) += 4; } -#define FILL_DWORD_H2N_ADVANCE(dst,w) { uint32_t du = htonl(dw); memcpy(dst, &du, 4); (dst) += 4; } +#define FILL_DWORD_H2N_ADVANCE(dst,dw) { uint32_t du = htonl(dw); memcpy(dst, &du, 4); (dst) += 4; } // ------------------