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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <stdlib.h>
#include <libdaemon/dlog.h>
#include "nlapi.h"
int nlapi_fd = -1;
struct callback_info {
nlapi_callback_t callback;
void *userdata;
struct callback_info * next;
};
struct callback_info *callbacks = NULL;
int nlapi_open(uint32_t groups) {
struct sockaddr_nl addr;
if ((nlapi_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
fprintf(stderr, "socket(PF_NETLINK): %s\n", strerror(errno));
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = groups;
addr.nl_pid = getpid();
if (bind(nlapi_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(nlapi_fd);
fprintf(stderr, "bind(): %s\n", strerror(errno));
return -1;
}
return 0;
}
int nlapi_work(int block) {
assert(nlapi_fd >= 0);
for (;;) {
int bytes;
char replybuf[1024];
struct nlmsghdr *p = (struct nlmsghdr *) replybuf;
if ((bytes = recv(nlapi_fd, &replybuf, sizeof(replybuf), block ? 0 : MSG_DONTWAIT)) < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
daemon_log(LOG_ERR, "NLAPI: recv(): %s\n", strerror(errno));
return -1;
}
for (; bytes > 0; p = NLMSG_NEXT(p, bytes)) {
struct callback_info *c;
if (!NLMSG_OK(p, bytes) || bytes < sizeof(struct nlmsghdr) || bytes < p->nlmsg_len) {
daemon_log(LOG_ERR, "NLAPI: Packet too small or truncated!\n");
return -1;
}
for (c = callbacks; c; c = c->next)
if (c->callback(p, c->userdata) < 0)
return -1;
}
if (block)
break;
}
return 0;
}
void nlapi_close(void) {
if (nlapi_fd >= 0)
close(nlapi_fd);
nlapi_fd = -1;
while (callbacks) {
struct callback_info *c = callbacks;
callbacks = callbacks->next;
free(c);
}
}
int nlapi_register(int (*callback) (struct nlmsghdr *n, void *u), void *u) {
struct callback_info *c;
assert(callback);
if (!(c = malloc(sizeof(struct callback_info)))) {
daemon_log(LOG_ERR, "NLAPI: Not enough memory.\n");
return -1;
}
c->callback = callback;
c->userdata = u;
c->next = callbacks;
callbacks = c;
return 0;
}
|