summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/network/meson.build2
-rw-r--r--src/network/networkd-manager.c24
-rw-r--r--src/network/networkd-manager.h4
-rw-r--r--src/network/networkd-wifi.c3
-rw-r--r--src/network/networkd-wiphy.c205
-rw-r--r--src/network/networkd-wiphy.h51
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__)