]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: manage WLAN phy
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 14 Feb 2022 17:06:29 +0000 (02:06 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 15 Feb 2022 07:06:43 +0000 (16:06 +0900)
src/network/meson.build
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-wifi.c
src/network/networkd-wiphy.c [new file with mode: 0644]
src/network/networkd-wiphy.h [new file with mode: 0644]

index 70731831e1a196d318b5c2bae27a83622a1b88d5..1b8aa80cfe2dc152c0db0f23f3a2ca7649dbdb49 100644 (file)
@@ -143,6 +143,8 @@ sources = files('''
         networkd-util.h
         networkd-wifi.c
         networkd-wifi.h
+        networkd-wiphy.c
+        networkd-wiphy.h
         tc/cake.c
         tc/cake.h
         tc/codel.c
index fab0b4094c337e50e9b5b3d79ecfaa10f1937140..553aa2beb1eb3835d6bba62df83aa4fe8a94e657 100644 (file)
@@ -42,6 +42,7 @@
 #include "networkd-speed-meter.h"
 #include "networkd-state-file.h"
 #include "networkd-wifi.h"
+#include "networkd-wiphy.h"
 #include "ordered-set.h"
 #include "path-lookup.h"
 #include "path-util.h"
@@ -554,6 +555,9 @@ Manager* manager_free(Manager *m) {
 
         m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
 
+        m->wiphy_by_name = hashmap_free(m->wiphy_by_name);
+        m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free);
+
         ordered_set_free_free(m->address_pools);
 
         hashmap_free(m->route_table_names_by_number);
@@ -793,6 +797,20 @@ static int manager_enumerate_nexthop(Manager *m) {
         return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop);
 }
 
+static int manager_enumerate_nl80211_wiphy(Manager *m) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
+        int r;
+
+        assert(m);
+        assert(m->genl);
+
+        r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_WIPHY, &req);
+        if (r < 0)
+                return r;
+
+        return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_wiphy);
+}
+
 static int manager_enumerate_nl80211_config(Manager *m) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
@@ -878,6 +896,12 @@ int manager_enumerate(Manager *m) {
         else if (r < 0)
                 return log_error_errno(r, "Could not enumerate routing policy rules: %m");
 
+        r = manager_enumerate_nl80211_wiphy(m);
+        if (r == -EOPNOTSUPP)
+                log_debug_errno(r, "Could not enumerate wireless LAN phy, ignoring: %m");
+        else if (r < 0)
+                return log_error_errno(r, "Could not enumerate wireless LAN phy: %m");
+
         r = manager_enumerate_nl80211_config(m);
         if (r == -EOPNOTSUPP)
                 log_debug_errno(r, "Could not enumerate wireless LAN interfaces, ignoring: %m");
index 86de5291244a4ed77e01ad976914dfe526b8eb8a..fab2cfaf111cbc72dce980779dc36559399e03f0 100644 (file)
@@ -84,6 +84,10 @@ struct Manager {
         Hashmap *route_table_numbers_by_name;
         Hashmap *route_table_names_by_number;
 
+        /* Wiphy */
+        Hashmap *wiphy_by_index;
+        Hashmap *wiphy_by_name;
+
         /* For link speed meter */
         bool use_speed_meter;
         sd_event_source *speed_meter_event_source;
index 996e600492f90a4accfc1ebc29b250b7fe9379e3..13d6734a02ef54ba36189f8342c8958cd081d164 100644 (file)
@@ -8,6 +8,7 @@
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-wifi.h"
+#include "networkd-wiphy.h"
 #include "string-util.h"
 #include "wifi-util.h"
 
@@ -72,6 +73,8 @@ int manager_genl_process_nl80211_config(sd_netlink *genl, sd_netlink_message *me
                 log_debug_errno(r, "nl80211: failed to determine genl message command, ignoring: %m");
                 return 0;
         }
+        if (IN_SET(cmd, NL80211_CMD_NEW_WIPHY, NL80211_CMD_DEL_WIPHY))
+                return manager_genl_process_nl80211_wiphy(genl, message, manager);
         if (!IN_SET(cmd, NL80211_CMD_SET_INTERFACE, NL80211_CMD_NEW_INTERFACE, NL80211_CMD_DEL_INTERFACE)) {
                 log_debug("nl80211: ignoring nl80211 %s(%u) message.",
                           strna(nl80211_cmd_to_string(cmd)), cmd);
diff --git a/src/network/networkd-wiphy.c b/src/network/networkd-wiphy.c
new file mode 100644 (file)
index 0000000..861ebe6
--- /dev/null
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <linux/nl80211.h>
+
+#include "device-util.h"
+#include "networkd-manager.h"
+#include "networkd-wiphy.h"
+#include "parse-util.h"
+#include "wifi-util.h"
+
+Wiphy *wiphy_free(Wiphy *w) {
+        if (!w)
+                return NULL;
+
+        if (w->manager) {
+                hashmap_remove_value(w->manager->wiphy_by_index, UINT32_TO_PTR(w->index), w);
+                if (w->name)
+                        hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
+        }
+
+        free(w->name);
+        return mfree(w);
+}
+
+static int wiphy_new(Manager *manager, uint32_t index, Wiphy **ret) {
+        _cleanup_(wiphy_freep) Wiphy *w = NULL;
+        int r;
+
+        assert(manager);
+
+        w = new(Wiphy, 1);
+        if (!w)
+                return -ENOMEM;
+
+        *w = (Wiphy) {
+                .index = index,
+        };
+
+        r = hashmap_ensure_put(&manager->wiphy_by_index, NULL, UINT32_TO_PTR(w->index), w);
+        if (r < 0)
+                return r;
+
+        w->manager = manager;
+
+        if (ret)
+                *ret = w;
+
+        TAKE_PTR(w);
+        return 0;
+}
+
+int wiphy_get_by_index(Manager *manager, uint32_t index, Wiphy **ret) {
+        Wiphy *w;
+
+        assert(manager);
+
+        w = hashmap_get(manager->wiphy_by_index, UINT32_TO_PTR(index));
+        if (!w)
+                return -ENODEV;
+
+        if (ret)
+                *ret = w;
+
+        return 0;
+}
+
+int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret) {
+        Wiphy *w;
+
+        assert(manager);
+        assert(name);
+
+        w = hashmap_get(manager->wiphy_by_name, name);
+        if (!w)
+                return -ENODEV;
+
+        if (ret)
+                *ret = w;
+
+        return 0;
+}
+
+static int wiphy_update_name(Wiphy *w, sd_netlink_message *message) {
+        const char *name;
+        int r;
+
+        assert(w);
+        assert(w->manager);
+        assert(message);
+
+        r = sd_netlink_message_read_string(message, NL80211_ATTR_WIPHY_NAME, &name);
+        if (r == -ENODATA)
+                return 0;
+        if (r < 0)
+                return r;
+
+        if (streq_ptr(w->name, name))
+                return 0;
+
+        if (w->name)
+                hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
+
+        r = free_and_strdup(&w->name, name);
+        if (r < 0)
+                return r;
+
+        return hashmap_ensure_put(&w->manager->wiphy_by_name, &string_hash_ops, w->name, w);
+}
+
+static int wiphy_update(Wiphy *w, sd_netlink_message *message) {
+        int r;
+
+        assert(w);
+        assert(message);
+
+        r = wiphy_update_name(w, message);
+        if (r < 0)
+                return log_wiphy_debug_errno(w, r, "Failed to update wiphy name: %m");
+
+        return 0;
+}
+
+int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *message, Manager *manager) {
+        const char *family;
+        uint32_t index;
+        uint8_t cmd;
+        Wiphy *w = NULL;
+        int r;
+
+        assert(genl);
+        assert(message);
+        assert(manager);
+
+        if (sd_netlink_message_is_error(message)) {
+                r = sd_netlink_message_get_errno(message);
+                if (r < 0)
+                        log_message_warning_errno(message, r, "nl80211: received error message, ignoring");
+
+                return 0;
+        }
+
+        r = sd_genl_message_get_family_name(genl, message, &family);
+        if (r < 0) {
+                log_debug_errno(r, "nl80211: failed to determine genl family, ignoring: %m");
+                return 0;
+        }
+        if (!streq(family, NL80211_GENL_NAME)) {
+                log_debug("nl80211: Received message of unexpected genl family '%s', ignoring.", family);
+                return 0;
+        }
+
+        r = sd_genl_message_get_command(genl, message, &cmd);
+        if (r < 0) {
+                log_debug_errno(r, "nl80211: failed to determine genl message command, ignoring: %m");
+                return 0;
+        }
+
+        r = sd_netlink_message_read_u32(message, NL80211_ATTR_WIPHY, &index);
+        if (r < 0) {
+                log_debug_errno(r, "nl80211: received %s(%u) message without valid index, ignoring: %m",
+                                strna(nl80211_cmd_to_string(cmd)), cmd);
+                return 0;
+        }
+
+        (void) wiphy_get_by_index(manager, index, &w);
+
+        switch (cmd) {
+        case NL80211_CMD_NEW_WIPHY: {
+                bool is_new = !w;
+
+                if (!w) {
+                        r = wiphy_new(manager, index, &w);
+                        if (r < 0) {
+                                log_warning_errno(r, "Failed to allocate wiphy, ignoring: %m");
+                                return 0;
+                        }
+                }
+
+                r = wiphy_update(w, message);
+                if (r < 0) {
+                        log_wiphy_warning_errno(w, r, "Failed to update wiphy, ignoring: %m");
+                        return 0;
+                }
+
+                log_wiphy_debug(w, "Received %s phy.", is_new ? "new" : "updated");
+                break;
+        }
+        case NL80211_CMD_DEL_WIPHY:
+
+                if (!w) {
+                        log_debug("The kernel removes wiphy we do not know, ignoring: %m");
+                        return 0;
+                }
+
+                log_wiphy_debug(w, "Removed.");
+                wiphy_free(w);
+                break;
+
+        default:
+                log_wiphy_debug(w, "nl80211: received %s(%u) message.",
+                                strna(nl80211_cmd_to_string(cmd)), cmd);
+        }
+
+        return 0;
+}
diff --git a/src/network/networkd-wiphy.h b/src/network/networkd-wiphy.h
new file mode 100644 (file)
index 0000000..072a7e5
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <inttypes.h>
+
+#include "sd-device.h"
+
+#include "macro.h"
+
+typedef struct Manager Manager;
+
+typedef struct Wiphy {
+        Manager *manager;
+
+        uint32_t index;
+        char *name;
+} Wiphy;
+
+Wiphy *wiphy_free(Wiphy *w);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Wiphy*, wiphy_free);
+
+int wiphy_get_by_index(Manager *manager, uint32_t index, Wiphy **ret);
+int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret);
+
+int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *message, Manager *manager);
+
+#define log_wiphy_full_errno_zerook(w, level, error, ...)               \
+        ({                                                              \
+                const Wiphy *_w = (w);                                  \
+                log_interface_full_errno_zerook(_w ? _w->name : NULL, level, error, __VA_ARGS__); \
+        })
+
+#define log_wiphy_full_errno(w, level, error, ...)                      \
+        ({                                                              \
+                int _error = (error);                                   \
+                ASSERT_NON_ZERO(_error);                                \
+                log_wiphy_full_errno_zerook(w, level, _error, __VA_ARGS__); \
+        })
+
+#define log_wiphy_full(w, level, ...) (void) log_wiphy_full_errno_zerook(w, level, 0, __VA_ARGS__)
+
+#define log_wiphy_debug(w, ...)   log_wiphy_full(w, LOG_DEBUG, __VA_ARGS__)
+#define log_wiphy_info(w, ...)    log_wiphy_full(w, LOG_INFO, __VA_ARGS__)
+#define log_wiphy_notice(w, ...)  log_wiphy_full(w, LOG_NOTICE, __VA_ARGS__)
+#define log_wiphy_warning(w, ...) log_wiphy_full(w, LOG_WARNING, __VA_ARGS__)
+#define log_wiphy_error(w, ...)   log_wiphy_full(w, LOG_ERR, __VA_ARGS__)
+
+#define log_wiphy_debug_errno(w, error, ...)   log_wiphy_full_errno(w, LOG_DEBUG, error, __VA_ARGS__)
+#define log_wiphy_info_errno(w, error, ...)    log_wiphy_full_errno(w, LOG_INFO, error, __VA_ARGS__)
+#define log_wiphy_notice_errno(w, error, ...)  log_wiphy_full_errno(w, LOG_NOTICE, error, __VA_ARGS__)
+#define log_wiphy_warning_errno(w, error, ...) log_wiphy_full_errno(w, LOG_WARNING, error, __VA_ARGS__)
+#define log_wiphy_error_errno(w, error, ...)   log_wiphy_full_errno(w, LOG_ERR, error, __VA_ARGS__)