1 #include "mcache.h"
2 #include "util.h"
3 
4 #include <assert.h>
5 #include <stdlib.h>
6 #include <string.h>
7 
8 // Delete dead_node and all following nodes from cache
cache_prune(struct mcache_node * dead_node,struct mcache_node ** cache)9 void cache_prune(struct mcache_node *dead_node, struct mcache_node **cache)
10 {
11 	struct mcache_node *node;
12 	struct mcache_node *next;
13 
14 	if (dead_node == *cache) {
15 		*cache = NULL;
16 	} else {
17 		for (node = *cache; node && node->next != dead_node; node = node->next) {
18 		}
19 
20 		/* Assert that dead_node was found in the cache */
21 		assert(node->next == dead_node);
22 		node->next = NULL;
23 	}
24 
25 	/* Delete remaining list */
26 	for (node = dead_node; node; node = next) {
27 		next = node->next;
28 		free(node);
29 	}
30 }
31 
32 // Delete only deda_node from the cache
cache_del(struct mcache_node * dead_node,struct mcache_node ** cache)33 void cache_del(struct mcache_node *dead_node, struct mcache_node **cache)
34 {
35 	struct mcache_node *node;
36 
37 	if (dead_node == *cache) {
38 		*cache = dead_node->next;
39 	} else {
40 		for (node = *cache; node && node->next != dead_node; node = node->next) {
41 		}
42 
43 		assert(node->next == dead_node);
44 		node->next = dead_node->next;
45 	}
46 
47 	free(dead_node);
48 }
49 
50 // Add new node to the cache
cache_add(uint8_t * l2_addr,uint8_t * ip_addr,uint8_t len,time_t tstamp,uint16_t vlan_tag,struct mcache_node ** cache)51 void cache_add(uint8_t *l2_addr, uint8_t *ip_addr, uint8_t len, time_t tstamp,
52 	uint16_t vlan_tag, struct mcache_node **cache)
53 {
54 	struct mcache_node *node;
55 
56 	node = (struct mcache_node *)calloc(sizeof(*node), 1);
57 
58 	if (!node) {
59 		log_msg(LOG_ERR, "%s: unable to allocate memory for new cache node", __FUNCTION__);
60 		return;
61 	}
62 
63 	memcpy(node->l2_addr, l2_addr, sizeof(node->l2_addr));
64 	memcpy(node->ip_addr, ip_addr, len);
65 	node->tstamp = tstamp;
66 	node->addr_len = len;
67 	node->vlan_tag = vlan_tag;
68 
69 	node->next = *cache;
70 	*cache = node;
71 }
72 
cache_lookup(uint8_t * l2_addr,uint8_t * ip_addr,uint8_t len,time_t tstamp,uint16_t vlan_tag,struct mcache_node ** cache)73 struct mcache_node *cache_lookup(uint8_t *l2_addr, uint8_t *ip_addr, uint8_t len,
74 	time_t tstamp, uint16_t vlan_tag, struct mcache_node **cache)
75 {
76 	struct mcache_node *node;
77 
78 	for (node = *cache; node != NULL; node = node->next) {
79 		/* New cache nodes are inserted at the begining of the list
80 		 * resulting cache list ordered by timestamp.
81 		 *
82 		 * If we find old cache node we can safely delete it and all
83 		 * following nodes.
84 		 */
85 		if (cfg.ratelimit > 0 && tstamp > node->tstamp + cfg.ratelimit) {
86 			cache_prune(node, cache);
87 			return NULL;
88 		}
89 
90 		if (vlan_tag != node->vlan_tag) {
91 			continue;
92 		}
93 
94 		if (len != node->addr_len) {
95 			continue;
96 		}
97 
98 		if (memcmp(ip_addr, node->ip_addr, len) != 0) {
99 			continue;
100 		}
101 
102 		if (memcmp(l2_addr, node->l2_addr, sizeof(node->l2_addr)) != 0) {
103 			cache_del(node, cache);
104 			return NULL;
105 		}
106 
107 		return node;
108 	}
109 
110 	return NULL;
111 }
112