summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2021-08-24 18:11:20 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2021-08-29 18:10:43 +0900
commit56fdc16da81aa1608d0ab49e76cc124a579382ec (patch)
tree342d71f264e950357fa4942df6740441feaa8676
parent1cedca05e4fadeef0bb88fb58cf9a989ab8e6af2 (diff)
downloadsystemd-56fdc16da81aa1608d0ab49e76cc124a579382ec.tar.gz
sd-netlink: drop sd_genl_family_t and introduce GenericNetlinkFamily
Kernel manages each genl family by its name, e.g. "nlctrl" or WG_GENL_NAME, and its ID (used for nlmsg_type) is determined dynamically when the corresponding module is loaded. This commit makes sd-netlink follow the same way; now, sd_genl_family_t is dropped, and sd_genl_message_new() takes a genl family name. Each genl family is resolved when it is used first time, and its information is stored in GenericNetlinkFamily.
-rw-r--r--src/libsystemd/sd-netlink/netlink-genl.c323
-rw-r--r--src/libsystemd/sd-netlink/netlink-genl.h4
-rw-r--r--src/libsystemd/sd-netlink/netlink-internal.h4
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c38
-rw-r--r--src/libsystemd/sd-netlink/netlink-socket.c6
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-genl.c44
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c50
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.h14
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c4
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c22
-rw-r--r--src/network/netdev/batadv.c2
-rw-r--r--src/network/netdev/fou-tunnel.c2
-rw-r--r--src/network/netdev/l2tp-tunnel.c4
-rw-r--r--src/network/netdev/macsec.c2
-rw-r--r--src/network/netdev/wireguard.c2
-rw-r--r--src/network/test-network-tables.c1
-rw-r--r--src/shared/wifi-util.c21
-rw-r--r--src/systemd/sd-netlink.h19
18 files changed, 363 insertions, 199 deletions
diff --git a/src/libsystemd/sd-netlink/netlink-genl.c b/src/libsystemd/sd-netlink/netlink-genl.c
index 06406add49..1aeca0c5cf 100644
--- a/src/libsystemd/sd-netlink/netlink-genl.c
+++ b/src/libsystemd/sd-netlink/netlink-genl.c
@@ -7,154 +7,302 @@
#include "alloc-util.h"
#include "netlink-genl.h"
#include "netlink-internal.h"
+#include "netlink-types.h"
-typedef struct {
- const char* name;
- uint8_t version;
-} genl_family;
-
-static const genl_family genl_families[] = {
- [SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
- [SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 },
- [SD_GENL_FOU] = { .name = "fou", .version = 1 },
- [SD_GENL_L2TP] = { .name = "l2tp", .version = 1 },
- [SD_GENL_MACSEC] = { .name = "macsec", .version = 1 },
- [SD_GENL_NL80211] = { .name = "nl80211", .version = 1 },
- [SD_GENL_BATADV] = { .name = "batadv", .version = 1 },
+typedef struct GenericNetlinkFamily {
+ sd_netlink *genl;
+
+ const NLTypeSystem *type_system;
+
+ uint16_t id; /* a.k.a nlmsg_type */
+ char *name;
+} GenericNetlinkFamily;
+
+static const GenericNetlinkFamily nlctrl_static = {
+ .id = GENL_ID_CTRL,
+ .name = (char*) CTRL_GENL_NAME,
};
-int sd_genl_socket_open(sd_netlink **ret) {
- return netlink_open_family(ret, NETLINK_GENERIC);
+static GenericNetlinkFamily *genl_family_free(GenericNetlinkFamily *f) {
+ if (!f)
+ return NULL;
+
+ if (f->genl) {
+ if (f->id > 0)
+ hashmap_remove(f->genl->genl_family_by_id, UINT_TO_PTR(f->id));
+ if (f->name)
+ hashmap_remove(f->genl->genl_family_by_name, f->name);
+ }
+
+ free(f->name);
+
+ return mfree(f);
}
-static int genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- const NLType *type;
- size_t size;
+DEFINE_TRIVIAL_CLEANUP_FUNC(GenericNetlinkFamily*, genl_family_free);
+
+void genl_clear_family(sd_netlink *nl) {
+ assert(nl);
+
+ nl->genl_family_by_name = hashmap_free_with_destructor(nl->genl_family_by_name, genl_family_free);
+ nl->genl_family_by_id = hashmap_free_with_destructor(nl->genl_family_by_id, genl_family_free);
+}
+
+static int genl_family_new(
+ sd_netlink *nl,
+ const char *expected_family_name,
+ const NLTypeSystem *type_system,
+ sd_netlink_message *message,
+ const GenericNetlinkFamily **ret) {
+
+ _cleanup_(genl_family_freep) GenericNetlinkFamily *f = NULL;
+ const char *family_name;
int r;
assert(nl);
- assert(nl->protocol == NETLINK_GENERIC);
+ assert(expected_family_name);
+ assert(type_system);
+ assert(message);
assert(ret);
- r = type_system_root_get_type(nl, &type, nlmsg_type);
+ f = new(GenericNetlinkFamily, 1);
+ if (!f)
+ return -ENOMEM;
+
+ *f = (GenericNetlinkFamily) {
+ .type_system = type_system,
+ };
+
+ if (sd_netlink_message_is_error(message)) {
+ int e;
+
+ /* Kernel does not support the genl family? To prevent from resolving the family name
+ * again, let's store the family with zero id to indicate that. */
+
+ e = sd_netlink_message_get_errno(message);
+ if (e >= 0) /* Huh? */
+ e = -EOPNOTSUPP;
+
+ f->name = strdup(expected_family_name);
+ if (!f->name)
+ return e;
+
+ if (hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f) < 0)
+ return e;
+
+ f->genl = nl;
+ TAKE_PTR(f);
+ return e;
+ }
+
+ r = sd_genl_message_get_family_name(nl, message, &family_name);
if (r < 0)
return r;
- r = message_new_empty(nl, &m);
+ if (!streq(family_name, CTRL_GENL_NAME))
+ return -EINVAL;
+
+ r = sd_netlink_message_read_u16(message, CTRL_ATTR_FAMILY_ID, &f->id);
if (r < 0)
return r;
- size = NLMSG_SPACE(sizeof(struct genlmsghdr));
- m->hdr = malloc0(size);
- if (!m->hdr)
- return -ENOMEM;
-
- m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
- m->hdr->nlmsg_len = size;
- m->hdr->nlmsg_type = nlmsg_type;
+ r = sd_netlink_message_read_string_strdup(message, CTRL_ATTR_FAMILY_NAME, &f->name);
+ if (r < 0)
+ return r;
- m->containers[0].type_system = type_get_type_system(type);
+ if (!streq(f->name, expected_family_name))
+ return -EINVAL;
- *(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) {
- .cmd = cmd,
- .version = genl_families[family].version,
- };
+ r = hashmap_ensure_put(&nl->genl_family_by_id, NULL, UINT_TO_PTR(f->id), f);
+ if (r < 0)
+ return r;
- *ret = TAKE_PTR(m);
+ r = hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f);
+ if (r < 0) {
+ hashmap_remove(nl->genl_family_by_id, UINT_TO_PTR(f->id));
+ return r;
+ }
+ f->genl = nl;
+ *ret = TAKE_PTR(f);
return 0;
}
-static int lookup_nlmsg_type(sd_netlink *nl, sd_genl_family_t family, uint16_t *ret) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
- uint16_t u;
- void *v;
- int r;
-
- assert(nl);
- assert(nl->protocol == NETLINK_GENERIC);
+static int genl_family_get_type_system(const GenericNetlinkFamily *family, const NLTypeSystem **ret) {
+ assert(family);
assert(ret);
- if (family == SD_GENL_ID_CTRL) {
- *ret = GENL_ID_CTRL;
+ if (family->type_system) {
+ *ret = family->type_system;
return 0;
}
- v = hashmap_get(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family));
- if (v) {
- *ret = PTR_TO_UINT(v);
- return 0;
- }
+ return genl_get_type_system_by_name(family->name, ret);
+}
+
+static int genl_message_new(
+ sd_netlink *nl,
+ const GenericNetlinkFamily *family,
+ uint8_t cmd,
+ sd_netlink_message **ret) {
+
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ const NLTypeSystem *type_system;
+ int r;
- r = genl_message_new(nl, SD_GENL_ID_CTRL, GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
+ assert(nl);
+ assert(nl->protocol == NETLINK_GENERIC);
+ assert(family);
+ assert(ret);
+
+ r = genl_family_get_type_system(family, &type_system);
if (r < 0)
return r;
- r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, genl_families[family].name);
+ r = message_new_full(nl, family->id, type_system, sizeof(struct genlmsghdr), &m);
if (r < 0)
return r;
- r = sd_netlink_call(nl, req, 0, &reply);
+ *(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) {
+ .cmd = cmd,
+ .version = 1,
+ };
+
+ *ret = TAKE_PTR(m);
+ return 0;
+}
+
+static int genl_family_get_by_name_internal(
+ sd_netlink *nl,
+ const GenericNetlinkFamily *ctrl,
+ const char *name,
+ const GenericNetlinkFamily **ret) {
+
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ const NLTypeSystem *type_system;
+ int r;
+
+ assert(nl);
+ assert(nl->protocol == NETLINK_GENERIC);
+ assert(ctrl);
+ assert(name);
+ assert(ret);
+
+ r = genl_get_type_system_by_name(name, &type_system);
if (r < 0)
return r;
- r = sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, &u);
+ r = genl_message_new(nl, ctrl, CTRL_CMD_GETFAMILY, &req);
if (r < 0)
return r;
- r = hashmap_ensure_put(&nl->genl_family_to_nlmsg_type, NULL, INT_TO_PTR(family), UINT_TO_PTR(u));
+ r = sd_netlink_message_append_string(req, CTRL_ATTR_FAMILY_NAME, name);
if (r < 0)
return r;
- r = hashmap_ensure_put(&nl->nlmsg_type_to_genl_family, NULL, UINT_TO_PTR(u), INT_TO_PTR(family));
+ r = sd_netlink_call(nl, req, 0, &reply);
if (r < 0)
return r;
- *ret = u;
- return 0;
+ return genl_family_new(nl, name, type_system, reply, ret);
}
-int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret) {
- uint16_t nlmsg_type = 0; /* Unnecessary initialization to appease gcc */
+static int genl_family_get_by_name(sd_netlink *nl, const char *name, const GenericNetlinkFamily **ret) {
+ const GenericNetlinkFamily *f, *ctrl;
int r;
- assert_return(nl, -EINVAL);
- assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
- assert_return(ret, -EINVAL);
+ assert(nl);
+ assert(nl->protocol == NETLINK_GENERIC);
+ assert(name);
+ assert(ret);
- r = lookup_nlmsg_type(nl, family, &nlmsg_type);
- if (r < 0)
- return r;
+ f = hashmap_get(nl->genl_family_by_name, name);
+ if (f) {
+ if (f->id == 0) /* kernel does not support the family. */
+ return -EOPNOTSUPP;
+
+ *ret = f;
+ return 0;
+ }
+
+ if (streq(name, CTRL_GENL_NAME))
+ return genl_family_get_by_name_internal(nl, &nlctrl_static, CTRL_GENL_NAME, ret);
+
+ ctrl = hashmap_get(nl->genl_family_by_name, CTRL_GENL_NAME);
+ if (!ctrl) {
+ r = genl_family_get_by_name_internal(nl, &nlctrl_static, CTRL_GENL_NAME, &ctrl);
+ if (r < 0)
+ return r;
+ }
- return genl_message_new(nl, family, nlmsg_type, cmd, ret);
+ return genl_family_get_by_name_internal(nl, ctrl, name, ret);
}
-int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t nlmsg_type, sd_genl_family_t *ret) {
- void *p;
+static int genl_family_get_by_id(sd_netlink *nl, uint16_t id, const GenericNetlinkFamily **ret) {
+ const GenericNetlinkFamily *f;
assert(nl);
assert(nl->protocol == NETLINK_GENERIC);
assert(ret);
- if (nlmsg_type == NLMSG_ERROR)
- *ret = SD_GENL_ERROR;
- else if (nlmsg_type == NLMSG_DONE)
- *ret = SD_GENL_DONE;
- else if (nlmsg_type == GENL_ID_CTRL)
- *ret = SD_GENL_ID_CTRL;
- else {
- p = hashmap_get(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(nlmsg_type));
- if (!p)
- return -EOPNOTSUPP;
+ f = hashmap_get(nl->genl_family_by_id, UINT_TO_PTR(id));
+ if (f) {
+ *ret = f;
+ return 0;
+ }
- *ret = PTR_TO_INT(p);
+ if (id == GENL_ID_CTRL) {
+ *ret = &nlctrl_static;
+ return 0;
}
+ return -ENOENT;
+}
+
+int genl_get_type_system_and_header_size(
+ sd_netlink *nl,
+ uint16_t id,
+ const NLTypeSystem **ret_type_system,
+ size_t *ret_header_size) {
+
+ const GenericNetlinkFamily *f;
+ int r;
+
+ assert(nl);
+ assert(nl->protocol == NETLINK_GENERIC);
+
+ r = genl_family_get_by_id(nl, id, &f);
+ if (r < 0)
+ return r;
+
+ if (ret_type_system) {
+ r = genl_family_get_type_system(f, ret_type_system);
+ if (r < 0)
+ return r;
+ }
+ if (ret_header_size)
+ *ret_header_size = sizeof(struct genlmsghdr);
return 0;
}
-int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family_t *ret) {
+int sd_genl_message_new(sd_netlink *nl, const char *family_name, uint8_t cmd, sd_netlink_message **ret) {
+ const GenericNetlinkFamily *family;
+ int r;
+
+ assert_return(nl, -EINVAL);
+ assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
+ assert_return(family_name, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = genl_family_get_by_name(nl, family_name, &family);
+ if (r < 0)
+ return r;
+
+ return genl_message_new(nl, family, cmd, ret);
+}
+
+int sd_genl_message_get_family_name(sd_netlink *nl, sd_netlink_message *m, const char **ret) {
+ const GenericNetlinkFamily *family;
uint16_t nlmsg_type;
int r;
@@ -167,5 +315,14 @@ int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_fa
if (r < 0)
return r;
- return nlmsg_type_to_genl_family(nl, nlmsg_type, ret);
+ r = genl_family_get_by_id(nl, nlmsg_type, &family);
+ if (r < 0)
+ return r;
+
+ *ret = family->name;
+ return 0;
+}
+
+int sd_genl_socket_open(sd_netlink **ret) {
+ return netlink_open_family(ret, NETLINK_GENERIC);
}
diff --git a/src/libsystemd/sd-netlink/netlink-genl.h b/src/libsystemd/sd-netlink/netlink-genl.h
index fd0461426b..b06be05952 100644
--- a/src/libsystemd/sd-netlink/netlink-genl.h
+++ b/src/libsystemd/sd-netlink/netlink-genl.h
@@ -3,4 +3,6 @@
#include "sd-netlink.h"
-int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family_t *ret);
+#define CTRL_GENL_NAME "nlctrl"
+
+void genl_clear_family(sd_netlink *nl);
diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h
index e19b460bcd..2594885fe6 100644
--- a/src/libsystemd/sd-netlink/netlink-internal.h
+++ b/src/libsystemd/sd-netlink/netlink-internal.h
@@ -95,8 +95,8 @@ struct sd_netlink {
sd_event_source *exit_event_source;
sd_event *event;
- Hashmap *genl_family_to_nlmsg_type;
- Hashmap *nlmsg_type_to_genl_family;
+ Hashmap *genl_family_by_name;
+ Hashmap *genl_family_by_id;
};
struct netlink_attribute {
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 325c570b2e..0c9b5454b6 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -80,20 +80,18 @@ int message_new_full(
}
int message_new(sd_netlink *nl, sd_netlink_message **ret, uint16_t type) {
- const NLType *nl_type;
+ const NLTypeSystem *type_system;
+ size_t size;
int r;
assert_return(nl, -EINVAL);
assert_return(ret, -EINVAL);
- r = type_system_root_get_type(nl, &nl_type, type);
+ r = type_system_root_get_type_system_and_header_size(nl, type, &type_system, &size);
if (r < 0)
return r;
- if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
- return -EINVAL;
-
- return message_new_full(nl, type, type_get_type_system(nl_type), type_get_size(nl_type), ret);
+ return message_new_full(nl, type, type_system, size, ret);
}
int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_netlink_message **ret) {
@@ -1319,8 +1317,6 @@ static int netlink_message_parse_error(sd_netlink_message *m) {
}
int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
- const NLType *nl_type;
- uint16_t type;
size_t size;
int r;
@@ -1341,28 +1337,18 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *nl) {
assert(m->hdr);
- r = type_system_root_get_type(nl, &nl_type, m->hdr->nlmsg_type);
+ r = type_system_root_get_type_system_and_header_size(nl, m->hdr->nlmsg_type,
+ &m->containers[0].type_system, &size);
if (r < 0)
return r;
- type = type_get_type(nl_type);
- size = type_get_size(nl_type);
-
- if (type == NETLINK_TYPE_NESTED) {
- m->containers[0].type_system = type_get_type_system(nl_type);
+ if (sd_netlink_message_is_error(m))
+ return netlink_message_parse_error(m);
- if (sd_netlink_message_is_error(m))
- r = netlink_message_parse_error(m);
- else
- r = netlink_container_parse(m,
- &m->containers[m->n_containers],
- (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
- NLMSG_PAYLOAD(m->hdr, size));
- if (r < 0)
- return r;
- }
-
- return 0;
+ return netlink_container_parse(m,
+ &m->containers[0],
+ (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
+ NLMSG_PAYLOAD(m->hdr, size));
}
void message_seal(sd_netlink_message *m) {
diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c
index 1168f4edc0..15c2789bee 100644
--- a/src/libsystemd/sd-netlink/netlink-socket.c
+++ b/src/libsystemd/sd-netlink/netlink-socket.c
@@ -326,7 +326,7 @@ int socket_read_message(sd_netlink *nl) {
for (struct nlmsghdr *new_msg = nl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- const NLType *nl_type;
+ size_t size;
if (!group && new_msg->nlmsg_pid != nl->sockaddr.nl.nl_pid)
/* not broadcast and not for us */
@@ -346,7 +346,7 @@ int socket_read_message(sd_netlink *nl) {
}
/* check that we support this message type */
- r = type_system_root_get_type(nl, &nl_type, new_msg->nlmsg_type);
+ r = type_system_root_get_type_system_and_header_size(nl, new_msg->nlmsg_type, NULL, &size);
if (r < 0) {
if (r == -EOPNOTSUPP)
log_debug("sd-netlink: ignored message with unknown type: %i",
@@ -356,7 +356,7 @@ int socket_read_message(sd_netlink *nl) {
}
/* check that the size matches the message type */
- if (new_msg->nlmsg_len < NLMSG_LENGTH(type_get_size(nl_type))) {
+ if (new_msg->nlmsg_len < NLMSG_LENGTH(size)) {
log_debug("sd-netlink: message is shorter than expected, dropping");
continue;
}
diff --git a/src/libsystemd/sd-netlink/netlink-types-genl.c b/src/libsystemd/sd-netlink/netlink-types-genl.c
index 33e80a1745..dde682f626 100644
--- a/src/libsystemd/sd-netlink/netlink-types-genl.c
+++ b/src/libsystemd/sd-netlink/netlink-types-genl.c
@@ -44,8 +44,6 @@ static const NLType genl_ctrl_types[] = {
[CTRL_ATTR_OP] = { .type = NETLINK_TYPE_U32 },
};
-DEFINE_TYPE_SYSTEM(genl_ctrl);
-
/***************** genl batadv type systems *****************/
static const NLType genl_batadv_types[] = {
[BATADV_ATTR_VERSION] = { .type = NETLINK_TYPE_STRING },
@@ -110,8 +108,6 @@ static const NLType genl_batadv_types[] = {
[BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NETLINK_TYPE_U32 },
};
-DEFINE_TYPE_SYSTEM(genl_batadv);
-
/***************** genl fou type systems *****************/
static const NLType genl_fou_types[] = {
[FOU_ATTR_PORT] = { .type = NETLINK_TYPE_U16 },
@@ -127,8 +123,6 @@ static const NLType genl_fou_types[] = {
[FOU_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32},
};
-DEFINE_TYPE_SYSTEM(genl_fou);
-
/***************** genl l2tp type systems *****************/
static const NLType genl_l2tp_types[] = {
[L2TP_ATTR_PW_TYPE] = { .type = NETLINK_TYPE_U16 },
@@ -160,8 +154,6 @@ static const NLType genl_l2tp_types[] = {
[L2TP_ATTR_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_FLAG },
};
-DEFINE_TYPE_SYSTEM(genl_l2tp);
-
/***************** genl macsec type systems *****************/
static const NLType genl_macsec_rxsc_types[] = {
[MACSEC_RXSC_ATTR_SCI] = { .type = NETLINK_TYPE_U64 },
@@ -185,8 +177,6 @@ static const NLType genl_macsec_types[] = {
[MACSEC_ATTR_SA_CONFIG] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_sa_type_system },
};
-DEFINE_TYPE_SYSTEM(genl_macsec);
-
/***************** genl nl80211 type systems *****************/
static const NLType genl_nl80211_types[] = {
[NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
@@ -195,8 +185,6 @@ static const NLType genl_nl80211_types[] = {
[NL80211_ATTR_IFTYPE] = { .type = NETLINK_TYPE_U32 },
};
-DEFINE_TYPE_SYSTEM(genl_nl80211);
-
/***************** genl wireguard type systems *****************/
static const NLType genl_wireguard_allowedip_types[] = {
[WGALLOWEDIP_A_FAMILY] = { .type = NETLINK_TYPE_U16 },
@@ -227,28 +215,20 @@ static const NLType genl_wireguard_types[] = {
[WGDEVICE_A_PEERS] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_peer_type_system },
};
-DEFINE_TYPE_SYSTEM(genl_wireguard);
-
/***************** genl families *****************/
-static const NLType genl_types[] = {
- [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_type_system, .size = sizeof(struct genlmsghdr) },
- [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system, .size = sizeof(struct genlmsghdr) },
- [SD_GENL_FOU] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_type_system, .size = sizeof(struct genlmsghdr) },
- [SD_GENL_L2TP] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system, .size = sizeof(struct genlmsghdr) },
- [SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_type_system, .size = sizeof(struct genlmsghdr) },
- [SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system, .size = sizeof(struct genlmsghdr) },
- [SD_GENL_BATADV] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_batadv_type_system, .size = sizeof(struct genlmsghdr) },
+static const NLTypeSystemUnionElement genl_type_systems[] = {
+ { .name = CTRL_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_ctrl), },
+ { .name = BATADV_NL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_batadv), },
+ { .name = FOU_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_fou), },
+ { .name = L2TP_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_l2tp), },
+ { .name = MACSEC_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_macsec), },
+ { .name = NL80211_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_nl80211), },
+ { .name = WG_GENL_NAME, .type_system = TYPE_SYSTEM_FROM_TYPE(genl_wireguard), },
};
-DEFINE_TYPE_SYSTEM(genl);
-
-int genl_get_type(sd_netlink *genl, uint16_t nlmsg_type, const NLType **ret) {
- sd_genl_family_t family;
- int r;
-
- r = nlmsg_type_to_genl_family(genl, nlmsg_type, &family);
- if (r < 0)
- return r;
+/* This is the root type system union, so match_attribute is not necessary. */
+DEFINE_TYPE_SYSTEM_UNION_MATCH_SIBLING(genl, 0);
- return type_system_get_type(&genl_type_system, ret, family);
+int genl_get_type_system_by_name(const char *name, const NLTypeSystem **ret) {
+ return type_system_union_get_type_system_by_string(&genl_type_system_union, ret, name);
}
diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c
index 0f17e7e8ad..7d6caf004b 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -2,6 +2,7 @@
#include <linux/netlink.h>
+#include "netlink-genl.h"
#include "netlink-internal.h"
#include "netlink-types-internal.h"
@@ -54,20 +55,43 @@ uint16_t type_system_get_count(const NLTypeSystem *type_system) {
return type_system->count;
}
-int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type) {
- if (!nl || IN_SET(type, NLMSG_DONE, NLMSG_ERROR))
- return type_system_get_type(&basic_type_system, ret, type);
-
- switch(nl->protocol) {
- case NETLINK_ROUTE:
- return rtnl_get_type(type, ret);
- case NETLINK_NETFILTER:
- return nfnl_get_type(type, ret);
- case NETLINK_GENERIC:
- return genl_get_type(nl, type, ret);
- default:
+int type_system_root_get_type_system_and_header_size(
+ sd_netlink *nl,
+ uint16_t type,
+ const NLTypeSystem **ret_type_system,
+ size_t *ret_header_size) {
+
+ const NLType *nl_type;
+ int r;
+
+ assert(nl);
+
+ if (IN_SET(type, NLMSG_DONE, NLMSG_ERROR))
+ r = type_system_get_type(&basic_type_system, &nl_type, type);
+ else
+ switch(nl->protocol) {
+ case NETLINK_ROUTE:
+ r = rtnl_get_type(type, &nl_type);
+ break;
+ case NETLINK_NETFILTER:
+ r = nfnl_get_type(type, &nl_type);
+ break;
+ case NETLINK_GENERIC:
+ return genl_get_type_system_and_header_size(nl, type, ret_type_system, ret_header_size);
+ default:
+ return -EOPNOTSUPP;
+ }
+ if (r < 0)
+ return r;
+
+ if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
return -EOPNOTSUPP;
- }
+
+ if (ret_type_system)
+ *ret_type_system = type_get_type_system(nl_type);
+ if (ret_header_size)
+ *ret_header_size = type_get_size(nl_type);
+ return 0;
}
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h
index baab1dbdb0..f8261b681c 100644
--- a/src/libsystemd/sd-netlink/netlink-types.h
+++ b/src/libsystemd/sd-netlink/netlink-types.h
@@ -37,15 +37,25 @@ typedef struct NLType NLType;
int rtnl_get_type(uint16_t nlmsg_type, const NLType **ret);
int nfnl_get_type(uint16_t nlmsg_type, const NLType **ret);
-int genl_get_type(sd_netlink *genl, uint16_t nlmsg_type, const NLType **ret);
+int genl_get_type_system_by_name(const char *name, const NLTypeSystem **ret);
+int genl_get_type_system_and_header_size(
+ sd_netlink *nl,
+ uint16_t id,
+ const NLTypeSystem **ret_type_system,
+ size_t *ret_header_size);
uint16_t type_get_type(const NLType *type);
size_t type_get_size(const NLType *type);
const NLTypeSystem *type_get_type_system(const NLType *type);
const NLTypeSystemUnion *type_get_type_system_union(const NLType *type);
+int type_system_root_get_type_system_and_header_size(
+ sd_netlink *nl,
+ uint16_t type,
+ const NLTypeSystem **ret_type_system,
+ size_t *ret_header_size);
+
uint16_t type_system_get_count(const NLTypeSystem *type_system);
-int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type);
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index 22697aa992..2305333575 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -9,6 +9,7 @@
#include "hashmap.h"
#include "io-util.h"
#include "macro.h"
+#include "netlink-genl.h"
#include "netlink-internal.h"
#include "netlink-slot.h"
#include "process-util.h"
@@ -196,8 +197,7 @@ static sd_netlink *netlink_free(sd_netlink *nl) {
hashmap_free(nl->broadcast_group_refs);
- hashmap_free(nl->genl_family_to_nlmsg_type);
- hashmap_free(nl->nlmsg_type_to_genl_family);
+ genl_clear_family(nl);
safe_close(nl->fd);
return mfree(nl);
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index a87fe11069..6cc6cdad45 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -9,6 +9,7 @@
#include "alloc-util.h"
#include "ether-addr-util.h"
#include "macro.h"
+#include "netlink-genl.h"
#include "netlink-internal.h"
#include "netlink-util.h"
#include "socket-util.h"
@@ -514,7 +515,7 @@ static void test_array(void) {
log_debug("/* %s */", __func__);
assert_se(sd_genl_socket_open(&genl) >= 0);
- assert_se(sd_genl_message_new(genl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &m) >= 0);
+ assert_se(sd_genl_message_new(genl, CTRL_GENL_NAME, CTRL_CMD_GETFAMILY, &m) >= 0);
assert_se(sd_netlink_message_open_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
for (unsigned i = 0; i < 10; i++) {
@@ -582,6 +583,23 @@ static void test_strv(sd_netlink *rtnl) {
assert_se(sd_netlink_message_exit_container(m) >= 0);
}
+static void test_genl(void) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ const char *name;
+
+ log_debug("/* %s */", __func__);
+
+ assert_se(sd_genl_socket_open(&genl) >= 0);
+ assert_se(sd_genl_message_new(genl, CTRL_GENL_NAME, CTRL_CMD_GETFAMILY, &m) >= 0);
+ assert_se(sd_genl_message_get_family_name(genl, m, &name) >= 0);
+ assert_se(streq(name, CTRL_GENL_NAME));
+
+ m = sd_netlink_message_unref(m);
+ assert_se(sd_genl_message_new(genl, "should-not-exist", CTRL_CMD_GETFAMILY, &m) < 0);
+ assert_se(sd_genl_message_new(genl, "should-not-exist", CTRL_CMD_GETFAMILY, &m) == -EOPNOTSUPP);
+}
+
int main(void) {
sd_netlink *rtnl;
sd_netlink_message *m;
@@ -642,5 +660,7 @@ int main(void) {
assert_se((r = sd_netlink_message_unref(r)) == NULL);
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
+ test_genl();
+
return EXIT_SUCCESS;
}
diff --git a/src/network/netdev/batadv.c b/src/network/netdev/batadv.c
index 1f899e90f6..1d12fc79cc 100644
--- a/src/network/netdev/batadv.c
+++ b/src/network/netdev/batadv.c
@@ -122,7 +122,7 @@ static int netdev_batadv_post_create(NetDev *netdev, Link *link, sd_netlink_mess
b = BATADV(netdev);
assert(b);
- r = sd_genl_message_new(netdev->manager->genl, SD_GENL_BATADV, BATADV_CMD_SET_MESH, &message);
+ r = sd_genl_message_new(netdev->manager->genl, BATADV_NL_NAME, BATADV_CMD_SET_MESH, &message);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
diff --git a/src/network/netdev/fou-tunnel.c b/src/network/netdev/fou-tunnel.c
index e01de0f151..bc4c108a22 100644
--- a/src/network/netdev/fou-tunnel.c
+++ b/src/network/netdev/fou-tunnel.c
@@ -36,7 +36,7 @@ static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **r
assert(t);
- r = sd_genl_message_new(netdev->manager->genl, SD_GENL_FOU, FOU_CMD_ADD, &m);
+ r = sd_genl_message_new(netdev->manager->genl, FOU_GENL_NAME, FOU_CMD_ADD, &m);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
diff --git a/src/network/netdev/l2tp-tunnel.c b/src/network/netdev/l2tp-tunnel.c
index f651b2f7bf..a04fa6ac46 100644
--- a/src/network/netdev/l2tp-tunnel.c
+++ b/src/network/netdev/l2tp-tunnel.c
@@ -104,7 +104,7 @@ static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, union in_addr_union *
assert(t);
- r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_TUNNEL_CREATE, &m);
+ r = sd_genl_message_new(netdev->manager->genl, L2TP_GENL_NAME, L2TP_CMD_TUNNEL_CREATE, &m);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
@@ -195,7 +195,7 @@ static int netdev_l2tp_fill_message_session(NetDev *netdev, L2tpSession *session
assert(session);
assert(session->tunnel);
- r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_SESSION_CREATE, &m);
+ r = sd_genl_message_new(netdev->manager->genl, L2TP_GENL_NAME, L2TP_CMD_SESSION_CREATE, &m);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c
index 74e9fdd10b..3b0c940804 100644
--- a/src/network/netdev/macsec.c
+++ b/src/network/netdev/macsec.c
@@ -224,7 +224,7 @@ static int netdev_macsec_fill_message(NetDev *netdev, int command, sd_netlink_me
assert(netdev);
assert(netdev->ifindex > 0);
- r = sd_genl_message_new(netdev->manager->genl, SD_GENL_MACSEC, command, &m);
+ r = sd_genl_message_new(netdev->manager->genl, MACSEC_GENL_NAME, command, &m);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c
index b8fc492d4f..1e90cad2e7 100644
--- a/src/network/netdev/wireguard.c
+++ b/src/network/netdev/wireguard.c
@@ -229,7 +229,7 @@ static int wireguard_set_interface(NetDev *netdev) {
message = sd_netlink_message_unref(message);
- r = sd_genl_message_new(netdev->manager->genl, SD_GENL_WIREGUARD, WG_CMD_SET_DEVICE, &message);
+ r = sd_genl_message_new(netdev->manager->genl, WG_GENL_NAME, WG_CMD_SET_DEVICE, &message);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m");
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index f687a1a370..b7b536f3b5 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -46,7 +46,6 @@ int main(int argc, char **argv) {
assert_cc(sizeof(sd_lldp_event_t) == sizeof(int64_t));
assert_cc(sizeof(sd_ndisc_event_t) == sizeof(int64_t));
assert_cc(sizeof(sd_dhcp_lease_server_type_t) == sizeof(int64_t));
- assert_cc(sizeof(sd_genl_family_t) == sizeof(int64_t));
return EXIT_SUCCESS;
}
diff --git a/src/shared/wifi-util.c b/src/shared/wifi-util.c
index b05e1aa0df..5891208076 100644
--- a/src/shared/wifi-util.c
+++ b/src/shared/wifi-util.c
@@ -1,17 +1,18 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "log.h"
+#include "string-util.h"
#include "wifi-util.h"
int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftype, char **ssid) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
- sd_genl_family_t family;
+ const char *family;
int r;
assert(genl);
assert(ifindex > 0);
- r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m);
+ r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &m);
if (r < 0)
return log_debug_errno(r, "Failed to create generic netlink message: %m");
@@ -38,11 +39,11 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftyp
if (r < 0)
return log_debug_errno(r, "Failed to get information about wifi interface %d: %m", ifindex);
- r = sd_genl_message_get_family(genl, reply, &family);
+ r = sd_genl_message_get_family_name(genl, reply, &family);
if (r < 0)
return log_debug_errno(r, "Failed to determine genl family: %m");
- if (family != SD_GENL_NL80211) {
- log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family);
+ if (!streq(family, NL80211_GENL_NAME)) {
+ log_debug("Received message of unexpected genl family '%s', ignoring.", family);
goto nodata;
}
@@ -75,14 +76,14 @@ nodata:
int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
- sd_genl_family_t family;
+ const char *family;
int r;
assert(genl);
assert(ifindex > 0);
assert(bssid);
- r = sd_genl_message_new(genl, SD_GENL_NL80211, NL80211_CMD_GET_STATION, &m);
+ r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &m);
if (r < 0)
return log_debug_errno(r, "Failed to create generic netlink message: %m");
@@ -106,11 +107,11 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
if (r < 0)
return log_debug_errno(r, "Failed to get information about wifi station: %m");
- r = sd_genl_message_get_family(genl, reply, &family);
+ r = sd_genl_message_get_family_name(genl, reply, &family);
if (r < 0)
return log_debug_errno(r, "Failed to determine genl family: %m");
- if (family != SD_GENL_NL80211) {
- log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family);
+ if (!streq(family, NL80211_GENL_NAME)) {
+ log_debug("Received message of unexpected genl family '%s', ignoring.", family);
goto nodata;
}
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index c67ea87540..6bb93fdf17 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -34,21 +34,6 @@ typedef struct sd_netlink sd_netlink;
typedef struct sd_netlink_message sd_netlink_message;
typedef struct sd_netlink_slot sd_netlink_slot;
-typedef enum sd_genl_family_t {
- SD_GENL_ERROR,
- SD_GENL_DONE,
- SD_GENL_ID_CTRL,
- SD_GENL_WIREGUARD,
- SD_GENL_FOU,
- SD_GENL_L2TP,
- SD_GENL_MACSEC,
- SD_GENL_NL80211,
- SD_GENL_BATADV,
- _SD_GENL_FAMILY_MAX,
- _SD_GENL_FAMILY_INVALID = -EINVAL,
- _SD_ENUM_FORCE_S64(GENL_FAMILY)
-} sd_genl_family_t;
-
/* callback */
typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *m, void *userdata);
typedef _sd_destroy_t sd_netlink_destroy_t;
@@ -250,8 +235,8 @@ int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m);
/* genl */
int sd_genl_socket_open(sd_netlink **ret);
-int sd_genl_message_new(sd_netlink *genl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret);
-int sd_genl_message_get_family(sd_netlink *genl, sd_netlink_message *m, sd_genl_family_t *ret);
+int sd_genl_message_new(sd_netlink *genl, const char *family_name, uint8_t cmd, sd_netlink_message **ret);
+int sd_genl_message_get_family_name(sd_netlink *genl, sd_netlink_message *m, const char **ret);
/* slot */
sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *slot);