]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-netlink/generic-netlink.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / generic-netlink.c
CommitLineData
05d0c2e3
JT
1#include <linux/genetlink.h>
2
3#include "sd-netlink.h"
4#include "netlink-internal.h"
5#include "alloc-util.h"
6
7typedef struct {
8 const char* name;
9 uint8_t version;
10} genl_family;
11
12static 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
17int sd_genl_socket_open(sd_netlink **ret) {
18 return netlink_open_family(ret, NETLINK_GENERIC);
19}
20static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);
21
22static 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
66int 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
79static 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}