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