fix(network): detect ethernet cable unplug again (carrier/operstate)

PR #4190 (merged as 93d85a0) reworked getNetworkState() so the rfkill
"disabled" state is evaluated whenever the module has no carrier. Because
the module always watches an RFKILL_TYPE_WLAN switch, a wired ethernet
module whose cable is unplugged (carrier lost) would return "disabled"
instead of "disconnected" whenever the system's WLAN radio happened to be
rfkill-blocked. With no format-disabled configured, that state falls back
to plain "format", so the interface kept looking connected after unplug.

rfkill only concerns wireless radios, so only honor it when there is no
interface at all or the current interface is actually wireless (detected
via /sys/class/net/<if>/phy80211 or /wireless). A wired interface that
lost its carrier now correctly reports "disconnected", while wifi rfkill
display from #4190 is preserved.

Fixes #4364.
This commit is contained in:
Alex
2026-07-04 13:43:01 +02:00
parent b0b46ec039
commit faf6a62bcf
2 changed files with 23 additions and 1 deletions
+22 -1
View File
@@ -8,6 +8,7 @@
#include <cassert>
#include <cstring>
#include <filesystem>
#include <fstream>
#include <optional>
#include <sstream>
@@ -288,6 +289,19 @@ void waybar::modules::Network::worker() {
};
}
bool waybar::modules::Network::isWireless() const {
// The rfkill switch we monitor (and thus the "disabled" state) only applies
// to wireless radios. An interface is wireless if the kernel exposes an
// 802.11 phy (cfg80211/mac80211) or a legacy "wireless" node for it in sysfs.
if (ifname_.empty()) {
return false;
}
const auto base = "/sys/class/net/" + ifname_;
std::error_code ec;
return std::filesystem::exists(base + "/phy80211", ec) ||
std::filesystem::exists(base + "/wireless", ec);
}
const std::string waybar::modules::Network::getNetworkState() const {
if (ifid_ == -1 || !carrier_) {
#ifdef WANT_RFKILL
@@ -295,7 +309,14 @@ const std::string waybar::modules::Network::getNetworkState() const {
if (config_["rfkill"].isBool()) {
display_rfkill = config_["rfkill"].asBool();
}
if (rfkill_.getState() && display_rfkill) return "disabled";
// The rfkill switch is for wireless (WLAN) radios only, so it must not mask
// a wired interface that merely lost its carrier (e.g. an unplugged ethernet
// cable): such an interface has to report "disconnected", not "disabled",
// otherwise cable-unplug detection breaks on ethernet modules (#4364).
// Only honor rfkill when there is no interface or the interface is wireless.
if (rfkill_.getState() && display_rfkill && (ifname_.empty() || isWireless())) {
return "disabled";
}
#endif
return "disconnected";
}