gluon/package/gluon-ebtables-limit-arp/src/addr_store.c
2023-01-12 21:46:52 +01:00

164 lines
2.9 KiB
C

// SPDX-FileCopyrightText: 2017 Linus Lüssing <linus.luessing@c0d3.blue>
// SPDX-License-Identifier: GPL-2.0-or-later
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "addr_store.h"
#include "gluon-arp-limiter.h"
#include "lookup3.h"
static struct addr_list *addr_node_alloc(void *addr,
struct addr_store *store)
{
struct addr_list *node;
size_t addr_len = store->addr_len;
node = malloc(sizeof(struct addr_list) + addr_len);
if (!node)
return NULL;
memcpy(node->addr, addr, addr_len);
node->next = NULL;
node->tic = clock;
return node;
}
static struct addr_list *addr_list_search(void *addr,
size_t addr_len,
struct addr_list *list)
{
struct addr_list *node = list;
struct addr_list *ret = NULL;
if (!node)
goto out;
do {
// Found it!
if (!memcmp(node->addr, addr, addr_len)) {
ret = node;
break;
}
node = node->next;
} while (node);
out:
return ret;
}
static void addr_list_add(struct addr_list *node, struct addr_list **list)
{
node->next = *list;
*list = node;
}
static struct addr_list **addr_store_get_bucket(void *addr,
struct addr_store *store)
{
int len = store->addr_len / sizeof(uint32_t);
int idx;
uint32_t ret;
ret = hashword(addr, len, 0);
idx = ret % ADDR_STORE_NUM_BUCKETS;
return &store->buckets[idx];
}
int addr_store_add(void *addr, struct addr_store *store)
{
struct addr_list **bucket = addr_store_get_bucket(addr, store);
struct addr_list *node = addr_list_search(addr, store->addr_len,
*bucket);
if (node) {
node->tic = clock;
return -EEXIST;
}
node = addr_node_alloc(addr, store);
if (!node) {
printf("Error: Out of memory\n");
return -ENOMEM;
}
addr_list_add(node, bucket);
return 0;
}
int addr_store_init(size_t addr_len,
void (*destructor)(struct addr_list *),
char *(*ntoa)(void *),
struct addr_store *store)
{
int i;
store->addr_len = addr_len;
store->destructor = destructor;
store->ntoa = ntoa;
for (i = 0; i < ADDR_STORE_NUM_BUCKETS; i++)
store->buckets[i] = NULL;
return 0;
}
static char *addr_ntoa(void *addr, struct addr_store *store)
{
return store->ntoa(addr);
}
static void addr_store_dump(struct addr_store *store)
{
int i;
struct addr_list *node;
for (i = 0; i < ADDR_STORE_NUM_BUCKETS; i++) {
node = store->buckets[i];
if (node)
printf("Bucket #%i:\n", i);
while (node) {
printf("\t%s\n", addr_ntoa(node->addr, store));
node = node->next;
}
}
}
void addr_store_cleanup(struct addr_store *store)
{
struct addr_list *node, *prev;
int i;
for (i = 0; i < ADDR_STORE_NUM_BUCKETS; i++) {
node = store->buckets[i];
prev = NULL;
while (node) {
if (node->tic != clock) {
store->destructor(node);
if (prev) {
prev->next = node->next;
free(node);
node = prev->next;
} else {
store->buckets[i] = node->next;
free(node);
node = store->buckets[i];
}
} else {
prev = node;
node = node->next;
}
}
}
addr_store_dump(store);
}