// // Created by epagris on 2022.12.10.. // #include #include "arp_cache.h" #include "dynmem.h" #include "utils.h" #include "eth_interface.h" #include "prefab/conn_blocks/arp_connblock.h" #include "prefab/packet_parsers/arp_packet.h" #include "etherlib_options.h" static int arpc_recv_cb(const Pckt * pckt, PcktSieveLayerTag tag) { ArpProps * arpProps = HEADER_FETCH_PROPS(ArpProps, pckt->header); EthInterface * intf = (EthInterface *) tag.p; // arp_new_connblock() puts pointer to intf into tag field bool weAreCalled = (arpProps->OPER == ARPOP_REQ) && (arpProps->PTYPE == ETH_IPv4_PACKET_CLASS) && (arpProps->TPA == intf->ip) && (intf->ip != 0); ArpCache * arpc = intf->arpc; if (weAreCalled) { arpc_respond(arpc, arpProps->SHA, arpProps->SPA); } return 0; } ArpCache *arpc_new(EthInterface * intf, uint16_t size) { // allocate table ArpCache * arcp = (ArpCache *) dynmem_alloc(2 * sizeof(uint16_t) + sizeof(ConnBlock) + size * sizeof(ArpEntry)); arcp->size = size; arcp->fill = 0; // create connblock arcp->cb = arp_new_connblock(intf, arpc_recv_cb); 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) { // search in the cache for (uint16_t i = 0; i < arpc->fill; i++) { ArpEntry * entry = arpc->entries + i; if (entry->ip == ip) { return entry; } } return NULL; } const ArpEntry *arpc_get_ask(ArpCache *arpc, ip4_addr ip) { const ArpEntry * entry = arpc_get(arpc, ip); if (entry != NULL) { return entry; } // not found in the cache, probe the network uint32_t attemptN = 0; while (((entry = arpc_get(arpc, ip)) == NULL) && (attemptN < ETHLIB_ARP_RETRY_COUNT)) { arpc_ask(arpc, ip); ETHLIB_SLEEP_MS(20); attemptN++; } return entry; } 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"); } void arpc_ask(ArpCache *arpc, ip4_addr addr) { ArpProps arpProps; arpProps.HTYPE = 1; arpProps.PTYPE = ETH_IPv4_PACKET_CLASS; arpProps.HLEN = ETH_HW_ADDR_LEN; arpProps.PLEN = sizeof(ip4_addr); arpProps.OPER = ARPOP_REQ; memcpy(arpProps.SHA, arpc->cb.intf->mac, ETH_HW_ADDR_LEN); arpProps.SPA = arpc->cb.intf->ip; memset(arpProps.THA, 0x00, ETH_HW_ADDR_LEN); arpProps.TPA = addr; arp_send(&arpc->cb, &arpProps); } void arpc_respond(ArpCache *arpc, const EthernetAddress hwAddr, ip4_addr ipAddr) { ArpProps arpProps; arpProps.HTYPE = 1; arpProps.PTYPE = ETH_IPv4_PACKET_CLASS; arpProps.HLEN = ETH_HW_ADDR_LEN; arpProps.PLEN = sizeof(ip4_addr); arpProps.OPER = ARPOP_REP; memcpy(arpProps.SHA, arpc->cb.intf->mac, ETH_HW_ADDR_LEN); arpProps.SPA = arpc->cb.intf->ip; memcpy(arpProps.THA, hwAddr, ETH_HW_ADDR_LEN); arpProps.TPA = ipAddr; arp_send(&arpc->cb, &arpProps); }