From 8d968fdd991d3471aa9b484eac58708786c48d85 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Wed, 24 Jul 2019 14:46:55 +0900 Subject: [PATCH] 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 +- test/fuzz/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 a9a9b13..03c488d 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -154,6 +154,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= 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 1f2e5c7..08c7567 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 7059c8a..71aec1a 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 c16e095..fd21008 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 328295e..7f00337 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 02fcb12..fd01387 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 490a0a3..95d3331 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 326bd3f..b3bc598 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 668cc0d..883f0fa 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 0000000..252985d --- /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 0000000..4789427 --- /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 23fcea6..50b5cc0 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 cced62c..62974b7 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 bd6a127..8f31530 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= -- 2.7.4