summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2022-02-16 15:42:33 +0200
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2022-02-24 23:04:48 +0200
commit9c4fbbe1b8ab6e2e6206f9fb9fe8bcf4c89aa5ff (patch)
treed85a0c0d21c30750606f34897e7738d25943c65c
parent2c9d3ef6c7f8604e9ba1fad81e0d1f316e2fc7d7 (diff)
downloadNetworkManager-9c4fbbe1b8ab6e2e6206f9fb9fe8bcf4c89aa5ff.tar.gz
rfkill: query the hardware rfkill reason from udev
The kernel may add a reason for hardware rfkill. Make the NetworkManager able eto fetch it and parse it. For now, no action will be taken upon the new reasons. The different reasons that the kernel can expose are either the radio was switched off by a hardware rfkill switch. This reason is adveritsed by bit 0 in the bitmap returned by RFKILL_STATE_REASON udev property. This is the rfkill that existed until now. The new reason is mapped to bit 1 and teaches the user space that the wifi device is currently used by the CSME firmware on the platform. In that case, the NetworkManager can ask CSME (through the iwlmei kernel module) what BSSID the CSME firmware is associated to. Once the NetworkManager gets to the conclusion is has the credentials to connect to that very same AP, it can request the wifi device and the CSME firmware will allow the host to take the ownership on the device. CSME will give 3 seconds to the host to get an IP or it'll take the device back. In order to complete all the process until we get the DHCP ACK within 3 seconds, the NetworkManager will need to optimize the scan and limit the scan to that specific BSSID on that specific channel. All this flow is not implemented yet, but the first step is to identify that the device is not owned by the host.
-rw-r--r--src/core/nm-manager.c5
-rw-r--r--src/core/nm-rfkill-manager.c24
-rw-r--r--src/core/nm-rfkill-manager.h7
3 files changed, 32 insertions, 4 deletions
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index 003552bc47..8a18440ce7 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -2323,6 +2323,11 @@ _rfkill_radio_state_set_from_manager(NMRfkillManager *rfkill_mgr,
rstate->sw_enabled = FALSE;
rstate->hw_enabled = FALSE;
return;
+ case NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER:
+ /* TODO: do something special here */
+ rstate->sw_enabled = FALSE;
+ rstate->hw_enabled = FALSE;
+ return;
}
nm_assert_not_reached();
}
diff --git a/src/core/nm-rfkill-manager.c b/src/core/nm-rfkill-manager.c
index bb6dcfd72c..2315973d85 100644
--- a/src/core/nm-rfkill-manager.c
+++ b/src/core/nm-rfkill-manager.c
@@ -90,6 +90,8 @@ nm_rfkill_state_to_string(NMRfkillState state)
return "soft-blocked";
case NM_RFKILL_STATE_HARD_BLOCKED:
return "hard-blocked";
+ case NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER:
+ return "hard-blocked-os-not-owner";
}
return nm_assert_unreachable_val("unknown");
}
@@ -153,7 +155,7 @@ killswitch_destroy(Killswitch *ks)
}
static NMRfkillState
-sysfs_state_to_nm_state(int sysfs_state)
+sysfs_state_to_nm_state(int sysfs_state, int sysfs_reason)
{
switch (sysfs_state) {
case 0:
@@ -161,6 +163,11 @@ sysfs_state_to_nm_state(int sysfs_state)
case 1:
return NM_RFKILL_STATE_UNBLOCKED;
case 2:
+ /* sysfs reason is a bitmap, in case we have both reasons (SIGNAL and NOT_OWNER), we want
+ * to consider the device as not owned.
+ */
+ if (sysfs_reason & 2)
+ return NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER;
return NM_RFKILL_STATE_HARD_BLOCKED;
default:
nm_log_warn(LOGD_RFKILL, "unhandled rfkill state %d", sysfs_state);
@@ -191,6 +198,7 @@ recheck_killswitches(NMRfkillManager *self)
struct udev_device *device;
NMRfkillState dev_state;
int sysfs_state;
+ int sysfs_reason;
device = udev_device_new_from_subsystem_sysname(nm_udev_client_get_udev(priv->udev_client),
"rfkill",
@@ -203,15 +211,23 @@ recheck_killswitches(NMRfkillManager *self)
G_MININT,
G_MAXINT,
-1);
- dev_state = sysfs_state_to_nm_state(sysfs_state);
+ sysfs_reason = _nm_utils_ascii_str_to_int64(
+ udev_device_get_property_value(device, "RFKILL_STATE_REASON"),
+ 10,
+ G_MININT,
+ G_MAXINT,
+ 1); /* defaults to SIGNAL in case the kernel does not support this */
+
+ dev_state = sysfs_state_to_nm_state(sysfs_state, sysfs_reason);
nm_log_dbg(LOGD_RFKILL,
- "%s rfkill%s switch %s state now %d/%u",
+ "%s rfkill%s switch %s state now %d/%u reason: 0x%x",
nm_rfkill_type_to_string(ks->rtype),
ks->platform ? " platform" : "",
ks->name,
sysfs_state,
- dev_state);
+ dev_state,
+ sysfs_reason);
if (ks->platform == FALSE) {
if (dev_state > poll_states[ks->rtype])
diff --git a/src/core/nm-rfkill-manager.h b/src/core/nm-rfkill-manager.h
index db1385ea6a..a9c723f154 100644
--- a/src/core/nm-rfkill-manager.h
+++ b/src/core/nm-rfkill-manager.h
@@ -11,6 +11,13 @@ typedef enum {
NM_RFKILL_STATE_UNBLOCKED = 0,
NM_RFKILL_STATE_SOFT_BLOCKED = 1,
NM_RFKILL_STATE_HARD_BLOCKED = 2,
+ /* NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER means that the CSME firmware
+ * is currently controlling the device. This feature is implmented on Intel
+ * wifi devices only.
+ * The NetworkManager can get ownership on the device, but it requires to
+ * first ask ownership through the iwlmei kernel module.
+ */
+ NM_RFKILL_STATE_HARD_BLOCKED_OS_NOT_OWNER = 3,
} NMRfkillState;
typedef enum {