1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
*/
#include <libubox/avl.h>
#include "dhcpsnoop.h"
#include "msg.h"
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_VAR(x) x[0], x[1], x[2], x[3], x[4], x[5]
#define IP_FMT "%d.%d.%d.%d"
#define IP_VAR(x) x[0], x[1], x[2], x[3]
struct mac {
struct avl_node avl;
uint8_t mac[6];
uint8_t ip[4];
struct uloop_timeout rebind;
};
static int
avl_mac_cmp(const void *k1, const void *k2, void *ptr)
{
return memcmp(k1, k2, 6);
}
static struct avl_tree mac_tree = AVL_TREE_INIT(mac_tree, avl_mac_cmp, false, NULL);
static void
cache_expire(struct uloop_timeout *t)
{
struct mac *mac = container_of(t, struct mac, rebind);
avl_delete(&mac_tree, &mac->avl);
free(mac);
}
void
cache_entry(void *_msg, uint32_t rebind)
{
struct dhcpv4_message *msg = (struct dhcpv4_message *) _msg;
struct mac *mac;
mac = avl_find_element(&mac_tree, msg->chaddr, mac, avl);
if (!mac) {
mac = malloc(sizeof(*mac));
if (!mac)
return;
memset(mac, 0, sizeof(*mac));
memcpy(mac->mac, msg->chaddr, 6);
mac->avl.key = mac->mac;
mac->rebind.cb = cache_expire;
avl_insert(&mac_tree, &mac->avl);
}
memcpy(mac->ip, &msg->yiaddr.s_addr, 4);
uloop_timeout_set(&mac->rebind, rebind * 1000);
}
void
cache_dump(struct blob_buf *b)
{
struct mac *mac;
avl_for_each_element(&mac_tree, mac, avl) {
char addr[18];
char ip[16];
snprintf(addr, sizeof(addr), MAC_FMT, MAC_VAR(mac->mac));
snprintf(ip, sizeof(ip), IP_FMT, IP_VAR(mac->ip));
blobmsg_add_string(b, addr, ip);
}
}
|