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
| | #define _GNU_SOURCE
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/param.h>
#include "__netlink.h"
struct __netlink_handle {
int fd;
unsigned int seq;
size_t bufsize;
};
struct __netlink_handle *__netlink_open(int type)
{
struct __netlink_handle *nh;
int bufsize = getpagesize();
/* required buffer size is MIN(8192,pagesize)-sizeof(struct skb_shared_info)
* the estimate for skb_shared_info size is conservative, but gives enough
* space to fit struct __netlink_handle including malloc overhead in one page . */
if (bufsize > 8192) bufsize = 8192;
bufsize -= 128;
nh = malloc(sizeof(struct __netlink_handle) + bufsize);
if (!nh) return 0;
nh->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, type);
if (nh->fd < 0) { free(nh); return 0; }
nh->seq = 1;
nh->bufsize = bufsize;
return nh;
}
void __netlink_close(struct __netlink_handle *nh)
{
close(nh->fd);
free(nh);
}
int __netlink_enumerate(struct __netlink_handle *nh, int type, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
{
struct nlmsghdr *h;
void *buf = (void*)(nh+1);
struct {
struct nlmsghdr nlh;
struct rtgenmsg g;
} *req = buf;
int r, ret = 0;
memset(req, 0, NETLINK_ALIGN(sizeof(*req)));
req->nlh.nlmsg_len = sizeof(*req);
req->nlh.nlmsg_type = type;
req->nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
req->nlh.nlmsg_seq = nh->seq++;
req->g.rtgen_family = AF_UNSPEC;
r = send(nh->fd, req, sizeof(*req), 0);
if (r < 0) return r;
while (1) {
r = recv(nh->fd, buf, nh->bufsize, MSG_DONTWAIT);
if (r <= 0) return -1;
for (h = (struct nlmsghdr*) buf; NLMSG_OK(h, (void*)((uint8_t*)buf+r)); h = NLMSG_NEXT(h)) {
if (h->nlmsg_type == NLMSG_DONE) return ret;
if (h->nlmsg_type == NLMSG_ERROR) return -1;
if (!ret) ret = cb(ctx, h);
}
}
}
|