#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");
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))
if (link->set_link_messages > 0)
return false;
+ if (up && link_rfkilled(link) > 0)
+ return false;
+
return true;
}
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);
if (!link->activated)
return false;
+ if (up && link_rfkilled(link) > 0)
+ return false;
+
return true;
}
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#include <net/if_arp.h>
#include <linux/nl80211.h>
#include "device-private.h"
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;
#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;
sd_device *dev;
sd_device *rfkill;
+ RFKillState rfkill_state;
} Wiphy;
Wiphy *wiphy_free(Wiphy *w);
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);