diff options
-rw-r--r-- | src/network/meson.build | 2 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 24 | ||||
-rw-r--r-- | src/network/networkd-manager.h | 4 | ||||
-rw-r--r-- | src/network/networkd-wifi.c | 3 | ||||
-rw-r--r-- | src/network/networkd-wiphy.c | 205 | ||||
-rw-r--r-- | src/network/networkd-wiphy.h | 51 |
6 files changed, 289 insertions, 0 deletions
diff --git a/src/network/meson.build b/src/network/meson.build index 70731831e1..1b8aa80cfe 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -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 diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index fab0b4094c..553aa2beb1 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -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"); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 86de529124..fab2cfaf11 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -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; diff --git a/src/network/networkd-wifi.c b/src/network/networkd-wifi.c index 996e600492..13d6734a02 100644 --- a/src/network/networkd-wifi.c +++ b/src/network/networkd-wifi.c @@ -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 index 0000000000..861ebe6b69 --- /dev/null +++ b/src/network/networkd-wiphy.c @@ -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 index 0000000000..072a7e5fdd --- /dev/null +++ b/src/network/networkd-wiphy.h @@ -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__) |