]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: support matching based on wifi SSID
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 24 Jul 2019 05:46:55 +0000 (14:46 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 14 Oct 2019 16:59:06 +0000 (01:59 +0900)
14 files changed:
man/systemd.network.xml
src/libsystemd-network/network-internal.c
src/libsystemd-network/network-internal.h
src/network/meson.build
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-wifi.c [new file with mode: 0644]
src/network/networkd-wifi.h [new file with mode: 0644]
src/network/test-network.c
src/udev/net/link-config.c
test/fuzz/fuzz-network-parser/directives.network

index a9a9b13d42e12a09a7c62fafb5a25600fa8fa4a5..03c488d7dcc386f26a04c1eb2dc0e97a4c0b66f9 100644 (file)
             </para>
           </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>
index 1f2e5c7e65eb5c5318c41c1c7ddb1079e747494a..08c756788e1992aab629e9f6f04f8aa66d890dc6 100644 (file)
@@ -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;
 }
 
index 7059c8ae45843ffcc5f444a5ea9e562007578cd0..71aec1a99bb2aae4f2333ae46983a1ed897ad168 100644 (file)
@@ -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);
index c16e095c2c7100727227d2cac745496a6b69d108..fd21008d10fe9ff828b6ddaa76418dc6d5f50196 100644 (file)
@@ -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')
index 328295e98ae09c7440146d1d66847b01dc65aa38..7f00337f137f43c9766a64f1f3948ed5e9109e81 100644 (file)
@@ -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) {
index 02fcb126c32e6bdaf6bb488b7dc99d1a13ccdd9c..fd01387895f30c1dd320e33d19549d7ff40ef807 100644 (file)
@@ -55,6 +55,9 @@ typedef struct Link {
         uint32_t mtu;
         sd_device *sd_device;
 
+        /* wlan */
+        char *ssid;
+
         unsigned flags;
         uint8_t kernel_operstate;
 
index 490a0a38a3b8a5d5d2f2a29a9f28b5444a6e635f..95d3331222385bc4ba530d58e979de5699707261 100644 (file)
@@ -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)
index 326bd3f106e04a3ec8b29384ca261c0ec6584a59..b3bc598c4428d575a9cb8fe36beb173591b5e777 100644 (file)
@@ -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;
index 668cc0d348c6258631f42234843cac21518edd75..883f0fab6ef2d513f94a2ce663d4f934b2dd2871 100644 (file)
@@ -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 (file)
index 0000000..252985d
--- /dev/null
@@ -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 (file)
index 0000000..4789427
--- /dev/null
@@ -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);
index 23fcea666e6eeeb73dd994073c35b8114ff33c82..50b5cc047c8a6747ba2714cb540c14365e0b6d0d 100644 (file)
@@ -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);
 }
 
index cced62cab26d6cf2eb0347b43568486c81df5754..62974b7c9588939f95822b3f42207af336a8b0de 100644 (file)
@@ -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;
 
index bd6a127ac5063a759fe03aa53ceed61f10b3fb0b..8f3153079baff2e295e7041a2d2b2820ece09aca 100644 (file)
@@ -19,6 +19,7 @@ Type=
 Driver=
 Architecture=
 Path=
+SSID=
 Name=
 Property=
 Virtualization=