summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYu Watanabe <watanabe.yu+github@gmail.com>2019-07-24 14:46:55 +0900
committerYu Watanabe <watanabe.yu+github@gmail.com>2019-10-15 01:59:06 +0900
commit8d968fdd991d3471aa9b484eac58708786c48d85 (patch)
tree995c8ba42dab376d1d8c9ce1e7bae4989fe7cd6b
parentad932b156c159094148bfbb508641fb818f932f1 (diff)
downloadsystemd-8d968fdd991d3471aa9b484eac58708786c48d85.tar.gz
network: support matching based on wifi SSID
-rw-r--r--man/systemd.network.xml8
-rw-r--r--src/libsystemd-network/network-internal.c7
-rw-r--r--src/libsystemd-network/network-internal.h4
-rw-r--r--src/network/meson.build2
-rw-r--r--src/network/networkd-link.c19
-rw-r--r--src/network/networkd-link.h3
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-network.c8
-rw-r--r--src/network/networkd-network.h3
-rw-r--r--src/network/networkd-wifi.c70
-rw-r--r--src/network/networkd-wifi.h8
-rw-r--r--src/network/test-network.c2
-rw-r--r--src/udev/net/link-config.c4
-rw-r--r--test/fuzz/fuzz-network-parser/directives.network1
14 files changed, 129 insertions, 11 deletions
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
@@ -154,6 +154,14 @@
</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>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..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 <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"
+
+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=