EtherLib/arp_cache.c
Epagris 9532b6b274 - EthIntf: packet interception in both directions; DHCP automanage; config loading and storing; info printing
- utils: atoip(), lefttrim()
- ARP: bunch of bugfixes
- TCP, FTP: WIP
- DHCP: mutex; query the FSM state
2024-10-06 23:29:15 +02:00

132 lines
3.7 KiB
C

//
// Created by epagris on 2022.12.10..
//
#include <memory.h>
#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);
//MSG("Megy a válasz!\n");
}
return 0;
}
ArpCache *arpc_new(EthInterface * intf, uint16_t size) {
// allocate table
ArpCache * arcp = (ArpCache *) dynmem_alloc(sizeof(ArpCache) + 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) {
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;
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.sieve->intf->mac, ETH_HW_ADDR_LEN);
arpProps.SPA = arpc->cb.sieve->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 = { 0 };
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.sieve->intf->mac, ETH_HW_ADDR_LEN);
arpProps.SPA = arpc->cb.sieve->intf->ip;
memcpy(arpProps.THA, hwAddr, ETH_HW_ADDR_LEN);
arpProps.TPA = ipAddr;
arp_send(&arpc->cb, &arpProps);
}