From 16a8f172b6ff5499f568ebd890c2e9fb61abc219 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 19 Jul 2019 11:14:51 +0900 Subject: [PATCH 01/15] bus-util: make map_basic handle SD_BUS_TYPE_OBJECT_PATH type --- src/shared/bus-util.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index e9b0b8a99d..50b0742c97 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1103,7 +1103,8 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigne switch (type) { - case SD_BUS_TYPE_STRING: { + case SD_BUS_TYPE_STRING: + case SD_BUS_TYPE_OBJECT_PATH: { const char **p = userdata; const char *s; From 338ff28d5f4cc972eefd6b5f7699e98bb68d8103 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 23 Jul 2019 15:35:29 +0900 Subject: [PATCH 02/15] sd-netlink: add missing license identifier --- src/libsystemd/sd-netlink/generic-netlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c index 5467f62ffa..32af79f6ae 100644 --- a/src/libsystemd/sd-netlink/generic-netlink.c +++ b/src/libsystemd/sd-netlink/generic-netlink.c @@ -1,3 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + #include #include "sd-netlink.h" From ddcda37016f418f0bf26ae4e4f7543671b0aa98e Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 23 Jul 2019 15:38:54 +0900 Subject: [PATCH 03/15] sd-netlink: drop unused variable --- src/libsystemd/sd-netlink/netlink-internal.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 4a366d421f..13e7ab6e17 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -116,8 +116,6 @@ struct netlink_container { struct sd_netlink_message { unsigned n_ref; - sd_netlink *rtnl; - int protocol; struct nlmsghdr *hdr; From 6bf8e24bad8bd001d8587d7922842341c32888c2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 23 Jul 2019 15:47:33 +0900 Subject: [PATCH 04/15] sd-netlink: use structured initializer --- src/libsystemd/sd-netlink/netlink-message.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 58ec1efdd4..e1395c6bde 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -31,13 +31,15 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) { buses and their queued messages. See sd-bus. */ - m = new0(sd_netlink_message, 1); + m = new(sd_netlink_message, 1); if (!m) return -ENOMEM; - m->n_ref = 1; - m->protocol = rtnl->protocol; - m->sealed = false; + *m = (sd_netlink_message) { + .n_ref = 1, + .protocol = rtnl->protocol, + .sealed = false, + }; *ret = m; From 59d4103fd545b23ce97973a1ecd0a1db8bc8fb82 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 23 Sep 2019 03:48:50 +0900 Subject: [PATCH 05/15] sd-netlink: introduce sd_netlink_message_read_string_strdup() --- src/libsystemd/sd-netlink/netlink-message.c | 26 +++++++++++++++++++++ src/systemd/sd-netlink.h | 1 + 2 files changed, 27 insertions(+) diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index e1395c6bde..a30911b404 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -618,6 +618,32 @@ int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t s return r; } +int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data) { + void *attr_data; + char *str; + int r; + + assert_return(m, -EINVAL); + + r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING); + if (r < 0) + return r; + + r = netlink_message_read_internal(m, type, &attr_data, NULL); + if (r < 0) + return r; + + if (data) { + str = strndup(attr_data, r); + if (!str) + return -ENOMEM; + + *data = str; + } + + return 0; +} + int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) { int r; void *attr_data; diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index d5b74e62e1..62c5ef0415 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -95,6 +95,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor int sd_netlink_message_close_container(sd_netlink_message *m); int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data); +int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data); int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data); int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data); int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data); From 2cac03f71d6f0f9a8d50f90d1b9fcb3457bfa6ff Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 23 Jul 2019 15:55:03 +0900 Subject: [PATCH 06/15] sd-netlink: drop unnecessarily exported variables --- src/libsystemd/sd-netlink/netlink-types.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index efc59a0a4b..45a2a383f5 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -36,8 +36,6 @@ struct NLTypeSystemUnion { const NLTypeSystem *type_systems; }; -extern const NLTypeSystem rtnl_type_system_root; -extern const NLTypeSystem genl_type_system_root; extern const NLTypeSystem genl_family_type_system_root; uint16_t type_get_type(const NLType *type); From 4e8f0ef92160267e7d4725735e948258dfb9bbec Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 23 Jul 2019 15:54:06 +0900 Subject: [PATCH 07/15] sd-netlink: save dynamic general netlink message type --- src/libsystemd/meson.build | 1 + src/libsystemd/sd-netlink/generic-netlink.c | 81 +++++++++++++++++--- src/libsystemd/sd-netlink/generic-netlink.h | 6 ++ src/libsystemd/sd-netlink/netlink-internal.h | 3 + src/libsystemd/sd-netlink/netlink-message.c | 13 +--- src/libsystemd/sd-netlink/netlink-socket.c | 7 +- src/libsystemd/sd-netlink/netlink-types.c | 37 ++++++++- src/libsystemd/sd-netlink/netlink-types.h | 1 + src/libsystemd/sd-netlink/sd-netlink.c | 3 + src/libsystemd/sd-netlink/test-netlink.c | 10 +-- src/systemd/sd-netlink.h | 3 +- 11 files changed, 130 insertions(+), 35 deletions(-) create mode 100644 src/libsystemd/sd-netlink/generic-netlink.h diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 77fe6e780f..aa1ed9b7dd 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -71,6 +71,7 @@ libsystemd_sources = files(''' sd-hwdb/hwdb-util.h sd-hwdb/sd-hwdb.c sd-netlink/generic-netlink.c + sd-netlink/generic-netlink.h sd-netlink/netlink-internal.h sd-netlink/netlink-message.c sd-netlink/netlink-slot.c diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c index 32af79f6ae..bfbfb0fd39 100644 --- a/src/libsystemd/sd-netlink/generic-netlink.c +++ b/src/libsystemd/sd-netlink/generic-netlink.c @@ -3,8 +3,10 @@ #include #include "sd-netlink.h" -#include "netlink-internal.h" + #include "alloc-util.h" +#include "generic-netlink.h" +#include "netlink-internal.h" typedef struct { const char* name; @@ -25,12 +27,12 @@ int sd_genl_socket_open(sd_netlink **ret) { static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id); static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) { - int r; - struct genlmsghdr *genl; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; const NLType *genl_cmd_type, *nl_type; const NLTypeSystem *type_system; + struct genlmsghdr *genl; size_t size; - _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); @@ -69,21 +71,33 @@ static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlms } int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) { + uint16_t id; int r; - uint16_t id = GENL_ID_CTRL; - if (family != SD_GENL_ID_CTRL) { - r = lookup_id(nl, family, &id); - if (r < 0) - return r; - } + r = lookup_id(nl, family, &id); + if (r < 0) + return r; return genl_message_new(nl, family, id, cmd, ret); } static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) { - int r; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + uint16_t u; + void *v; + int r; + + if (family == SD_GENL_ID_CTRL) { + *id = GENL_ID_CTRL; + return 0; + } + + v = hashmap_get(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family)); + if (v) { + *id = PTR_TO_UINT(v); + return 0; + } + r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req); if (r < 0) @@ -97,5 +111,48 @@ static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) { if (r < 0) return r; - return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id); + r = sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, &u); + if (r < 0) + return r; + + r = hashmap_ensure_allocated(&nl->genl_family_to_nlmsg_type, NULL); + if (r < 0) + return r; + + r = hashmap_ensure_allocated(&nl->nlmsg_type_to_genl_family, NULL); + if (r < 0) + return r; + + r = hashmap_put(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family), UINT_TO_PTR(u)); + if (r < 0) + return r; + + r = hashmap_put(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(u), INT_TO_PTR(family)); + if (r < 0) + return r; + + *id = u; + return 0; +} + +int nlmsg_type_to_genl_family(sd_netlink *nl, uint16_t type, sd_genl_family *ret) { + void *p; + + assert_return(nl, -EINVAL); + assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); + assert(ret); + + if (type == NLMSG_ERROR) + *ret = SD_GENL_ERROR; + else if (type == GENL_ID_CTRL) + *ret = SD_GENL_ID_CTRL; + else { + p = hashmap_get(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(type)); + if (!p) + return -EOPNOTSUPP; + + *ret = PTR_TO_INT(p); + } + + return 0; } diff --git a/src/libsystemd/sd-netlink/generic-netlink.h b/src/libsystemd/sd-netlink/generic-netlink.h new file mode 100644 index 0000000000..82afe4ee13 --- /dev/null +++ b/src/libsystemd/sd-netlink/generic-netlink.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-netlink.h" + +int nlmsg_type_to_genl_family(sd_netlink *nl, uint16_t type, sd_genl_family *ret); diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 13e7ab6e17..93f495f259 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -98,6 +98,9 @@ struct sd_netlink { sd_event_source *time_event_source; sd_event_source *exit_event_source; sd_event *event; + + Hashmap *genl_family_to_nlmsg_type; + Hashmap *nlmsg_type_to_genl_family; }; struct netlink_attribute { diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index a30911b404..bfbfcb26b1 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -49,15 +49,12 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) { int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; const NLType *nl_type; - const NLTypeSystem *type_system_root; size_t size; int r; assert_return(rtnl, -EINVAL); - type_system_root = type_system_get_root(rtnl->protocol); - - r = type_system_get_type(type_system_root, &nl_type, type); + r = type_system_root_get_type(rtnl, &nl_type, type); if (r < 0) return r; @@ -1025,22 +1022,20 @@ int sd_netlink_message_get_errno(sd_netlink_message *m) { return err->error; } -int sd_netlink_message_rewind(sd_netlink_message *m) { +int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) { const NLType *nl_type; - const NLTypeSystem *type_system_root; uint16_t type; size_t size; unsigned i; int r; assert_return(m, -EINVAL); + assert_return(genl || m->protocol != NETLINK_GENERIC, -EINVAL); /* don't allow appending to message once parsed */ if (!m->sealed) rtnl_message_seal(m); - type_system_root = type_system_get_root(m->protocol); - for (i = 1; i <= m->n_containers; i++) m->containers[i].attributes = mfree(m->containers[i].attributes); @@ -1052,7 +1047,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m) { assert(m->hdr); - r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type); + r = type_system_root_get_type(genl, &nl_type, m->hdr->nlmsg_type); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 98edb7e2ba..7331aa1c19 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -313,14 +313,11 @@ int socket_read_message(sd_netlink *rtnl) { size_t len; int r; unsigned i = 0; - const NLTypeSystem *type_system_root; assert(rtnl); assert(rtnl->rbuffer); assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr)); - type_system_root = type_system_get_root(rtnl->protocol); - /* read nothing, just get the pending message size */ r = socket_recv_message(rtnl->fd, &iov, NULL, true); if (r <= 0) @@ -381,7 +378,7 @@ int socket_read_message(sd_netlink *rtnl) { } /* check that we support this message type */ - r = type_system_get_type(type_system_root, &nl_type, new_msg->nlmsg_type); + r = type_system_root_get_type(rtnl, &nl_type, new_msg->nlmsg_type); if (r < 0) { if (r == -EOPNOTSUPP) log_debug("sd-netlink: ignored message with unknown type: %i", @@ -407,7 +404,7 @@ int socket_read_message(sd_netlink *rtnl) { return -ENOMEM; /* seal and parse the top-level message */ - r = sd_netlink_message_rewind(m); + r = sd_netlink_message_rewind(m, rtnl); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 6db0ffd13f..ae4b6c72f7 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -23,10 +23,14 @@ #include #include +#include "sd-netlink.h" + +#include "generic-netlink.h" +#include "hashmap.h" #include "macro.h" #include "missing.h" +#include "netlink-internal.h" #include "netlink-types.h" -#include "sd-netlink.h" #include "string-table.h" #include "util.h" @@ -992,16 +996,18 @@ static const NLType genl_families[] = { [SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system }, }; +/* Mainly used when sending message */ const NLTypeSystem genl_family_type_system_root = { .count = ELEMENTSOF(genl_families), .types = genl_families, }; static const NLType genl_types[] = { - [NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) }, - [GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) }, + [SD_GENL_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) }, + [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) }, }; +/* Mainly used when message received */ const NLTypeSystem genl_type_system_root = { .count = ELEMENTSOF(genl_types), .types = genl_types, @@ -1049,6 +1055,31 @@ const NLTypeSystem *type_system_get_root(int protocol) { } } +int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type) { + sd_genl_family family; + const NLType *nl_type; + int r; + + if (!nl || nl->protocol != NETLINK_GENERIC) + return type_system_get_type(&rtnl_type_system_root, ret, type); + + r = nlmsg_type_to_genl_family(nl, type, &family); + if (r < 0) + return r; + + if (family >= genl_type_system_root.count) + return -EOPNOTSUPP; + + nl_type = &genl_type_system_root.types[family]; + + if (nl_type->type == NETLINK_TYPE_UNSPEC) + return -EOPNOTSUPP; + + *ret = nl_type; + + return 0; +} + int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) { const NLType *nl_type; diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index 45a2a383f5..9bc6f68339 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -45,6 +45,7 @@ void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **re const NLTypeSystem* type_system_get_root(int protocol); 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 f3366d1bf7..ce2ad3614d 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -178,6 +178,9 @@ static sd_netlink *netlink_free(sd_netlink *rtnl) { hashmap_free(rtnl->broadcast_group_refs); + hashmap_free(rtnl->genl_family_to_nlmsg_type); + hashmap_free(rtnl->nlmsg_type_to_genl_family); + safe_close(rtnl->fd); return mfree(rtnl); } diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index 868fcd0124..379ad3058c 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -26,7 +26,7 @@ static void test_message_link_bridge(sd_netlink *rtnl) { assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0); assert_se(sd_netlink_message_close_container(message) >= 0); - assert_se(sd_netlink_message_rewind(message) >= 0); + assert_se(sd_netlink_message_rewind(message, NULL) >= 0); assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0); assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0); @@ -49,7 +49,7 @@ static void test_link_configure(sd_netlink *rtnl, int ifindex) { assert_se(sd_netlink_message_append_u32(message, IFLA_MTU, mtu) >= 0); assert_se(sd_netlink_call(rtnl, message, 0, NULL) == 1); - assert_se(sd_netlink_message_rewind(message) >= 0); + assert_se(sd_netlink_message_rewind(message, NULL) >= 0); assert_se(sd_netlink_message_read_string(message, IFLA_IFNAME, &name_out) >= 0); assert_se(streq(name, name_out)); @@ -153,7 +153,7 @@ static void test_route(sd_netlink *rtnl) { return; } - assert_se(sd_netlink_message_rewind(req) >= 0); + assert_se(sd_netlink_message_rewind(req, NULL) >= 0); assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0); assert_se(addr_data.s_addr == addr.s_addr); @@ -439,7 +439,7 @@ static void test_container(sd_netlink *rtnl) { assert_se(sd_netlink_message_close_container(m) >= 0); assert_se(sd_netlink_message_close_container(m) == -EINVAL); - assert_se(sd_netlink_message_rewind(m) >= 0); + assert_se(sd_netlink_message_rewind(m, NULL) >= 0); assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0); assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0); @@ -530,7 +530,7 @@ static void test_array(void) { assert_se(sd_netlink_message_close_container(m) >= 0); rtnl_message_seal(m); - assert_se(sd_netlink_message_rewind(m) >= 0); + assert_se(sd_netlink_message_rewind(m, genl) >= 0); assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0); for (unsigned i = 0; i < 10; i++) { diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 62c5ef0415..04bb2e547a 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -35,6 +35,7 @@ typedef struct sd_netlink_message sd_netlink_message; typedef struct sd_netlink_slot sd_netlink_slot; typedef enum sd_gen_family { + SD_GENL_ERROR, SD_GENL_ID_CTRL, SD_GENL_WIREGUARD, SD_GENL_FOU, @@ -111,7 +112,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m); int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type); int sd_netlink_message_cancel_array(sd_netlink_message *m); -int sd_netlink_message_rewind(sd_netlink_message *m); +int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl); sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m); From 2be081ffd6228a0c0f9321c9ce722348c2ef4abd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 23 Jul 2019 18:27:21 +0900 Subject: [PATCH 08/15] sd-netlink: support NLMSG_DONE --- src/libsystemd/sd-netlink/generic-netlink.c | 2 ++ src/libsystemd/sd-netlink/netlink-types.c | 3 ++- src/systemd/sd-netlink.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c index bfbfb0fd39..cfd9b4973d 100644 --- a/src/libsystemd/sd-netlink/generic-netlink.c +++ b/src/libsystemd/sd-netlink/generic-netlink.c @@ -144,6 +144,8 @@ int nlmsg_type_to_genl_family(sd_netlink *nl, uint16_t type, sd_genl_family *ret if (type == NLMSG_ERROR) *ret = SD_GENL_ERROR; + else if (type == NLMSG_DONE) + *ret = SD_GENL_DONE; else if (type == GENL_ID_CTRL) *ret = SD_GENL_ID_CTRL; else { diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index ae4b6c72f7..c9e20d6ed7 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -991,7 +991,7 @@ static const NLTypeSystem genl_macsec_device_type_system = { static const NLType genl_families[] = { [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system }, [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system }, - [SD_GENL_FOU] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_cmds_type_system}, + [SD_GENL_FOU] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_cmds_type_system }, [SD_GENL_L2TP] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_tunnel_session_type_system }, [SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system }, }; @@ -1004,6 +1004,7 @@ const NLTypeSystem genl_family_type_system_root = { static const NLType genl_types[] = { [SD_GENL_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) }, + [SD_GENL_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system }, [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) }, }; diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 04bb2e547a..283c2dd35b 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -36,6 +36,7 @@ typedef struct sd_netlink_slot sd_netlink_slot; typedef enum sd_gen_family { SD_GENL_ERROR, + SD_GENL_DONE, SD_GENL_ID_CTRL, SD_GENL_WIREGUARD, SD_GENL_FOU, From 31e78d1042a39709e54215a511a8d5f47b23a72b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 24 Jul 2019 13:10:12 +0900 Subject: [PATCH 09/15] sd-netlink: introduce sd_genl_message_get_family() --- src/libsystemd/sd-netlink/generic-netlink.c | 16 ++++++++++++++++ src/systemd/sd-netlink.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c index cfd9b4973d..58dda0323d 100644 --- a/src/libsystemd/sd-netlink/generic-netlink.c +++ b/src/libsystemd/sd-netlink/generic-netlink.c @@ -158,3 +158,19 @@ int nlmsg_type_to_genl_family(sd_netlink *nl, uint16_t type, sd_genl_family *ret return 0; } + +int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family *family) { + uint16_t type; + int r; + + assert_return(m, -EINVAL); + assert_return(nl, -EINVAL); + assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL); + assert_return(family, -EINVAL); + + r = sd_netlink_message_get_type(m, &type); + if (r < 0) + return r; + + return nlmsg_type_to_genl_family(nl, type, family); +} diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 283c2dd35b..43a15a98c0 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -204,6 +204,7 @@ int sd_rtnl_message_routing_policy_rule_get_flags(sd_netlink_message *m, unsigne /* genl */ int sd_genl_socket_open(sd_netlink **nl); int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m); +int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family *family); /* slot */ sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *nl); From a1d736e25c747a0a99aea741bc41f16d5840f4b5 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Tue, 23 Jul 2019 15:59:48 +0900 Subject: [PATCH 10/15] sd-netlink: add nl80211 type systems --- src/libsystemd/sd-netlink/generic-netlink.c | 1 + src/libsystemd/sd-netlink/netlink-types.c | 34 +++++++++++++++++++++ src/systemd/sd-netlink.h | 1 + 3 files changed, 36 insertions(+) diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c index 58dda0323d..ad35b143f8 100644 --- a/src/libsystemd/sd-netlink/generic-netlink.c +++ b/src/libsystemd/sd-netlink/generic-netlink.c @@ -19,6 +19,7 @@ static const genl_family genl_families[] = { [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 }, }; int sd_genl_socket_open(sd_netlink **ret) { diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index c9e20d6ed7..5c57ccf503 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -988,12 +989,44 @@ static const NLTypeSystem genl_macsec_device_type_system = { .types = genl_macsec, }; +static const NLType genl_nl80211_types[] = { + [NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 }, + [NL80211_ATTR_MAC] = { .type = NETLINK_TYPE_ETHER_ADDR }, + [NL80211_ATTR_SSID] = { .type = NETLINK_TYPE_STRING }, +}; + +static const NLTypeSystem genl_nl80211_type_system = { + .count = ELEMENTSOF(genl_nl80211_types), + .types = genl_nl80211_types, +}; + +static const NLType genl_nl80211_cmds[] = { + [NL80211_CMD_GET_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_SET_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_NEW_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_DEL_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_GET_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_SET_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_NEW_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_DEL_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_GET_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_SET_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_NEW_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, + [NL80211_CMD_DEL_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system }, +}; + +static const NLTypeSystem genl_nl80211_cmds_type_system = { + .count = ELEMENTSOF(genl_nl80211_cmds), + .types = genl_nl80211_cmds, +}; + static const NLType genl_families[] = { [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system }, [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system }, [SD_GENL_FOU] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_cmds_type_system }, [SD_GENL_L2TP] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_tunnel_session_type_system }, [SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system }, + [SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_cmds_type_system }, }; /* Mainly used when sending message */ @@ -1006,6 +1039,7 @@ static const NLType genl_types[] = { [SD_GENL_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) }, [SD_GENL_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system }, [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) }, + [SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system, .size = sizeof(struct genlmsghdr) }, }; /* Mainly used when message received */ diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 43a15a98c0..53ac45775e 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -42,6 +42,7 @@ typedef enum sd_gen_family { SD_GENL_FOU, SD_GENL_L2TP, SD_GENL_MACSEC, + SD_GENL_NL80211, } sd_genl_family; /* callback */ From 1a6bb31faedf6d6feae2a42a6aa02105181d8aea Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 21 Jun 2019 12:06:56 +0900 Subject: [PATCH 11/15] network: split link_free() into two parts --- src/network/networkd-link.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 897a2b2fc9..6c1cb45492 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -661,6 +661,25 @@ void link_dns_settings_clear(Link *link) { link->dnssec_negative_trust_anchors = set_free_free(link->dnssec_negative_trust_anchors); } +static void link_free_engines(Link *link) { + if (!link) + return; + + link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server); + link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client); + link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); + link->dhcp_routes = set_free(link->dhcp_routes); + + link->lldp = sd_lldp_unref(link->lldp); + + ndisc_flush(link); + + link->ipv4ll = sd_ipv4ll_unref(link->ipv4ll); + link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); + link->ndisc = sd_ndisc_unref(link->ndisc); + link->radv = sd_radv_unref(link->radv); +} + static Link *link_free(Link *link) { Address *address; @@ -686,25 +705,11 @@ static Link *link_free(Link *link) { address_free(address); } - sd_dhcp_server_unref(link->dhcp_server); - sd_dhcp_client_unref(link->dhcp_client); - sd_dhcp_lease_unref(link->dhcp_lease); - set_free(link->dhcp_routes); - link_lldp_emit_stop(link); - + link_free_engines(link); free(link->lease_file); - - sd_lldp_unref(link->lldp); free(link->lldp_file); - ndisc_flush(link); - - sd_ipv4ll_unref(link->ipv4ll); - sd_dhcp6_client_unref(link->dhcp6_client); - sd_ndisc_unref(link->ndisc); - sd_radv_unref(link->radv); - free(link->ifname); free(link->kind); From ad932b156c159094148bfbb508641fb818f932f1 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 4 Jul 2019 13:52:03 +0900 Subject: [PATCH 12/15] network: introduce link_reconfigure() Will be used in later commits. --- src/network/networkd-link.c | 72 +++++++++++++++++++++++++++++++++++++ src/network/networkd-link.h | 2 ++ 2 files changed, 74 insertions(+) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 6c1cb45492..328295e98a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2855,6 +2855,78 @@ static int link_configure_duid(Link *link) { return 0; } +int link_reconfigure(Link *link) { + Network *network; + int r; + + if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_LINGER)) + return 0; + + r = network_get(link->manager, link->sd_device, link->ifname, + &link->mac, &network); + if (r == -ENOENT) { + link_enter_unmanaged(link); + return 0; + } else if (r == 0 && network->unmanaged) { + link_enter_unmanaged(link); + return 0; + } else if (r < 0) + return r; + + if (link->network == network) + return 0; + + log_link_info(link, "Re-configuring with %s", network->filename); + + /* Dropping old .network file */ + r = link_stop_clients(link, false); + if (r < 0) { + link_enter_failed(link); + return r; + } + + if (link_dhcp4_server_enabled(link)) + (void) sd_dhcp_server_stop(link->dhcp_server); + + r = link_drop_config(link); + if (r < 0) + return r; + + if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING)) { + log_link_debug(link, "State is %s, dropping config", link_state_to_string(link->state)); + r = link_drop_foreign_config(link); + if (r < 0) + return r; + } + + link_free_carrier_maps(link); + link_free_engines(link); + link->network = network_unref(link->network); + + /* Then, apply new .network file */ + r = network_apply(network, link); + if (r < 0) + return r; + + r = link_new_carrier_maps(link); + if (r < 0) + return r; + + link_set_state(link, LINK_STATE_INITIALIZED); + + /* link_configure_duid() returns 0 if it requests product UUID. In that case, + * link_configure() is called later asynchronously. */ + r = link_configure_duid(link); + if (r <= 0) + return r; + + r = link_configure(link); + if (r < 0) + return r; + + return 0; +} + static int link_initialized_and_synced(Link *link) { Network *network; int r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index d6604c9120..02fcb126c3 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -204,6 +204,8 @@ uint32_t link_get_ipv6_accept_ra_route_table(Link *link); int link_request_set_routes(Link *link); int link_request_set_nexthop(Link *link); +int link_reconfigure(Link *link); + #define ADDRESS_FMT_VAL(address) \ be32toh((address).s_addr) >> 24, \ (be32toh((address).s_addr) >> 16) & 0xFFu, \ From 8d968fdd991d3471aa9b484eac58708786c48d85 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 24 Jul 2019 14:46:55 +0900 Subject: [PATCH 13/15] network: support matching based on wifi SSID --- man/systemd.network.xml | 8 +++ src/libsystemd-network/network-internal.c | 7 +- src/libsystemd-network/network-internal.h | 4 +- src/network/meson.build | 2 + src/network/networkd-link.c | 19 ++++- src/network/networkd-link.h | 3 + src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 8 ++- src/network/networkd-network.h | 3 +- src/network/networkd-wifi.c | 70 +++++++++++++++++++ src/network/networkd-wifi.h | 8 +++ src/network/test-network.c | 2 +- src/udev/net/link-config.c | 4 +- .../fuzz-network-parser/directives.network | 1 + 14 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 src/network/networkd-wifi.c create mode 100644 src/network/networkd-wifi.h diff --git a/man/systemd.network.xml b/man/systemd.network.xml index a9a9b13d42..03c488d7dc 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -153,6 +153,14 @@ + + SSID= + + A whitespace-separated list of shell-style globs matching the SSID of the currently + connected wireless LAN. If the list is prefixed with a "!", the test is inverted. + + + Host= diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 1f2e5c7e65..08c756788e 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -142,9 +142,11 @@ bool net_match_config(Set *match_mac, char * const *match_types, char * const *match_names, char * const *match_property, + char * const *match_ssid, sd_device *device, const struct ether_addr *dev_mac, - const char *dev_name) { + const char *dev_name, + const char *ssid) { const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str; @@ -178,6 +180,9 @@ bool net_match_config(Set *match_mac, if (!net_condition_test_property(match_property, device)) return false; + if (!net_condition_test_strv(match_ssid, ssid)) + return false; + return true; } diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 7059c8ae45..71aec1a99b 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -20,9 +20,11 @@ bool net_match_config(Set *match_mac, char * const *match_type, char * const *match_name, char * const *match_property, + char * const *match_ssid, sd_device *device, const struct ether_addr *dev_mac, - const char *dev_name); + const char *dev_name, + const char *ssid); CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); diff --git a/src/network/meson.build b/src/network/meson.build index c16e095c2c..fd21008d10 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -103,6 +103,8 @@ sources = files(''' networkd-speed-meter.h networkd-util.c networkd-util.h + networkd-wifi.c + networkd-wifi.h '''.split()) systemd_networkd_sources = files('networkd.c') diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 328295e98a..7f00337f13 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -33,6 +33,7 @@ #include "networkd-neighbor.h" #include "networkd-radv.h" #include "networkd-routing-policy-rule.h" +#include "networkd-wifi.h" #include "set.h" #include "socket-util.h" #include "stdio-util.h" @@ -712,6 +713,7 @@ static Link *link_free(Link *link) { free(link->ifname); free(link->kind); + free(link->ssid); (void) unlink(link->state_file); free(link->state_file); @@ -2863,7 +2865,7 @@ int link_reconfigure(Link *link) { return 0; r = network_get(link->manager, link->sd_device, link->ifname, - &link->mac, &network); + &link->mac, link->ssid, &network); if (r == -ENOENT) { link_enter_unmanaged(link); return 0; @@ -2952,8 +2954,12 @@ static int link_initialized_and_synced(Link *link) { return r; if (!link->network) { + r = wifi_get_ssid(link); + if (r < 0) + return r; + r = network_get(link->manager, link->sd_device, link->ifname, - &link->mac, &network); + &link->mac, link->ssid, &network); if (r == -ENOENT) { link_enter_unmanaged(link); return 0; @@ -3327,6 +3333,15 @@ static int link_carrier_gained(Link *link) { assert(link); + r = wifi_get_ssid(link); + if (r < 0) + return r; + if (r > 0) { + r = link_reconfigure(link); + if (r < 0) + return r; + } + if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) { r = link_acquire_conf(link); if (r < 0) { diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 02fcb126c3..fd01387895 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -55,6 +55,9 @@ typedef struct Link { uint32_t mtu; sd_device *sd_device; + /* wlan */ + char *ssid; + unsigned flags; uint8_t kernel_operstate; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 490a0a38a3..95d3331222 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -29,6 +29,7 @@ Match.MACAddress, config_parse_hwaddrs, Match.Path, config_parse_match_strv, 0, offsetof(Network, match_path) Match.Driver, config_parse_match_strv, 0, offsetof(Network, match_driver) Match.Type, config_parse_match_strv, 0, offsetof(Network, match_type) +Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid) Match.Name, config_parse_match_ifnames, 0, offsetof(Network, match_name) Match.Property, config_parse_match_property, 0, offsetof(Network, match_property) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 326bd3f106..b3bc598c44 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -159,7 +159,7 @@ int network_verify(Network *network) { if (set_isempty(network->match_mac) && strv_isempty(network->match_path) && strv_isempty(network->match_driver) && strv_isempty(network->match_type) && strv_isempty(network->match_name) && strv_isempty(network->match_property) && - !network->conditions) + strv_isempty(network->match_ssid) && !network->conditions) log_warning("%s: No valid settings found in the [Match] section. " "The file will match all interfaces. " "If that is intended, please add Name=* in the [Match] section.", @@ -547,6 +547,7 @@ static Network *network_free(Network *network) { strv_free(network->match_type); strv_free(network->match_name); strv_free(network->match_property); + strv_free(network->match_ssid); condition_free_list(network->conditions); free(network->description); @@ -653,7 +654,7 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) { int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *address, - Network **ret) { + const char *ssid, Network **ret) { Network *network; Iterator i; @@ -663,7 +664,8 @@ int network_get(Manager *manager, sd_device *device, ORDERED_HASHMAP_FOREACH(network, manager->networks, i) if (net_match_config(network->match_mac, network->match_path, network->match_driver, network->match_type, network->match_name, network->match_property, - device, address, ifname)) { + network->match_ssid, + device, address, ifname, ssid)) { if (network->match_name && device) { const char *attr; uint8_t name_assign_type = NET_NAME_UNKNOWN; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 668cc0d348..883f0fab6e 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -63,6 +63,7 @@ struct Network { char **match_type; char **match_name; char **match_property; + char **match_ssid; LIST_HEAD(Condition, conditions); char *description; @@ -285,7 +286,7 @@ int network_load_one(Manager *manager, const char *filename); int network_verify(Network *network); int network_get_by_name(Manager *manager, const char *name, Network **ret); -int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac, Network **ret); +int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac, const char *ssid, Network **ret); int network_apply(Network *network, Link *link); void network_apply_anonymize_if_set(Network *network); diff --git a/src/network/networkd-wifi.c b/src/network/networkd-wifi.c new file mode 100644 index 0000000000..252985db49 --- /dev/null +++ b/src/network/networkd-wifi.c @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include +#include + +#include "sd-bus.h" + +#include "bus-util.h" +#include "netlink-internal.h" +#include "netlink-util.h" +#include "networkd-link.h" +#include "networkd-manager.h" +#include "networkd-wifi.h" +#include "string-util.h" + +int wifi_get_ssid(Link *link) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; + _cleanup_free_ char *ssid = NULL; + sd_genl_family family; + const char *type; + int r; + + if (!link->sd_device) + return 0; + + r = sd_device_get_devtype(link->sd_device, &type); + if (r == -ENOENT) + return 0; + else if (r < 0) + return r; + + if (!streq(type, "wlan")) + return 0; + + r = sd_genl_message_new(link->manager->genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m); + if (r < 0) + return log_link_error_errno(link, r, "Failed to create generic netlink message: %m"); + + r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFINDEX, link->ifindex); + if (r < 0) + return log_link_error_errno(link, r, "Could not append NL80211_ATTR_IFINDEX attribute: %m"); + + r = sd_netlink_call(link->manager->genl, m, 0, &reply); + if (r < 0) + return log_link_error_errno(link, r, "Failed to request information about wifi interface: %m"); + if (!reply) + return 0; + + r = sd_netlink_message_get_errno(reply); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to get information about wifi interface: %m"); + + r = sd_genl_message_get_family(link->manager->genl, reply, &family); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to determine genl family: %m"); + if (family != SD_GENL_NL80211) { + log_link_debug(link, "Received message of unexpected genl family %u, ignoring.", family); + return 0; + } + + r = sd_netlink_message_read_string_strdup(reply, NL80211_ATTR_SSID, &ssid); + if (r < 0 && r != -ENODATA) + return log_link_warning_errno(link, r, "Failed to get NL80211_ATTR_SSID attribute: %m"); + + free_and_replace(link->ssid, ssid); + if (link->ssid) + log_link_info(link, "Connected SSID: %s", link->ssid); + + return r; +} diff --git a/src/network/networkd-wifi.h b/src/network/networkd-wifi.h new file mode 100644 index 0000000000..4789427ba4 --- /dev/null +++ b/src/network/networkd-wifi.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" + +typedef struct Link Link; + +int wifi_get_ssid(Link *link); diff --git a/src/network/test-network.c b/src/network/test-network.c index 23fcea666e..50b5cc047c 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -125,7 +125,7 @@ static void test_network_get(Manager *manager, sd_device *loopback) { /* let's assume that the test machine does not have a .network file that applies to the loopback device... */ - assert_se(network_get(manager, loopback, "lo", &mac, &network) == -ENOENT); + assert_se(network_get(manager, loopback, "lo", &mac, NULL, &network) == -ENOENT); assert_se(!network); } diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index cced62cab2..62974b7c95 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -242,8 +242,8 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) LIST_FOREACH(links, link, ctx->links) { if (net_match_config(link->match_mac, link->match_path, link->match_driver, - link->match_type, link->match_name, link->match_property, - device, NULL, NULL)) { + link->match_type, link->match_name, link->match_property, NULL, + device, NULL, NULL, NULL)) { if (link->match_name && !strv_contains(link->match_name, "*")) { unsigned name_assign_type = NET_NAME_UNKNOWN; diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index bd6a127ac5..8f3153079b 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -19,6 +19,7 @@ Type= Driver= Architecture= Path= +SSID= Name= Property= Virtualization= From 0894cfe41c9edacc560c109f1a115922d0a045f3 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 24 Jul 2019 15:16:26 +0900 Subject: [PATCH 14/15] network: also read BSSID --- src/network/networkd-link.c | 4 +- src/network/networkd-link.h | 1 + src/network/networkd-wifi.c | 106 ++++++++++++++++++++++++++++++------ src/network/networkd-wifi.h | 2 +- 4 files changed, 93 insertions(+), 20 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 7f00337f13..1c0ae0184c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2954,7 +2954,7 @@ static int link_initialized_and_synced(Link *link) { return r; if (!link->network) { - r = wifi_get_ssid(link); + r = wifi_get_info(link); if (r < 0) return r; @@ -3333,7 +3333,7 @@ static int link_carrier_gained(Link *link) { assert(link); - r = wifi_get_ssid(link); + r = wifi_get_info(link); if (r < 0) return r; if (r > 0) { diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index fd01387895..8a96da90b2 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -57,6 +57,7 @@ typedef struct Link { /* wlan */ char *ssid; + struct ether_addr bssid; unsigned flags; uint8_t kernel_operstate; diff --git a/src/network/networkd-wifi.c b/src/network/networkd-wifi.c index 252985db49..94195d778f 100644 --- a/src/network/networkd-wifi.c +++ b/src/network/networkd-wifi.c @@ -13,25 +13,12 @@ #include "networkd-wifi.h" #include "string-util.h" -int wifi_get_ssid(Link *link) { +static int wifi_get_ssid(Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; _cleanup_free_ char *ssid = NULL; sd_genl_family family; - const char *type; int r; - if (!link->sd_device) - return 0; - - r = sd_device_get_devtype(link->sd_device, &type); - if (r == -ENOENT) - return 0; - else if (r < 0) - return r; - - if (!streq(type, "wlan")) - return 0; - r = sd_genl_message_new(link->manager->genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m); if (r < 0) return log_link_error_errno(link, r, "Failed to create generic netlink message: %m"); @@ -63,8 +50,93 @@ int wifi_get_ssid(Link *link) { return log_link_warning_errno(link, r, "Failed to get NL80211_ATTR_SSID attribute: %m"); free_and_replace(link->ssid, ssid); - if (link->ssid) - log_link_info(link, "Connected SSID: %s", link->ssid); + return r == -ENODATA ? 0 : 1; +} - return r; +static int wifi_get_bssid(Link *link) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; + struct ether_addr mac = {}; + sd_genl_family family; + int r; + + assert(link); + assert(link->manager); + assert(link->manager->genl); + + r = sd_genl_message_new(link->manager->genl, SD_GENL_NL80211, NL80211_CMD_GET_STATION, &m); + if (r < 0) + return log_link_error_errno(link, r, "Failed to create generic netlink message: %m"); + + r = sd_netlink_message_set_flags(m, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); + if (r < 0) + return log_link_error_errno(link, r, "Failed to set dump flag: %m"); + + r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFINDEX, link->ifindex); + if (r < 0) + return log_link_error_errno(link, r, "Could not append NL80211_ATTR_IFINDEX attribute: %m"); + + r = sd_netlink_call(link->manager->genl, m, 0, &reply); + if (r < 0) + return log_link_error_errno(link, r, "Failed to request information about wifi station: %m"); + if (!reply) + return 0; + + r = sd_netlink_message_get_errno(reply); + if (r < 0) + return log_link_error_errno(link, r, "Failed to get information about wifi station: %m"); + + r = sd_genl_message_get_family(link->manager->genl, reply, &family); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to determine genl family: %m"); + if (family != SD_GENL_NL80211) { + log_link_debug(link, "Received message of unexpected genl family %u, ignoring.", family); + return 0; + } + + r = sd_netlink_message_read_ether_addr(reply, NL80211_ATTR_MAC, &mac); + if (r < 0 && r != -ENODATA) + return log_link_warning_errno(link, r, "Failed to get NL80211_ATTR_MAC attribute: %m"); + + r = memcmp(&link->bssid, &mac, sizeof(mac)); + if (r == 0) + return 0; + + memcpy(&link->bssid, &mac, sizeof(mac)); + return 1; +} + +int wifi_get_info(Link *link) { + char buf[ETHER_ADDR_TO_STRING_MAX]; + const char *type; + int r, s; + + assert(link); + + if (!link->sd_device) + return 0; + + r = sd_device_get_devtype(link->sd_device, &type); + if (r == -ENOENT) + return 0; + else if (r < 0) + return r; + + if (!streq(type, "wlan")) + return 0; + + r = wifi_get_ssid(link); + if (r < 0) + return r; + + s = wifi_get_bssid(link); + if (s < 0) + return s; + + if (r > 0 || s > 0) { + if (link->ssid) + log_link_info(link, "Connected WiFi access point: %s (%s)", + link->ssid, ether_addr_to_string(&link->bssid, buf)); + return 1; + } + return 0; } diff --git a/src/network/networkd-wifi.h b/src/network/networkd-wifi.h index 4789427ba4..57aa153370 100644 --- a/src/network/networkd-wifi.h +++ b/src/network/networkd-wifi.h @@ -5,4 +5,4 @@ typedef struct Link Link; -int wifi_get_ssid(Link *link); +int wifi_get_info(Link *link); From 277ba8d1ab968f4c699c623a6bb17bd3b5fd17eb Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 24 Jul 2019 15:32:24 +0900 Subject: [PATCH 15/15] network: add support matching based on BSSID= --- man/systemd.network.xml | 10 ++++++++++ src/libsystemd-network/network-internal.c | 7 ++++++- src/libsystemd-network/network-internal.h | 4 +++- src/network/networkd-link.c | 4 ++-- src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 7 ++++--- src/network/networkd-network.h | 4 +++- src/network/test-network.c | 2 +- src/udev/net/link-config.c | 4 ++-- test/fuzz/fuzz-network-parser/directives.network | 1 + 10 files changed, 33 insertions(+), 11 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 03c488d7dc..3863f3d004 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -161,6 +161,16 @@ + + BSSID= + + A whitespace-separated list of hardware address of the currently connected wireless + LAN. Use full colon-, hyphen- or dot-delimited hexadecimal. See the example in + MACAddress=. This option may appear more than one, in which case the + lists are merged. If the empty string is assigned to this option, the list of BSSID defined + prior to this is reset. + + Host= diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 08c756788e..a8cb4ea286 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -143,10 +143,12 @@ bool net_match_config(Set *match_mac, char * const *match_names, char * const *match_property, char * const *match_ssid, + Set *match_bssid, sd_device *device, const struct ether_addr *dev_mac, const char *dev_name, - const char *ssid) { + const char *ssid, + const struct ether_addr *bssid) { const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str; @@ -183,6 +185,9 @@ bool net_match_config(Set *match_mac, if (!net_condition_test_strv(match_ssid, ssid)) return false; + if (match_bssid && (!bssid || !set_contains(match_bssid, bssid))) + return false; + return true; } diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 71aec1a99b..f40ad6b1dd 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -21,10 +21,12 @@ bool net_match_config(Set *match_mac, char * const *match_name, char * const *match_property, char * const *match_ssid, + Set *match_bssid, sd_device *device, const struct ether_addr *dev_mac, const char *dev_name, - const char *ssid); + const char *ssid, + const struct ether_addr *bssid); CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 1c0ae0184c..5fedd3765c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -2865,7 +2865,7 @@ int link_reconfigure(Link *link) { return 0; r = network_get(link->manager, link->sd_device, link->ifname, - &link->mac, link->ssid, &network); + &link->mac, link->ssid, &link->bssid, &network); if (r == -ENOENT) { link_enter_unmanaged(link); return 0; @@ -2959,7 +2959,7 @@ static int link_initialized_and_synced(Link *link) { return r; r = network_get(link->manager, link->sd_device, link->ifname, - &link->mac, link->ssid, &network); + &link->mac, link->ssid, &link->bssid, &network); if (r == -ENOENT) { link_enter_unmanaged(link); return 0; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 95d3331222..832303aaa7 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -30,6 +30,7 @@ Match.Path, config_parse_match_strv, Match.Driver, config_parse_match_strv, 0, offsetof(Network, match_driver) Match.Type, config_parse_match_strv, 0, offsetof(Network, match_type) Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid) +Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid) Match.Name, config_parse_match_ifnames, 0, offsetof(Network, match_name) Match.Property, config_parse_match_property, 0, offsetof(Network, match_property) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index b3bc598c44..7a2ee5ff85 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -548,6 +548,7 @@ static Network *network_free(Network *network) { strv_free(network->match_name); strv_free(network->match_property); strv_free(network->match_ssid); + set_free_free(network->match_bssid); condition_free_list(network->conditions); free(network->description); @@ -654,7 +655,7 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) { int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *address, - const char *ssid, Network **ret) { + const char *ssid, const struct ether_addr *bssid, Network **ret) { Network *network; Iterator i; @@ -664,8 +665,8 @@ int network_get(Manager *manager, sd_device *device, ORDERED_HASHMAP_FOREACH(network, manager->networks, i) if (net_match_config(network->match_mac, network->match_path, network->match_driver, network->match_type, network->match_name, network->match_property, - network->match_ssid, - device, address, ifname, ssid)) { + network->match_ssid, network->match_bssid, + device, address, ifname, ssid, bssid)) { if (network->match_name && device) { const char *attr; uint8_t name_assign_type = NET_NAME_UNKNOWN; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 883f0fab6e..fd98d88d6a 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -64,6 +64,7 @@ struct Network { char **match_name; char **match_property; char **match_ssid; + Set *match_bssid; LIST_HEAD(Condition, conditions); char *description; @@ -286,7 +287,8 @@ int network_load_one(Manager *manager, const char *filename); int network_verify(Network *network); int network_get_by_name(Manager *manager, const char *name, Network **ret); -int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac, const char *ssid, Network **ret); +int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac, + const char *ssid, const struct ether_addr *bssid, Network **ret); int network_apply(Network *network, Link *link); void network_apply_anonymize_if_set(Network *network); diff --git a/src/network/test-network.c b/src/network/test-network.c index 50b5cc047c..130adcbca8 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -125,7 +125,7 @@ static void test_network_get(Manager *manager, sd_device *loopback) { /* let's assume that the test machine does not have a .network file that applies to the loopback device... */ - assert_se(network_get(manager, loopback, "lo", &mac, NULL, &network) == -ENOENT); + assert_se(network_get(manager, loopback, "lo", &mac, NULL, NULL, &network) == -ENOENT); assert_se(!network); } diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 62974b7c95..b84caaf459 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -242,8 +242,8 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) LIST_FOREACH(links, link, ctx->links) { if (net_match_config(link->match_mac, link->match_path, link->match_driver, - link->match_type, link->match_name, link->match_property, NULL, - device, NULL, NULL, NULL)) { + link->match_type, link->match_name, link->match_property, NULL, NULL, + device, NULL, NULL, NULL, NULL)) { if (link->match_name && !strv_contains(link->match_name, "*")) { unsigned name_assign_type = NET_NAME_UNKNOWN; diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index 8f3153079b..22fe2b4e33 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -20,6 +20,7 @@ Driver= Architecture= Path= SSID= +BSSID= Name= Property= Virtualization=