network: do not try to bring up wifi interface if rfkill is active
This fixes the following error: --- systemd-networkd[465]: wlan0: Could not bring up interface: Operation not possible due to RF-kill --- Fixes #23649.
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-queue.h"
|
||||
#include "networkd-setlink.h"
|
||||
#include "networkd-wiphy.h"
|
||||
|
||||
static int get_link_default_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||
return link_getlink_handler_internal(rtnl, m, link, "Failed to sync link information");
|
||||
@@ -998,7 +999,7 @@ static int link_up_or_down(Link *link, bool up, Request *req) {
|
||||
return request_call_netlink_async(link->manager->rtnl, m, req);
|
||||
}
|
||||
|
||||
static bool link_is_ready_to_activate(Link *link) {
|
||||
static bool link_is_ready_to_activate(Link *link, bool up) {
|
||||
assert(link);
|
||||
|
||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
@@ -1007,6 +1008,9 @@ static bool link_is_ready_to_activate(Link *link) {
|
||||
if (link->set_link_messages > 0)
|
||||
return false;
|
||||
|
||||
if (up && link_rfkilled(link) > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1017,7 +1021,7 @@ static int link_process_activation(Request *req, Link *link, void *userdata) {
|
||||
assert(req);
|
||||
assert(link);
|
||||
|
||||
if (!link_is_ready_to_activate(link))
|
||||
if (!link_is_ready_to_activate(link, up))
|
||||
return 0;
|
||||
|
||||
r = link_up_or_down(link, up, req);
|
||||
@@ -1097,6 +1101,9 @@ static bool link_is_ready_to_bring_up_or_down(Link *link, bool up) {
|
||||
if (!link->activated)
|
||||
return false;
|
||||
|
||||
if (up && link_rfkilled(link) > 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <net/if_arp.h>
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include "device-private.h"
|
||||
@@ -103,6 +104,129 @@ int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_get_wiphy(Link *link, Wiphy **ret) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *phy = NULL;
|
||||
const char *s;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
if (link->iftype != ARPHRD_ETHER)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!link->dev)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = sd_device_get_devtype(link->dev, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!streq_ptr(s, "wlan"))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = sd_device_get_syspath(link->dev, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
s = strjoina(s, "/phy80211");
|
||||
r = sd_device_new_from_syspath(&phy, s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_get_sysname(phy, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* TODO:
|
||||
* Maybe, it is better to cache the found Wiphy object in the Link object.
|
||||
* To support that, we need to investigate what happens when the _phy_ is renamed. */
|
||||
|
||||
return wiphy_get_by_name(link->manager, s, ret);
|
||||
}
|
||||
|
||||
static int rfkill_get_state(sd_device *dev) {
|
||||
int r;
|
||||
|
||||
assert(dev);
|
||||
|
||||
/* The previous values may be outdated. Let's clear cache and re-read the values. */
|
||||
device_clear_sysattr_cache(dev);
|
||||
|
||||
r = device_get_sysattr_bool(dev, "soft");
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r > 0)
|
||||
return RFKILL_SOFT;
|
||||
|
||||
r = device_get_sysattr_bool(dev, "hard");
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r > 0)
|
||||
return RFKILL_HARD;
|
||||
|
||||
return RFKILL_UNBLOCKED;
|
||||
}
|
||||
|
||||
static int wiphy_rfkilled(Wiphy *w) {
|
||||
int r;
|
||||
|
||||
assert(w);
|
||||
|
||||
if (!udev_available()) {
|
||||
if (w->rfkill_state != RFKILL_UNBLOCKED) {
|
||||
log_wiphy_debug(w, "Running in container, assuming the radio transmitter is unblocked.");
|
||||
w->rfkill_state = RFKILL_UNBLOCKED; /* To suppress the above log message, cache the state. */
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!w->rfkill) {
|
||||
if (w->rfkill_state != RFKILL_UNBLOCKED) {
|
||||
log_wiphy_debug(w, "No rfkill device found, assuming the radio transmitter is unblocked.");
|
||||
w->rfkill_state = RFKILL_UNBLOCKED; /* To suppress the above log message, cache the state. */
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
r = rfkill_get_state(w->rfkill);
|
||||
if (r < 0)
|
||||
return log_wiphy_debug_errno(w, r, "Could not get rfkill state: %m");
|
||||
|
||||
if (w->rfkill_state != r)
|
||||
switch (r) {
|
||||
case RFKILL_UNBLOCKED:
|
||||
log_wiphy_debug(w, "The radio transmitter is unblocked.");
|
||||
break;
|
||||
case RFKILL_SOFT:
|
||||
log_wiphy_debug(w, "The radio transmitter is turned off by software.");
|
||||
break;
|
||||
case RFKILL_HARD:
|
||||
log_wiphy_debug(w, "The radio transmitter is forced off by something outside of the driver's control.");
|
||||
break;
|
||||
default:
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
w->rfkill_state = r; /* Cache the state to suppress the above log messages. */
|
||||
return r != RFKILL_UNBLOCKED;
|
||||
}
|
||||
|
||||
int link_rfkilled(Link *link) {
|
||||
Wiphy *w;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
r = link_get_wiphy(link, &w);
|
||||
if (IN_SET(r, -EOPNOTSUPP, -ENODEV))
|
||||
return false; /* Typically, non-wifi interface or running in container */
|
||||
if (r < 0)
|
||||
return log_link_debug_errno(link, r, "Could not get phy: %m");
|
||||
|
||||
return wiphy_rfkilled(w);
|
||||
}
|
||||
|
||||
static int wiphy_update_name(Wiphy *w, sd_netlink_message *message) {
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
@@ -7,8 +7,19 @@
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Manager Manager;
|
||||
|
||||
/* The following values are different from the ones defined in linux/rfkill.h. */
|
||||
typedef enum RFKillState {
|
||||
RFKILL_UNKNOWN,
|
||||
RFKILL_UNBLOCKED,
|
||||
RFKILL_SOFT,
|
||||
RFKILL_HARD,
|
||||
_RFKILL_STATE_MAX,
|
||||
_RFKILL_STATE_INVALID = -EINVAL,
|
||||
} RFKillState;
|
||||
|
||||
typedef struct Wiphy {
|
||||
Manager *manager;
|
||||
|
||||
@@ -17,6 +28,7 @@ typedef struct Wiphy {
|
||||
|
||||
sd_device *dev;
|
||||
sd_device *rfkill;
|
||||
RFKillState rfkill_state;
|
||||
} Wiphy;
|
||||
|
||||
Wiphy *wiphy_free(Wiphy *w);
|
||||
@@ -25,6 +37,8 @@ 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 link_rfkilled(Link *link);
|
||||
|
||||
int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *message, Manager *manager);
|
||||
int manager_udev_process_wiphy(Manager *m, sd_device *device, sd_device_action_t action);
|
||||
int manager_udev_process_rfkill(Manager *m, sd_device *device, sd_device_action_t action);
|
||||
|
||||
Reference in New Issue
Block a user