]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: GPL-2.0 */ | |
2 | /* | |
3 | * libgenl.c GENL library | |
4 | */ | |
5 | ||
6 | #include <stdio.h> | |
7 | #include <stdlib.h> | |
8 | #include <unistd.h> | |
9 | ||
10 | #include <linux/genetlink.h> | |
11 | #include "libgenl.h" | |
12 | ||
13 | static int genl_parse_getfamily(struct nlmsghdr *nlh) | |
14 | { | |
15 | struct rtattr *tb[CTRL_ATTR_MAX + 1]; | |
16 | struct genlmsghdr *ghdr = NLMSG_DATA(nlh); | |
17 | int len = nlh->nlmsg_len; | |
18 | struct rtattr *attrs; | |
19 | ||
20 | if (nlh->nlmsg_type != GENL_ID_CTRL) { | |
21 | fprintf(stderr, "Not a controller message, nlmsg_len=%d " | |
22 | "nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type); | |
23 | return -1; | |
24 | } | |
25 | ||
26 | len -= NLMSG_LENGTH(GENL_HDRLEN); | |
27 | ||
28 | if (len < 0) { | |
29 | fprintf(stderr, "wrong controller message len %d\n", len); | |
30 | return -1; | |
31 | } | |
32 | ||
33 | if (ghdr->cmd != CTRL_CMD_NEWFAMILY) { | |
34 | fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd); | |
35 | return -1; | |
36 | } | |
37 | ||
38 | attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); | |
39 | parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len); | |
40 | ||
41 | if (tb[CTRL_ATTR_FAMILY_ID] == NULL) { | |
42 | fprintf(stderr, "Missing family id TLV\n"); | |
43 | return -1; | |
44 | } | |
45 | ||
46 | return rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]); | |
47 | } | |
48 | ||
49 | int genl_resolve_family(struct rtnl_handle *grth, const char *family) | |
50 | { | |
51 | GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, | |
52 | NLM_F_REQUEST); | |
53 | struct nlmsghdr *answer; | |
54 | int fnum; | |
55 | ||
56 | addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME, | |
57 | family, strlen(family) + 1); | |
58 | ||
59 | if (rtnl_talk(grth, &req.n, &answer) < 0) { | |
60 | fprintf(stderr, "Error talking to the kernel\n"); | |
61 | return -2; | |
62 | } | |
63 | ||
64 | fnum = genl_parse_getfamily(answer); | |
65 | free(answer); | |
66 | ||
67 | return fnum; | |
68 | } | |
69 | ||
70 | int genl_init_handle(struct rtnl_handle *grth, const char *family, | |
71 | int *genl_family) | |
72 | { | |
73 | if (*genl_family >= 0) | |
74 | return 0; | |
75 | ||
76 | if (rtnl_open_byproto(grth, 0, NETLINK_GENERIC) < 0) { | |
77 | fprintf(stderr, "Cannot open generic netlink socket\n"); | |
78 | return -1; | |
79 | } | |
80 | ||
81 | *genl_family = genl_resolve_family(grth, family); | |
82 | if (*genl_family < 0) | |
83 | return -1; | |
84 | ||
85 | return 0; | |
86 | } |