From 3efcde1c4bec187971d2412e77397d2f809b9c59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiesner=20Andr=C3=A1s?= Date: Thu, 15 Dec 2022 08:37:53 +0100 Subject: [PATCH] ARP learning works; ARP connblock basics --- arp_cache.c | 10 ++++++ arp_cache.h | 8 +++++ global_state.c | 8 +++++ prefab/conn_blocks/arp_connblock.c | 32 +++++++++++++++++++ prefab/conn_blocks/arp_connblock.h | 15 +++++++++ prefab/packet_parsers/arp_packet.c | 49 ++++++++++++++++++++++++++++-- prefab/packet_parsers/arp_packet.h | 11 ++++++- 7 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 prefab/conn_blocks/arp_connblock.c create mode 100644 prefab/conn_blocks/arp_connblock.h diff --git a/arp_cache.c b/arp_cache.c index a32a89d..3b97b64 100644 --- a/arp_cache.c +++ b/arp_cache.c @@ -5,6 +5,7 @@ #include #include "arp_cache.h" #include "dynmem.h" +#include "utils.h" ArpCache *arpc_new(uint16_t size) { ArpCache * arcp = (ArpCache *) dynmem_alloc(2 * sizeof(uint16_t) + size * sizeof(ArpEntry)); @@ -40,3 +41,12 @@ const ArpEntry *arpc_get(ArpCache *arpc, ip4_addr ip) { return NULL; } + +void arpc_dump(ArpCache *arpc) { + for (uint16_t i = 0; i < arpc->fill; i++) { + ArpEntry * entry = arpc->entries + i; + PRINT_IPv4(entry->ip); + MSG(" -> %02x:%02x:%02x:%02x:%02x:%02x\n", entry->eth[0], entry->eth[1], entry->eth[2], entry->eth[3], entry->eth[4], entry->eth[5]); + } + MSG("\n"); +} diff --git a/arp_cache.h b/arp_cache.h index d1fc6ea..df5dd86 100644 --- a/arp_cache.h +++ b/arp_cache.h @@ -4,6 +4,8 @@ #include "prefab/packet_parsers/ethernet_frame.h" #include "prefab/packet_parsers/ipv4_types.h" +#define ETH_ARP_PACKET_CLASS (0x0806) + /** * ARP cache entry record. */ @@ -48,4 +50,10 @@ const ArpEntry *arpc_get(ArpCache *arpc, ip4_addr ip); */ void arpc_free(ArpCache * aprc); +/** + * Dump ARP cache contents. + * @param arpc + */ +void arpc_dump(ArpCache * arpc); + #endif //ETHERLIB_TEST_ARP_CACHE_H diff --git a/global_state.c b/global_state.c index d4cdf39..0fcd6b7 100644 --- a/global_state.c +++ b/global_state.c @@ -4,6 +4,7 @@ #include "prefab/prefab.h" #include "packet_sieve.h" +#include "prefab/packet_parsers/arp_packet.h" EthState gEthState; @@ -29,6 +30,13 @@ static void register_packet_parsers() { cdesc.procFun = parse_udp; cdesc.propertySize = sizeof(UdpProps); packreg_add_class(E.pcktReg, &cdesc); + + // ARP packet parser + cdesc.class = ETH_ARP_PACKET_CLASS; + cdesc.containerClass = 0; + cdesc.procFun = parse_arp; + cdesc.propertySize = sizeof(ArpProps); + packreg_add_class(E.pcktReg, &cdesc); } void ethlib_init() { diff --git a/prefab/conn_blocks/arp_connblock.c b/prefab/conn_blocks/arp_connblock.c new file mode 100644 index 0000000..28df46d --- /dev/null +++ b/prefab/conn_blocks/arp_connblock.c @@ -0,0 +1,32 @@ +#include "arp_connblock.h" + +#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) { + EthernetProps * ethProps = (EthernetProps *) contProps; + ArpProps * arpProps = (ArpProps *) ownProps; + + return ethProps->length_type == ETH_ARP_PACKET_CLASS; +} + +ConnBlock arp_new_connblock(EthInterface * intf) { + ConnBlock arpConnB; // create ARP connblock + + PcktSieveFilterCondition filtCond; + packfiltcond_zero(&filtCond); + PcktSieveLayerTag tag; + tag.u = 0; + arpConnB.sieveLayer = packsieve_new_layer(&intf->sieve.layer0, &filtCond, false, filtArp, NULL, tag, ETH_ARP_PACKET_CLASS); + ASSERT_NULL(arpConnB.sieveLayer); + + arpConnB.intf = intf; + + SNPRINTF(arpConnB.sieveLayer->infoTag, PCKT_SIEVE_INFOTAG_LEN, "ARP"); + + return arpConnB; +} \ No newline at end of file diff --git a/prefab/conn_blocks/arp_connblock.h b/prefab/conn_blocks/arp_connblock.h new file mode 100644 index 0000000..d0a30d7 --- /dev/null +++ b/prefab/conn_blocks/arp_connblock.h @@ -0,0 +1,15 @@ +#ifndef ETHERLIB_TEST_ARP_CONNBLOCK_H +#define ETHERLIB_TEST_ARP_CONNBLOCK_H + +#endif //ETHERLIB_TEST_ARP_CONNBLOCK_H + +#include +#include "../../connection_block.h" +#include "../../eth_interface.h" + +/** + * Create new ARP connection block. + * @param intf associated Ethernet interface + * @return ARP connection block + */ +ConnBlock arp_new_connblock(EthInterface * intf); \ No newline at end of file diff --git a/prefab/packet_parsers/arp_packet.c b/prefab/packet_parsers/arp_packet.c index 74873b9..5e1e842 100644 --- a/prefab/packet_parsers/arp_packet.c +++ b/prefab/packet_parsers/arp_packet.c @@ -6,7 +6,52 @@ #include "../../packet_registry.h" #include "ethernet_frame.h" #include "../../utils.h" +#include "../../eth_interface.h" -int parse_arp_packet(const uint8_t *hdr, uint32_t size, PcktProps * props) { +static EthernetAddress emptyEthAddr = { 0x00 }; + +static void arp_fetch_mapping(const ArpProps * arpProps, ArpCache * arpc) { + ArpEntry entry; + if ((memcmp(arpProps->SHA, emptyEthAddr, ETH_HW_ADDR_LEN)) && (arpProps->SPA != 0)) { + memcpy(entry.eth, arpProps->SHA, ETH_HW_ADDR_LEN); + entry.ip = arpProps->SPA; + arpc_learn(arpc, &entry); + } + if ((memcmp(arpProps->THA, emptyEthAddr, ETH_HW_ADDR_LEN)) && (arpProps->TPA != 0)) { + memcpy(entry.eth, arpProps->THA, ETH_HW_ADDR_LEN); + entry.ip = arpProps->TPA; + arpc_learn(arpc, &entry); + } +} + +int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf) { + // parse ARP packet + ArpProps *arpProps = HEADER_FETCH_PROPS(ArpProps, pcktHdrLe); + FETCH_WORD_H2N_ADVANCE(&arpProps->HTYPE, hdr); // hardware type + FETCH_WORD_H2N_ADVANCE(&arpProps->PTYPE, hdr); // protocol type + FETCH_BYTE_ADVANCE(&arpProps->HLEN, hdr); // hardware address size + FETCH_BYTE_ADVANCE(&arpProps->PLEN, hdr); // protocol address size + FETCH_WORD_H2N_ADVANCE(&arpProps->OPER, hdr); // operation code + FETCH_ADVANCE(&arpProps->SHA, hdr, ETH_HW_ADDR_LEN); // sender HW address + FETCH_ADVANCE(&arpProps->SPA, hdr, sizeof(ip4_addr)); // sender protocol address + FETCH_ADVANCE(&arpProps->THA, hdr, ETH_HW_ADDR_LEN); // target HW address + FETCH_ADVANCE(&arpProps->TPA, hdr, sizeof(ip4_addr)); // target protocol address + + // learn new mapping + arp_fetch_mapping(arpProps, intf->arpc); return 0; -} \ No newline at end of file +} + +void insert_arp_header(uint8_t *hdr, const PcktHeaderElement *headers) { + ArpProps *arpProps = HEADER_FETCH_PROPS(ArpProps, headers); + + FILL_WORD_H2N_ADVANCE(hdr, arpProps->HTYPE); // hardware type + FILL_WORD_H2N_ADVANCE(hdr, arpProps->PTYPE); // protocol type + FILL_BYTE_ADVANCE(hdr, &arpProps->HLEN); // hardware address size + FILL_BYTE_ADVANCE(hdr, &arpProps->PLEN); // protocol address size + FILL_WORD_H2N_ADVANCE(hdr, arpProps->OPER); // operation code + FILL_ADVANCE(hdr, &arpProps->SHA, ETH_HW_ADDR_LEN); // sender HW address + FILL_ADVANCE(hdr, &arpProps->SPA, sizeof(ip4_addr)); // sender protocol address + FILL_ADVANCE(hdr, &arpProps->THA, ETH_HW_ADDR_LEN); // target HW address + FILL_ADVANCE(hdr, &arpProps->TPA, sizeof(ip4_addr)); // target protocol address +} diff --git a/prefab/packet_parsers/arp_packet.h b/prefab/packet_parsers/arp_packet.h index 417dc55..ed69d83 100644 --- a/prefab/packet_parsers/arp_packet.h +++ b/prefab/packet_parsers/arp_packet.h @@ -6,6 +6,10 @@ #define ETHERLIB_TEST_ARP_PACKET_H #include +#include "ipv4_types.h" + +#include "../../packet_registry.h" +#include "../../packet_sieve.h" #define ETH_ARP_PACKET_CLASS (0x0806) @@ -30,7 +34,12 @@ typedef struct { uint8_t HLEN; ///< Hardware address length uint8_t PLEN; ///< Protocol address length uint16_t OPER; ///< Operation - uint16_t addr[]; ///< Array of addresses (SHA, SPA, THA, TPA) + uint8_t SHA[6]; ///< Array of addresses (SHA, SPA, THA, TPA) + ip4_addr SPA; + uint8_t THA[6]; + ip4_addr TPA; } ArpProps; +int parse_arp(const uint8_t *hdr, uint32_t size, PcktHeaderElement *pcktHdrLe, struct EthInterface_ *intf); + #endif //ETHERLIB_TEST_ARP_PACKET_H