]>
Commit | Line | Data |
---|---|---|
05d0c2e3 JT |
1 | #include <linux/genetlink.h> |
2 | ||
3 | #include "sd-netlink.h" | |
4 | #include "netlink-internal.h" | |
5 | #include "alloc-util.h" | |
6 | ||
7 | typedef struct { | |
8 | const char* name; | |
9 | uint8_t version; | |
10 | } genl_family; | |
11 | ||
12 | static const genl_family genl_families[] = { | |
13 | [SD_GENL_ID_CTRL] = { .name = "", .version = 1 }, | |
e5719363 | 14 | [SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 }, |
05d0c2e3 JT |
15 | }; |
16 | ||
17 | int sd_genl_socket_open(sd_netlink **ret) { | |
18 | return netlink_open_family(ret, NETLINK_GENERIC); | |
19 | } | |
20 | static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id); | |
21 | ||
22 | static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) { | |
23 | int r; | |
24 | struct genlmsghdr *genl; | |
25 | const NLType *genl_cmd_type, *nl_type; | |
26 | const NLTypeSystem *type_system; | |
27 | size_t size; | |
28 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; | |
29 | ||
30 | assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); | |
31 | ||
32 | r = type_system_get_type(&genl_family_type_system_root, &genl_cmd_type, family); | |
33 | if (r < 0) | |
34 | return r; | |
35 | ||
36 | r = message_new_empty(nl, &m); | |
37 | if (r < 0) | |
38 | return r; | |
39 | ||
40 | size = NLMSG_SPACE(sizeof(struct genlmsghdr)); | |
41 | m->hdr = malloc0(size); | |
42 | if (!m->hdr) | |
43 | return -ENOMEM; | |
44 | ||
45 | m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; | |
46 | ||
47 | type_get_type_system(genl_cmd_type, &type_system); | |
48 | ||
49 | r = type_system_get_type(type_system, &nl_type, cmd); | |
50 | if (r < 0) | |
51 | return r; | |
52 | ||
53 | m->hdr->nlmsg_len = size; | |
54 | m->hdr->nlmsg_type = nlmsg_type; | |
55 | ||
56 | type_get_type_system(nl_type, &m->containers[0].type_system); | |
57 | genl = NLMSG_DATA(m->hdr); | |
58 | genl->cmd = cmd; | |
59 | genl->version = genl_families[family].version; | |
60 | ||
1cc6c93a | 61 | *ret = TAKE_PTR(m); |
05d0c2e3 JT |
62 | |
63 | return 0; | |
64 | } | |
65 | ||
66 | int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) { | |
67 | int r; | |
68 | uint16_t id = GENL_ID_CTRL; | |
69 | ||
70 | if (family != SD_GENL_ID_CTRL) { | |
71 | r = lookup_id(nl, family, &id); | |
72 | if (r < 0) | |
73 | return r; | |
74 | } | |
75 | ||
76 | return genl_message_new(nl, family, id, cmd, ret); | |
77 | } | |
78 | ||
79 | static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) { | |
80 | int r; | |
81 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; | |
82 | ||
83 | r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req); | |
84 | if (r < 0) | |
85 | return r; | |
86 | ||
87 | r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, genl_families[family].name); | |
88 | if (r < 0) | |
89 | return r; | |
90 | ||
91 | r = sd_netlink_call(nl, req, 0, &reply); | |
92 | if (r < 0) | |
93 | return r; | |
94 | ||
95 | return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id); | |
96 | } |