summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2019-10-23 14:51:23 +0200
committerGitHub <noreply@github.com>2019-10-23 14:51:23 +0200
commit510c4bb31f030a4a5a0dd7525a2012d55b58fe2a (patch)
tree928c635895cdc41ff5355eb6ed62aebe746f0695
parentc199cc0704271378ea5eafc0bddb6b7453c4e71f (diff)
parent277ba8d1ab968f4c699c623a6bb17bd3b5fd17eb (diff)
downloadsystemd-510c4bb31f030a4a5a0dd7525a2012d55b58fe2a.tar.gz
Merge pull request #13142 from yuwata/network-wifi-ssid-support-nl80211
network: wifi ssid support with nl80211
-rw-r--r--man/systemd.network.xml18
-rw-r--r--src/libsystemd-network/network-internal.c12
-rw-r--r--src/libsystemd-network/network-internal.h6
-rw-r--r--src/libsystemd/meson.build1
-rw-r--r--src/libsystemd/sd-netlink/generic-netlink.c102
-rw-r--r--src/libsystemd/sd-netlink/generic-netlink.h6
-rw-r--r--src/libsystemd/sd-netlink/netlink-internal.h5
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c49
-rw-r--r--src/libsystemd/sd-netlink/netlink-socket.c7
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.c74
-rw-r--r--src/libsystemd/sd-netlink/netlink-types.h3
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c3
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c10
-rw-r--r--src/network/meson.build2
-rw-r--r--src/network/networkd-link.c124
-rw-r--r--src/network/networkd-link.h6
-rw-r--r--src/network/networkd-network-gperf.gperf2
-rw-r--r--src/network/networkd-network.c9
-rw-r--r--src/network/networkd-network.h5
-rw-r--r--src/network/networkd-wifi.c142
-rw-r--r--src/network/networkd-wifi.h8
-rw-r--r--src/network/test-network.c2
-rw-r--r--src/shared/bus-util.c3
-rw-r--r--src/systemd/sd-netlink.h7
-rw-r--r--src/udev/net/link-config.c4
-rw-r--r--test/fuzz/fuzz-network-parser/directives.network2
26 files changed, 542 insertions, 70 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 5d3c9383d9..c0aa807054 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -154,6 +154,24 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>SSID=</varname></term>
+ <listitem>
+ <para>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.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>BSSID=</varname></term>
+ <listitem>
+ <para>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
+ <varname>MACAddress=</varname>. 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.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Host=</varname></term>
<listitem>
<para>Matches against the hostname or machine ID of the host. See
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 1f2e5c7e65..a8cb4ea286 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -142,9 +142,13 @@ bool net_match_config(Set *match_mac,
char * const *match_types,
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 *dev_name,
+ const char *ssid,
+ const struct ether_addr *bssid) {
const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
@@ -178,6 +182,12 @@ 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;
+
+ 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 7059c8ae45..f40ad6b1dd 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -20,9 +20,13 @@ bool net_match_config(Set *match_mac,
char * const *match_type,
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 *dev_name,
+ 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/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 5467f62ffa..ad35b143f8 100644
--- a/src/libsystemd/sd-netlink/generic-netlink.c
+++ b/src/libsystemd/sd-netlink/generic-netlink.c
@@ -1,8 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
#include <linux/genetlink.h>
#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;
@@ -15,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) {
@@ -23,12 +28,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);
@@ -67,21 +72,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)
@@ -95,5 +112,66 @@ 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 == NLMSG_DONE)
+ *ret = SD_GENL_DONE;
+ 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;
+}
+
+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/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 4a366d421f..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 {
@@ -116,8 +119,6 @@ struct netlink_container {
struct sd_netlink_message {
unsigned n_ref;
- sd_netlink *rtnl;
-
int protocol;
struct nlmsghdr *hdr;
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 58ec1efdd4..bfbfcb26b1 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;
@@ -47,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;
@@ -616,6 +615,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;
@@ -997,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);
@@ -1024,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..5c57ccf503 100644
--- a/src/libsystemd/sd-netlink/netlink-types.c
+++ b/src/libsystemd/sd-netlink/netlink-types.c
@@ -20,13 +20,18 @@
#include <linux/if_tunnel.h>
#include <linux/nexthop.h>
#include <linux/l2tp.h>
+#include <linux/nl80211.h>
#include <linux/veth.h>
#include <linux/wireguard.h>
+#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"
@@ -984,24 +989,60 @@ 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_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 */
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_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 */
const NLTypeSystem genl_type_system_root = {
.count = ELEMENTSOF(genl_types),
.types = genl_types,
@@ -1049,6 +1090,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 efc59a0a4b..9bc6f68339 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);
@@ -47,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/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 897a2b2fc9..5fedd3765c 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"
@@ -661,6 +662,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,27 +706,14 @@ 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);
+ free(link->ssid);
(void) unlink(link->state_file);
free(link->state_file);
@@ -2850,6 +2857,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, link->ssid, &link->bssid, &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;
@@ -2875,8 +2954,12 @@ static int link_initialized_and_synced(Link *link) {
return r;
if (!link->network) {
+ r = wifi_get_info(link);
+ if (r < 0)
+ return r;
+
r = network_get(link->manager, link->sd_device, link->ifname,
- &link->mac, &network);
+ &link->mac, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;
@@ -3250,6 +3333,15 @@ static int link_carrier_gained(Link *link) {
assert(link);
+ r = wifi_get_info(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 d6604c9120..8a96da90b2 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -55,6 +55,10 @@ typedef struct Link {
uint32_t mtu;
sd_device *sd_device;
+ /* wlan */
+ char *ssid;
+ struct ether_addr bssid;
+
unsigned flags;
uint8_t kernel_operstate;
@@ -204,6 +208,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, \
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index fb80a47cfd..d4d5743527 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -29,6 +29,8 @@ 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.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 cd63bb5f72..24d6556c76 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,8 @@ 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);
+ set_free_free(network->match_bssid);
condition_free_list(network->conditions);
free(network->description);
@@ -655,7 +657,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, const struct ether_addr *bssid, Network **ret) {
Network *network;
Iterator i;
@@ -665,7 +667,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, 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 691e2b3959..d169481cd8 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -63,6 +63,8 @@ struct Network {
char **match_type;
char **match_name;
char **match_property;
+ char **match_ssid;
+ Set *match_bssid;
LIST_HEAD(Condition, conditions);
char *description;
@@ -286,7 +288,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, 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/networkd-wifi.c b/src/network/networkd-wifi.c
new file mode 100644
index 0000000000..94195d778f
--- /dev/null
+++ b/src/network/networkd-wifi.c
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <net/ethernet.h>
+#include <linux/nl80211.h>
+
+#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"
+
+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;
+ int r;
+
+ 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);
+ return r == -ENODATA ? 0 : 1;
+}
+
+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
new file mode 100644
index 0000000000..57aa153370
--- /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_info(Link *link);
diff --git a/src/network/test-network.c b/src/network/test-network.c
index 23fcea666e..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, &network) == -ENOENT);
+ assert_se(network_get(manager, loopback, "lo", &mac, NULL, NULL, &network) == -ENOENT);
assert_se(!network);
}
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;
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index d5b74e62e1..53ac45775e 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -35,11 +35,14 @@ 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_DONE,
SD_GENL_ID_CTRL,
SD_GENL_WIREGUARD,
SD_GENL_FOU,
SD_GENL_L2TP,
SD_GENL_MACSEC,
+ SD_GENL_NL80211,
} sd_genl_family;
/* callback */
@@ -95,6 +98,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);
@@ -110,7 +114,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);
@@ -201,6 +205,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);
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index cced62cab2..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,
- device, 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 ae8af3aba2..81a96435ca 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -19,6 +19,8 @@ Type=
Driver=
Architecture=
Path=
+SSID=
+BSSID=
Name=
Property=
Virtualization=