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
|
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <net/if_arp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/uio.h>
#include <linux/genetlink.h>
#include "triton.h"
#include "log.h"
#include "libnetlink.h"
#define GENL_MAX_FAM_GRPS 128
int __export genl_resolve_mcg(const char *family, const char *name, int *fam_id)
{
struct rtnl_handle rth;
struct nlmsghdr *nlh;
struct genlmsghdr *ghdr;
struct rtattr *tb[CTRL_ATTR_MAX + 1];
struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
struct rtattr *tb3[CTRL_ATTR_MCAST_GRP_MAX + 1];
struct rtattr *attrs;
int i, len, ret = -1;
struct {
struct nlmsghdr n;
char buf[4096];
} req;
if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC)) {
log_error("genl: cannot open rtnetlink\n");
return -1;
}
nlh = &req.n;
nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
nlh->nlmsg_type = GENL_ID_CTRL;
ghdr = NLMSG_DATA(&req.n);
ghdr->cmd = CTRL_CMD_GETFAMILY;
addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
if (rtnl_talk(&rth, nlh, 0, 0, nlh, NULL, NULL, 0) < 0 ) {
log_error("genl: error talking to kernel\n");
goto out;
}
if (nlh->nlmsg_type != GENL_ID_CTRL) {
log_error("genl: not a controller message %d\n", nlh->nlmsg_type);
goto out;
}
ghdr = NLMSG_DATA(nlh);
if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
log_error("genl: unknown controller command %d\n", ghdr->cmd);
goto out;
}
len = nlh->nlmsg_len - NLMSG_LENGTH(GENL_HDRLEN);
if (len < 0) {
log_error("genl: wrong controller message len %d\n", len);
goto out;
}
attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN);
parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
if (!tb[CTRL_ATTR_FAMILY_ID]) {
log_error("genl: missing CTRL_FAMILY_ID attribute\n");
goto out;
}
if (!tb[CTRL_ATTR_MCAST_GROUPS])
goto out;
if (fam_id)
*fam_id = *(uint32_t *)(RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]));
parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS, tb[CTRL_ATTR_MCAST_GROUPS]);
for (i = 1; i < GENL_MAX_FAM_GRPS; i++) {
if (tb2[i]) {
parse_rtattr_nested(tb3, CTRL_ATTR_MCAST_GRP_MAX, tb2[i]);
if (!tb3[CTRL_ATTR_MCAST_GRP_ID] || !tb3[CTRL_ATTR_MCAST_GRP_NAME])
continue;
if (strcmp(RTA_DATA(tb3[CTRL_ATTR_MCAST_GRP_NAME]), name))
continue;
ret = *(uint32_t *)(RTA_DATA(tb3[CTRL_ATTR_MCAST_GRP_ID]));
break;
}
}
out:
rtnl_close(&rth);
return ret;
}
|