core/rfkill: merge branch 'th/rfkill-cleanup'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1079
This commit is contained in:
Thomas Haller 2022-02-08 18:59:06 +01:00
commit 60153308fe
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
10 changed files with 417 additions and 408 deletions

View file

@ -361,7 +361,6 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDevice,
PROP_FIRMWARE_MISSING,
PROP_NM_PLUGIN_MISSING,
PROP_TYPE_DESC,
PROP_RFKILL_TYPE,
PROP_IFINDEX,
PROP_AVAILABLE_CONNECTIONS,
PROP_PHYSICAL_PORT_ID,
@ -473,7 +472,6 @@ typedef struct _NMDevicePrivate {
char *driver;
char *driver_version;
char *firmware_version;
RfKillType rfkill_type;
bool firmware_missing : 1;
bool nm_plugin_missing : 1;
bool
@ -5149,12 +5147,17 @@ nm_device_get_applied_setting(NMDevice *self, GType setting_type)
return connection ? nm_connection_get_setting(connection, setting_type) : NULL;
}
RfKillType
NMRfkillType
nm_device_get_rfkill_type(NMDevice *self)
{
NMRfkillType t;
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
return NM_DEVICE_GET_PRIVATE(self)->rfkill_type;
t = NM_DEVICE_GET_CLASS(self)->rfkill_type;
nm_assert(NM_IN_SET(t, NM_RFKILL_TYPE_UNKNOWN, NM_RFKILL_TYPE_WLAN, NM_RFKILL_TYPE_WWAN));
return t;
}
static const char *
@ -16987,9 +16990,6 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
case PROP_TYPE_DESC:
g_value_set_string(value, priv->type_desc);
break;
case PROP_RFKILL_TYPE:
g_value_set_uint(value, priv->rfkill_type);
break;
case PROP_AVAILABLE_CONNECTIONS:
nm_dbus_utils_g_value_set_object_path_from_hash(value, priv->available_connections, TRUE);
break;
@ -17125,10 +17125,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
/* construct-only */
priv->type_desc = g_value_dup_string(value);
break;
case PROP_RFKILL_TYPE:
/* construct-only */
priv->rfkill_type = g_value_get_uint(value);
break;
case PROP_PERM_HW_ADDRESS:
/* construct-only */
priv->hw_addr_perm = g_value_dup_string(value);
@ -17178,7 +17174,6 @@ nm_device_init(NMDevice *self)
priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED;
priv->state = NM_DEVICE_STATE_UNMANAGED;
priv->state_reason = NM_DEVICE_STATE_REASON_NONE;
priv->rfkill_type = RFKILL_TYPE_UNKNOWN;
priv->unmanaged_flags = NM_UNMANAGED_PLATFORM_INIT;
priv->unmanaged_mask = priv->unmanaged_flags;
priv->available_connections = g_hash_table_new_full(nm_direct_hash, NULL, g_object_unref, NULL);
@ -17581,6 +17576,8 @@ nm_device_class_init(NMDeviceClass *klass)
klass->reapply_connection = reapply_connection;
klass->set_platform_mtu = set_platform_mtu;
klass->rfkill_type = NM_RFKILL_TYPE_UNKNOWN;
obj_properties[PROP_UDI] =
g_param_spec_string(NM_DEVICE_UDI,
"",
@ -17738,14 +17735,6 @@ nm_device_class_init(NMDeviceClass *klass)
"",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
obj_properties[PROP_RFKILL_TYPE] =
g_param_spec_uint(NM_DEVICE_RFKILL_TYPE,
"",
"",
RFKILL_TYPE_WLAN,
RFKILL_TYPE_MAX,
RFKILL_TYPE_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
obj_properties[PROP_IFINDEX] = g_param_spec_int(NM_DEVICE_IFINDEX,
"",
"",

View file

@ -65,7 +65,6 @@
#define NM_DEVICE_SLAVES "slaves" /* partially internal */
#define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */
#define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */
#define NM_DEVICE_IFINDEX "ifindex" /* Internal only */
#define NM_DEVICE_MASTER "master" /* Internal only */
#define NM_DEVICE_HAS_PENDING_ACTION "has-pending-action" /* Internal only */
@ -208,6 +207,8 @@ typedef struct _NMDeviceClass {
bool can_reapply_change_ovs_external_ids : 1;
NMRfkillType rfkill_type : 4;
void (*state_changed)(NMDevice *device,
NMDeviceState new_state,
NMDeviceState old_state,
@ -409,7 +410,6 @@ typedef struct _NMDeviceClass {
gboolean (*set_platform_mtu)(NMDevice *self, guint32 mtu);
const char *(*get_dhcp_anycast_address)(NMDevice *self);
} NMDeviceClass;
GType nm_device_get_type(void);
@ -535,7 +535,7 @@ gboolean nm_device_get_enabled(NMDevice *device);
void nm_device_set_enabled(NMDevice *device, gboolean enabled);
RfKillType nm_device_get_rfkill_type(NMDevice *device);
NMRfkillType nm_device_get_rfkill_type(NMDevice *device);
/* IPv6 prefix delegation */

View file

@ -1196,8 +1196,6 @@ nm_device_iwd_p2p_new(GDBusObject *dbus_obj)
NM_DEVICE_TYPE_WIFI_P2P,
NM_DEVICE_LINK_TYPE,
NM_LINK_TYPE_WIFI,
NM_DEVICE_RFKILL_TYPE,
RFKILL_TYPE_WLAN,
NULL);
if (!self || !nm_device_iwd_p2p_set_dbus_obj(self, dbus_obj))
@ -1252,6 +1250,8 @@ nm_device_iwd_p2p_class_init(NMDeviceIwdP2PClass *klass)
device_class->state_changed = device_state_changed;
device_class->rfkill_type = NM_RFKILL_TYPE_WLAN;
obj_properties[PROP_PEERS] = g_param_spec_boxed(NM_DEVICE_IWD_P2P_PEERS,
"",
"",

View file

@ -3426,8 +3426,6 @@ nm_device_iwd_new(const char *iface)
NM_DEVICE_TYPE_WIFI,
NM_DEVICE_LINK_TYPE,
NM_LINK_TYPE_WIFI,
NM_DEVICE_RFKILL_TYPE,
RFKILL_TYPE_WLAN,
NULL);
}
@ -3490,6 +3488,8 @@ nm_device_iwd_class_init(NMDeviceIwdClass *klass)
device_class->state_changed = device_state_changed;
device_class->rfkill_type = NM_RFKILL_TYPE_WLAN;
obj_properties[PROP_MODE] = g_param_spec_uint(NM_DEVICE_IWD_MODE,
"",
"",

View file

@ -1229,8 +1229,6 @@ nm_device_wifi_p2p_new(const char *iface)
NM_DEVICE_TYPE_WIFI_P2P,
NM_DEVICE_LINK_TYPE,
NM_LINK_TYPE_WIFI,
NM_DEVICE_RFKILL_TYPE,
RFKILL_TYPE_WLAN,
NULL);
}
@ -1293,6 +1291,8 @@ nm_device_wifi_p2p_class_init(NMDeviceWifiP2PClass *klass)
device_class->state_changed = device_state_changed;
device_class->rfkill_type = NM_RFKILL_TYPE_WLAN;
obj_properties[PROP_PEERS] = g_param_spec_boxed(NM_DEVICE_WIFI_P2P_PEERS,
"",
"",

View file

@ -3663,8 +3663,6 @@ nm_device_wifi_new(const char *iface, _NMDeviceWifiCapabilities capabilities)
NM_DEVICE_TYPE_WIFI,
NM_DEVICE_LINK_TYPE,
NM_LINK_TYPE_WIFI,
NM_DEVICE_RFKILL_TYPE,
RFKILL_TYPE_WLAN,
NM_DEVICE_WIFI_CAPABILITIES,
(guint) capabilities,
NULL);
@ -3756,6 +3754,8 @@ nm_device_wifi_class_init(NMDeviceWifiClass *klass)
device_class->state_changed = device_state_changed;
device_class->rfkill_type = NM_RFKILL_TYPE_WLAN;
obj_properties[PROP_MODE] = g_param_spec_uint(NM_DEVICE_WIFI_MODE,
"",
"",

View file

@ -757,8 +757,6 @@ nm_device_modem_new(NMModem *modem)
"Broadband",
NM_DEVICE_DEVICE_TYPE,
NM_DEVICE_TYPE_MODEM,
NM_DEVICE_RFKILL_TYPE,
RFKILL_TYPE_WWAN,
NM_DEVICE_MODEM_MODEM,
modem,
NM_DEVICE_MODEM_CAPABILITIES,
@ -840,6 +838,8 @@ nm_device_modem_class_init(NMDeviceModemClass *klass)
device_class->state_changed = device_state_changed;
device_class->rfkill_type = NM_RFKILL_TYPE_WWAN;
obj_properties[PROP_MODEM] =
g_param_spec_object(NM_DEVICE_MODEM_MODEM,
"",

View file

@ -54,15 +54,16 @@
/*****************************************************************************/
typedef struct {
gboolean user_enabled;
gboolean sw_enabled;
gboolean hw_enabled;
RfKillType rtype;
guint prop_id;
guint hw_prop_id;
NMConfigRunStatePropertyType key;
const char *desc;
const char *prop;
const char *hw_prop;
} RadioState;
} RfkillTypeDesc;
typedef struct {
bool user_enabled : 1;
bool sw_enabled : 1;
bool hw_enabled : 1;
} RfkillRadioState;
typedef enum {
ASYNC_OP_TYPE_AC_AUTH_ACTIVATE_INTERNAL,
@ -169,7 +170,8 @@ typedef struct {
NMSettings *settings;
RadioState radio_states[RFKILL_TYPE_MAX];
RfkillRadioState radio_states[NM_RFKILL_TYPE_MAX];
NMVpnManager *vpn_manager;
NMSleepMonitor *sleep_monitor;
@ -2276,11 +2278,24 @@ _static_hostname_changed_cb(NMHostnameManager *hostname_manager, GParamSpec *psp
}
/*****************************************************************************/
/* General NMManager stuff */
/*****************************************************************************/
static const RfkillTypeDesc _rfkill_type_desc[NM_RFKILL_TYPE_MAX] = {
[NM_RFKILL_TYPE_WLAN] =
{
.prop_id = PROP_WIRELESS_ENABLED,
.hw_prop_id = PROP_WIRELESS_HARDWARE_ENABLED,
.key = NM_CONFIG_STATE_PROPERTY_WIFI_ENABLED,
},
[NM_RFKILL_TYPE_WWAN] =
{
.prop_id = PROP_WWAN_ENABLED,
.hw_prop_id = PROP_WWAN_HARDWARE_ENABLED,
.key = NM_CONFIG_STATE_PROPERTY_WWAN_ENABLED,
},
};
static gboolean
radio_enabled_for_rstate(RadioState *rstate, gboolean check_changeable)
_rfkill_radio_state_get_enabled(const RfkillRadioState *rstate, gboolean check_changeable)
{
gboolean enabled;
@ -2290,25 +2305,45 @@ radio_enabled_for_rstate(RadioState *rstate, gboolean check_changeable)
return enabled;
}
static void
_rfkill_radio_state_set_from_manager(NMRfkillManager *rfkill_mgr,
NMRfkillType rtype,
RfkillRadioState *rstate)
{
switch (nm_rfkill_manager_get_rfkill_state(rfkill_mgr, rtype)) {
case NM_RFKILL_STATE_UNBLOCKED:
rstate->sw_enabled = TRUE;
rstate->hw_enabled = TRUE;
return;
case NM_RFKILL_STATE_SOFT_BLOCKED:
rstate->sw_enabled = FALSE;
rstate->hw_enabled = TRUE;
return;
case NM_RFKILL_STATE_HARD_BLOCKED:
rstate->sw_enabled = FALSE;
rstate->hw_enabled = FALSE;
return;
}
nm_assert_not_reached();
}
static gboolean
radio_enabled_for_type(NMManager *self, RfKillType rtype, gboolean check_changeable)
_rfkill_radio_state_get(NMManager *self, NMRfkillType rtype)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
return radio_enabled_for_rstate(&priv->radio_states[rtype], check_changeable);
nm_assert(_NM_INT_NOT_NEGATIVE(rtype) && rtype < G_N_ELEMENTS(priv->radio_states));
return _rfkill_radio_state_get_enabled(&priv->radio_states[rtype], TRUE);
}
static void
manager_update_radio_enabled(NMManager *self, RadioState *rstate, gboolean enabled)
_rfkill_update_devices(NMManager *self, NMRfkillType rtype, gboolean enabled)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
NMDevice *device;
/* Do nothing for radio types not yet implemented */
if (!rstate->prop)
return;
g_object_notify(G_OBJECT(self), rstate->prop);
_notify(self, _rfkill_type_desc[rtype].prop_id);
/* Don't touch devices if asleep/networking disabled */
if (manager_sleeping(self))
@ -2316,7 +2351,7 @@ manager_update_radio_enabled(NMManager *self, RadioState *rstate, gboolean enabl
/* enable/disable wireless devices as required */
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
if (nm_device_get_rfkill_type(device) == rstate->rtype) {
if (nm_device_get_rfkill_type(device) == rtype) {
_LOG2D(LOGD_RFKILL,
device,
"rfkill: setting radio %s",
@ -2327,89 +2362,185 @@ manager_update_radio_enabled(NMManager *self, RadioState *rstate, gboolean enabl
}
static void
update_rstate_from_rfkill(NMRfkillManager *rfkill_mgr, RadioState *rstate)
_rfkill_update_one_type(NMManager *self, NMRfkillType rtype)
{
switch (nm_rfkill_manager_get_rfkill_state(rfkill_mgr, rstate->rtype)) {
case RFKILL_UNBLOCKED:
rstate->sw_enabled = TRUE;
rstate->hw_enabled = TRUE;
break;
case RFKILL_SOFT_BLOCKED:
rstate->sw_enabled = FALSE;
rstate->hw_enabled = TRUE;
break;
case RFKILL_HARD_BLOCKED:
rstate->sw_enabled = FALSE;
rstate->hw_enabled = FALSE;
break;
default:
g_warn_if_reached();
break;
}
}
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
RfkillRadioState *rstate = &priv->radio_states[rtype];
gboolean old_enabled;
gboolean new_enabled;
gboolean old_rfkilled;
gboolean new_rfkilled;
gboolean old_hwe;
static void
manager_rfkill_update_one_type(NMManager *self, RadioState *rstate, RfKillType rtype)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
gboolean old_enabled, new_enabled, old_rfkilled, new_rfkilled, old_hwe;
nm_assert(_NM_INT_NOT_NEGATIVE(rtype) && rtype < G_N_ELEMENTS(priv->radio_states));
old_enabled = radio_enabled_for_rstate(rstate, TRUE);
old_enabled = _rfkill_radio_state_get_enabled(rstate, TRUE);
old_rfkilled = rstate->hw_enabled && rstate->sw_enabled;
old_hwe = rstate->hw_enabled;
/* recheck kernel rfkill state */
update_rstate_from_rfkill(priv->rfkill_mgr, rstate);
_rfkill_radio_state_set_from_manager(priv->rfkill_mgr, rtype, rstate);
/* Print out all states affecting device enablement */
if (rstate->desc) {
_LOGD(LOGD_RFKILL,
"rfkill: %s hw-enabled %d sw-enabled %d",
rstate->desc,
rstate->hw_enabled,
rstate->sw_enabled);
}
_LOGD(LOGD_RFKILL,
"rfkill: %s hw-enabled %d sw-enabled %d",
nm_rfkill_type_to_string(rtype),
rstate->hw_enabled,
rstate->sw_enabled);
/* Log new killswitch state */
new_rfkilled = rstate->hw_enabled && rstate->sw_enabled;
if (old_rfkilled != new_rfkilled) {
_LOGI(LOGD_RFKILL,
"rfkill: %s now %s by radio killswitch",
rstate->desc,
nm_rfkill_type_to_string(rtype),
new_rfkilled ? "enabled" : "disabled");
}
/* Send out property changed signal for HW enabled */
if (rstate->hw_enabled != old_hwe) {
if (rstate->hw_prop)
g_object_notify(G_OBJECT(self), rstate->hw_prop);
}
if (rstate->hw_enabled != old_hwe)
_notify(self, _rfkill_type_desc[rtype].hw_prop_id);
/* And finally update the actual device radio state itself; respect the
* daemon state here because this is never called from user-triggered
* radio changes and we only want to ignore the daemon enabled state when
* handling user radio change requests.
*/
new_enabled = radio_enabled_for_rstate(rstate, TRUE);
new_enabled = _rfkill_radio_state_get_enabled(rstate, TRUE);
if (new_enabled != old_enabled)
manager_update_radio_enabled(self, rstate, new_enabled);
_rfkill_update_devices(self, rtype, new_enabled);
}
static void
nm_manager_rfkill_update(NMManager *self, RfKillType rtype)
_rfkill_update(NMManager *self, NMRfkillType rtype)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
guint i;
guint i;
if (rtype != RFKILL_TYPE_UNKNOWN)
manager_rfkill_update_one_type(self, &priv->radio_states[rtype], rtype);
if (rtype != NM_RFKILL_TYPE_UNKNOWN)
_rfkill_update_one_type(self, rtype);
else {
/* Otherwise, sync all radio types */
for (i = 0; i < RFKILL_TYPE_MAX; i++)
manager_rfkill_update_one_type(self, &priv->radio_states[i], i);
for (i = 0; i < NM_RFKILL_TYPE_MAX; i++)
_rfkill_update_one_type(self, i);
}
}
/*****************************************************************************/
#define KERN_RFKILL_OP_CHANGE_ALL 3
#define KERN_RFKILL_TYPE_WLAN 1
#define KERN_RFKILL_TYPE_WWAN 5
struct rfkill_event {
uint32_t idx;
uint8_t type;
uint8_t op;
uint8_t soft;
uint8_t hard;
} _nm_packed;
static void
_rfkill_update_system(NMManager *self, NMRfkillType rtype, gboolean enabled)
{
nm_auto_close int fd = -1;
struct rfkill_event event;
ssize_t len;
int errsv;
nm_assert(NM_IN_SET(rtype, NM_RFKILL_TYPE_WLAN, NM_RFKILL_TYPE_WWAN));
fd = open("/dev/rfkill", O_RDWR | O_CLOEXEC);
if (fd < 0) {
if (errno == EACCES)
_LOGW(LOGD_RFKILL,
"rfkill: (%s): failed to open killswitch device",
nm_rfkill_type_to_string(rtype));
return;
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
_LOGW(LOGD_RFKILL,
"rfkill: (%s): failed to set killswitch device for "
"non-blocking operation",
nm_rfkill_type_to_string(rtype));
return;
}
memset(&event, 0, sizeof(event));
event.op = KERN_RFKILL_OP_CHANGE_ALL;
switch (rtype) {
case NM_RFKILL_TYPE_WLAN:
event.type = KERN_RFKILL_TYPE_WLAN;
break;
case NM_RFKILL_TYPE_WWAN:
event.type = KERN_RFKILL_TYPE_WWAN;
break;
default:
nm_assert_not_reached();
}
event.soft = enabled ? 0 : 1;
len = write(fd, &event, sizeof(event));
if (len < 0) {
errsv = errno;
_LOGW(LOGD_RFKILL,
"rfkill: (%s): failed to change Wi-Fi killswitch state: (%d) %s",
nm_rfkill_type_to_string(rtype),
errsv,
nm_strerror_native(errsv));
} else if (len == sizeof(event)) {
_LOGI(LOGD_RFKILL,
"rfkill: %s hardware radio set %s",
nm_rfkill_type_to_string(rtype),
enabled ? "enabled" : "disabled");
} else {
/* Failed to write full structure */
_LOGW(LOGD_RFKILL,
"rfkill: (%s): failed to change Wi-Fi killswitch state",
nm_rfkill_type_to_string(rtype));
}
}
static void
_rfkill_update_from_user(NMManager *self, NMRfkillType rtype, gboolean enabled)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
RfkillRadioState *rstate = &priv->radio_states[rtype];
gboolean old_enabled, new_enabled;
/* Don't touch devices if asleep/networking disabled */
if (manager_sleeping(self))
return;
_LOGD(LOGD_RFKILL,
"rfkill: (%s): setting radio %s by user",
nm_rfkill_type_to_string(rtype),
enabled ? "enabled" : "disabled");
/* Update enabled key in state file */
nm_config_state_set(priv->config, TRUE, FALSE, _rfkill_type_desc[rtype].key, enabled);
/* When the user toggles the radio, their request should override any
* daemon (like ModemManager) enabled state that can be changed. For WWAN
* for example, we want the WwanEnabled property to reflect the daemon state
* too so that users can toggle the modem powered, but we don't want that
* daemon state to affect whether or not the user *can* turn it on, which is
* what the kernel rfkill state does. So we ignore daemon enabled state
* when determining what the new state should be since it shouldn't block
* the user's request.
*/
old_enabled = _rfkill_radio_state_get_enabled(rstate, TRUE);
rstate->user_enabled = enabled;
new_enabled = _rfkill_radio_state_get_enabled(rstate, FALSE);
if (new_enabled != old_enabled) {
/* Try to change the kernel rfkill state */
_rfkill_update_system(self, rtype, new_enabled);
_rfkill_update_devices(self, rtype, new_enabled);
}
}
/*****************************************************************************/
static void
device_auth_done_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data)
{
@ -3207,7 +3338,7 @@ add_device(NMManager *self, NMDevice *device, GError **error)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
const char *iface, *type_desc;
RfKillType rtype;
NMRfkillType rtype;
GSList *iter, *remove = NULL;
int ifindex;
const char *dbus_path;
@ -3294,9 +3425,9 @@ add_device(NMManager *self, NMDevice *device, GError **error)
* global state.
*/
rtype = nm_device_get_rfkill_type(device);
if (rtype != RFKILL_TYPE_UNKNOWN) {
nm_manager_rfkill_update(self, rtype);
nm_device_set_enabled(device, radio_enabled_for_type(self, rtype, TRUE));
if (rtype != NM_RFKILL_TYPE_UNKNOWN) {
_rfkill_update(self, rtype);
nm_device_set_enabled(device, _rfkill_radio_state_get(self, rtype));
}
iface = nm_device_get_iface(device);
@ -3671,12 +3802,14 @@ platform_query_devices(NMManager *self)
}
static void
rfkill_manager_rfkill_changed_cb(NMRfkillManager *rfkill_mgr,
RfKillType rtype,
RfKillState udev_state,
gpointer user_data)
rfkill_manager_rfkill_changed_cb(NMRfkillManager *rfkill_mgr,
/* NMRfkillType */ guint rtype,
/* NMRfkillState */ guint udev_state,
gpointer user_data)
{
nm_manager_rfkill_update(NM_MANAGER(user_data), rtype);
nm_assert(rtype < NM_RFKILL_TYPE_MAX);
_rfkill_update(NM_MANAGER(user_data), rtype);
}
const CList *
@ -6313,7 +6446,7 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
/* Ensure rfkill state is up-to-date since we don't respond to state
* changes during sleep.
*/
nm_manager_rfkill_update(self, RFKILL_TYPE_UNKNOWN);
_rfkill_update(self, NM_RFKILL_TYPE_UNKNOWN);
/* Re-manage managed devices */
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
@ -6330,20 +6463,19 @@ do_sleep_wake(NMManager *self, gboolean sleeping_changed)
/* enable/disable wireless devices since that we don't respond
* to killswitch changes during sleep.
*/
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
RadioState *rstate = &priv->radio_states[i];
gboolean enabled = radio_enabled_for_rstate(rstate, TRUE);
for (i = 0; i < NM_RFKILL_TYPE_MAX; i++) {
const NMRfkillType rtype = i;
const RfkillRadioState *rstate = &priv->radio_states[rtype];
gboolean enabled = _rfkill_radio_state_get_enabled(rstate, TRUE);
if (rstate->desc) {
_LOGD(LOGD_RFKILL,
"rfkill: %s %s devices (hw_enabled %d, sw_enabled %d, user_enabled %d)",
enabled ? "enabling" : "disabling",
rstate->desc,
rstate->hw_enabled,
rstate->sw_enabled,
rstate->user_enabled);
}
if (nm_device_get_rfkill_type(device) == rstate->rtype)
_LOGD(LOGD_RFKILL,
"rfkill: %s %s devices (hw_enabled %d, sw_enabled %d, user_enabled %d)",
enabled ? "enabling" : "disabling",
nm_rfkill_type_to_string(rtype),
rstate->hw_enabled,
rstate->sw_enabled,
rstate->user_enabled);
if (nm_device_get_rfkill_type(device) == rtype)
nm_device_set_enabled(device, enabled);
}
@ -6929,25 +7061,21 @@ nm_manager_start(NMManager *self, GError **error)
nm_device_factory_manager_for_each_factory(start_factory, NULL);
/* Set initial radio enabled/disabled state */
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
RadioState *rstate = &priv->radio_states[i];
gboolean enabled;
if (!rstate->desc)
continue;
for (i = 0; i < NM_RFKILL_TYPE_MAX; i++) {
const NMRfkillType rtype = i;
RfkillRadioState *rstate = &priv->radio_states[rtype];
gboolean enabled;
/* recheck kernel rfkill state */
update_rstate_from_rfkill(priv->rfkill_mgr, rstate);
_rfkill_radio_state_set_from_manager(priv->rfkill_mgr, rtype, rstate);
if (rstate->desc) {
_LOGI(LOGD_RFKILL,
"rfkill: %s %s by radio killswitch; %s by state file",
rstate->desc,
(rstate->hw_enabled && rstate->sw_enabled) ? "enabled" : "disabled",
rstate->user_enabled ? "enabled" : "disabled");
}
enabled = radio_enabled_for_rstate(rstate, TRUE);
manager_update_radio_enabled(self, rstate, enabled);
_LOGI(LOGD_RFKILL,
"rfkill: %s %s by radio killswitch; %s by state file",
nm_rfkill_type_to_string(rtype),
(rstate->hw_enabled && rstate->sw_enabled) ? "enabled" : "disabled",
rstate->user_enabled ? "enabled" : "disabled");
enabled = _rfkill_radio_state_get_enabled(rstate, TRUE);
_rfkill_update_devices(self, rtype, enabled);
}
_LOGI(LOGD_CORE, "Networking is %s by state file", priv->net_enabled ? "enabled" : "disabled");
@ -7588,118 +7716,7 @@ auth_mgr_changed(NMAuthManager *auth_manager, gpointer user_data)
"()");
}
#define KERN_RFKILL_OP_CHANGE_ALL 3
#define KERN_RFKILL_TYPE_WLAN 1
#define KERN_RFKILL_TYPE_WWAN 5
struct rfkill_event {
uint32_t idx;
uint8_t type;
uint8_t op;
uint8_t soft;
uint8_t hard;
} _nm_packed;
static void
rfkill_change(NMManager *self, const char *desc, RfKillType rtype, gboolean enabled)
{
int fd;
struct rfkill_event event;
ssize_t len;
int errsv;
g_return_if_fail(rtype == RFKILL_TYPE_WLAN || rtype == RFKILL_TYPE_WWAN);
fd = open("/dev/rfkill", O_RDWR | O_CLOEXEC);
if (fd < 0) {
if (errno == EACCES)
_LOGW(LOGD_RFKILL, "rfkill: (%s): failed to open killswitch device", desc);
return;
}
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
_LOGW(LOGD_RFKILL,
"rfkill: (%s): failed to set killswitch device for "
"non-blocking operation",
desc);
nm_close(fd);
return;
}
memset(&event, 0, sizeof(event));
event.op = KERN_RFKILL_OP_CHANGE_ALL;
switch (rtype) {
case RFKILL_TYPE_WLAN:
event.type = KERN_RFKILL_TYPE_WLAN;
break;
case RFKILL_TYPE_WWAN:
event.type = KERN_RFKILL_TYPE_WWAN;
break;
default:
g_assert_not_reached();
}
event.soft = enabled ? 0 : 1;
len = write(fd, &event, sizeof(event));
if (len < 0) {
errsv = errno;
_LOGW(LOGD_RFKILL,
"rfkill: (%s): failed to change Wi-Fi killswitch state: (%d) %s",
desc,
errsv,
nm_strerror_native(errsv));
} else if (len == sizeof(event)) {
_LOGI(LOGD_RFKILL,
"rfkill: %s hardware radio set %s",
desc,
enabled ? "enabled" : "disabled");
} else {
/* Failed to write full structure */
_LOGW(LOGD_RFKILL, "rfkill: (%s): failed to change Wi-Fi killswitch state", desc);
}
nm_close(fd);
}
static void
manager_radio_user_toggled(NMManager *self, RadioState *rstate, gboolean enabled)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
gboolean old_enabled, new_enabled;
/* Don't touch devices if asleep/networking disabled */
if (manager_sleeping(self))
return;
if (rstate->desc) {
_LOGD(LOGD_RFKILL,
"rfkill: (%s): setting radio %s by user",
rstate->desc,
enabled ? "enabled" : "disabled");
}
/* Update enabled key in state file */
nm_config_state_set(priv->config, TRUE, FALSE, rstate->key, enabled);
/* When the user toggles the radio, their request should override any
* daemon (like ModemManager) enabled state that can be changed. For WWAN
* for example, we want the WwanEnabled property to reflect the daemon state
* too so that users can toggle the modem powered, but we don't want that
* daemon state to affect whether or not the user *can* turn it on, which is
* what the kernel rfkill state does. So we ignore daemon enabled state
* when determining what the new state should be since it shouldn't block
* the user's request.
*/
old_enabled = radio_enabled_for_rstate(rstate, TRUE);
rstate->user_enabled = enabled;
new_enabled = radio_enabled_for_rstate(rstate, FALSE);
if (new_enabled != old_enabled) {
/* Try to change the kernel rfkill state */
if (rstate->rtype == RFKILL_TYPE_WLAN || rstate->rtype == RFKILL_TYPE_WWAN)
rfkill_change(self, rstate->desc, rstate->rtype, new_enabled);
manager_update_radio_enabled(self, rstate, new_enabled);
}
}
/*****************************************************************************/
static gboolean
periodic_update_active_connection_timestamps(gpointer user_data)
@ -7876,8 +7893,8 @@ constructed(GObject *object)
priv->net_enabled = state->net_enabled;
priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = state->wifi_enabled;
priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = state->wwan_enabled;
priv->radio_states[NM_RFKILL_TYPE_WLAN].user_enabled = state->wifi_enabled;
priv->radio_states[NM_RFKILL_TYPE_WWAN].user_enabled = state->wwan_enabled;
priv->rfkill_mgr = nm_rfkill_manager_new();
g_signal_connect(priv->rfkill_mgr,
@ -7890,21 +7907,18 @@ constructed(GObject *object)
* changes to the WirelessEnabled/WWANEnabled properties which toggle kernel
* rfkill.
*/
rfkill_change(self,
priv->radio_states[RFKILL_TYPE_WLAN].desc,
RFKILL_TYPE_WLAN,
priv->radio_states[RFKILL_TYPE_WLAN].user_enabled);
rfkill_change(self,
priv->radio_states[RFKILL_TYPE_WWAN].desc,
RFKILL_TYPE_WWAN,
priv->radio_states[RFKILL_TYPE_WWAN].user_enabled);
_rfkill_update_system(self,
NM_RFKILL_TYPE_WLAN,
priv->radio_states[NM_RFKILL_TYPE_WLAN].user_enabled);
_rfkill_update_system(self,
NM_RFKILL_TYPE_WWAN,
priv->radio_states[NM_RFKILL_TYPE_WWAN].user_enabled);
}
static void
nm_manager_init(NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE(self);
guint i;
GFile *file;
c_list_init(&priv->auth_lst_head);
@ -7918,25 +7932,16 @@ nm_manager_init(NMManager *self)
priv->capabilities = g_array_new(FALSE, FALSE, sizeof(guint32));
/* Initialize rfkill structures and states */
memset(priv->radio_states, 0, sizeof(priv->radio_states));
priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = TRUE;
priv->radio_states[RFKILL_TYPE_WLAN].key = NM_CONFIG_STATE_PROPERTY_WIFI_ENABLED;
priv->radio_states[RFKILL_TYPE_WLAN].prop = NM_MANAGER_WIRELESS_ENABLED;
priv->radio_states[RFKILL_TYPE_WLAN].hw_prop = NM_MANAGER_WIRELESS_HARDWARE_ENABLED;
priv->radio_states[RFKILL_TYPE_WLAN].desc = "Wi-Fi";
priv->radio_states[RFKILL_TYPE_WLAN].rtype = RFKILL_TYPE_WLAN;
priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = TRUE;
priv->radio_states[RFKILL_TYPE_WWAN].key = NM_CONFIG_STATE_PROPERTY_WWAN_ENABLED;
priv->radio_states[RFKILL_TYPE_WWAN].prop = NM_MANAGER_WWAN_ENABLED;
priv->radio_states[RFKILL_TYPE_WWAN].hw_prop = NM_MANAGER_WWAN_HARDWARE_ENABLED;
priv->radio_states[RFKILL_TYPE_WWAN].desc = "WWAN";
priv->radio_states[RFKILL_TYPE_WWAN].rtype = RFKILL_TYPE_WWAN;
for (i = 0; i < RFKILL_TYPE_MAX; i++)
priv->radio_states[i].hw_enabled = TRUE;
priv->radio_states[NM_RFKILL_TYPE_WLAN] = (RfkillRadioState){
.user_enabled = TRUE,
.sw_enabled = FALSE,
.hw_enabled = TRUE,
};
priv->radio_states[NM_RFKILL_TYPE_WWAN] = (RfkillRadioState){
.user_enabled = TRUE,
.sw_enabled = FALSE,
.hw_enabled = TRUE,
};
priv->sleeping = FALSE;
priv->state = NM_STATE_DISCONNECTED;
@ -8008,16 +8013,16 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
g_value_set_boolean(value, priv->net_enabled);
break;
case PROP_WIRELESS_ENABLED:
g_value_set_boolean(value, radio_enabled_for_type(self, RFKILL_TYPE_WLAN, TRUE));
g_value_set_boolean(value, _rfkill_radio_state_get(self, NM_RFKILL_TYPE_WLAN));
break;
case PROP_WIRELESS_HARDWARE_ENABLED:
g_value_set_boolean(value, priv->radio_states[RFKILL_TYPE_WLAN].hw_enabled);
g_value_set_boolean(value, priv->radio_states[NM_RFKILL_TYPE_WLAN].hw_enabled);
break;
case PROP_WWAN_ENABLED:
g_value_set_boolean(value, radio_enabled_for_type(self, RFKILL_TYPE_WWAN, TRUE));
g_value_set_boolean(value, _rfkill_radio_state_get(self, NM_RFKILL_TYPE_WWAN));
break;
case PROP_WWAN_HARDWARE_ENABLED:
g_value_set_boolean(value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled);
g_value_set_boolean(value, priv->radio_states[NM_RFKILL_TYPE_WWAN].hw_enabled);
break;
case PROP_WIMAX_ENABLED:
g_value_set_boolean(value, FALSE);
@ -8108,14 +8113,14 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
switch (prop_id) {
case PROP_WIRELESS_ENABLED:
manager_radio_user_toggled(NM_MANAGER(object),
&priv->radio_states[RFKILL_TYPE_WLAN],
g_value_get_boolean(value));
_rfkill_update_from_user(NM_MANAGER(object),
NM_RFKILL_TYPE_WLAN,
g_value_get_boolean(value));
break;
case PROP_WWAN_ENABLED:
manager_radio_user_toggled(NM_MANAGER(object),
&priv->radio_states[RFKILL_TYPE_WWAN],
g_value_get_boolean(value));
_rfkill_update_from_user(NM_MANAGER(object),
NM_RFKILL_TYPE_WWAN,
g_value_get_boolean(value));
break;
case PROP_WIMAX_ENABLED:
/* WIMAX is deprecated. This does nothing. */

View file

@ -9,6 +9,7 @@
#include <libudev.h>
#include "c-list/src/c-list.h"
#include "libnm-udev-aux/nm-udev-utils.h"
/*****************************************************************************/
@ -24,8 +25,9 @@ typedef struct {
NMUdevClient *udev_client;
/* Authoritative rfkill state (RFKILL_* enum) */
RfKillState rfkill_states[RFKILL_TYPE_MAX];
GSList *killswitches;
NMRfkillState rfkill_states[NM_RFKILL_TYPE_MAX];
CList killswitch_lst_head;
} NMRfkillManagerPrivate;
struct _NMRfkillManager {
@ -45,60 +47,63 @@ G_DEFINE_TYPE(NMRfkillManager, nm_rfkill_manager, G_TYPE_OBJECT)
/*****************************************************************************/
typedef struct {
char *name;
guint64 seqnum;
char *path;
char *driver;
RfKillType rtype;
int state;
gboolean platform;
CList killswitch_lst;
char *name;
char *path;
char *driver;
guint64 seqnum;
NMRfkillType rtype;
int state;
bool platform : 1;
} Killswitch;
RfKillState
nm_rfkill_manager_get_rfkill_state(NMRfkillManager *self, RfKillType rtype)
NMRfkillState
nm_rfkill_manager_get_rfkill_state(NMRfkillManager *self, NMRfkillType rtype)
{
g_return_val_if_fail(self != NULL, RFKILL_UNBLOCKED);
g_return_val_if_fail(rtype < RFKILL_TYPE_MAX, RFKILL_UNBLOCKED);
g_return_val_if_fail(self != NULL, NM_RFKILL_STATE_UNBLOCKED);
g_return_val_if_fail(rtype < NM_RFKILL_TYPE_MAX, NM_RFKILL_STATE_UNBLOCKED);
return NM_RFKILL_MANAGER_GET_PRIVATE(self)->rfkill_states[rtype];
}
static const char *
rfkill_type_to_desc(RfKillType rtype)
const char *
nm_rfkill_type_to_string(NMRfkillType type)
{
if (rtype == 0)
switch (type) {
case NM_RFKILL_TYPE_WLAN:
return "Wi-Fi";
else if (rtype == 1)
case NM_RFKILL_TYPE_WWAN:
return "WWAN";
else if (rtype == 2)
return "WiMAX";
return "unknown";
case NM_RFKILL_TYPE_UNKNOWN:
break;
}
return nm_assert_unreachable_val("unknown");
}
static const char *
rfkill_state_to_desc(RfKillState rstate)
nm_rfkill_state_to_string(NMRfkillState state)
{
if (rstate == 0)
switch (state) {
case NM_RFKILL_STATE_UNBLOCKED:
return "unblocked";
else if (rstate == 1)
case NM_RFKILL_STATE_SOFT_BLOCKED:
return "soft-blocked";
else if (rstate == 2)
case NM_RFKILL_STATE_HARD_BLOCKED:
return "hard-blocked";
return "unknown";
}
return nm_assert_unreachable_val("unknown");
}
static Killswitch *
killswitch_new(struct udev_device *device, RfKillType rtype)
killswitch_new(struct udev_device *device, NMRfkillType rtype)
{
Killswitch *ks;
struct udev_device *parent = NULL, *grandparent = NULL;
const char *driver, *subsys, *parent_subsys = NULL;
ks = g_malloc0(sizeof(Killswitch));
ks->name = g_strdup(udev_device_get_sysname(device));
ks->seqnum = udev_device_get_seqnum(device);
ks->path = g_strdup(udev_device_get_syspath(device));
ks->rtype = rtype;
struct udev_device *parent = NULL;
struct udev_device *grandparent = NULL;
const char *driver;
const char *subsys;
const char *parent_subsys = NULL;
gboolean platform;
driver = udev_device_get_property_value(device, "DRIVER");
subsys = udev_device_get_subsystem(device);
@ -116,14 +121,23 @@ killswitch_new(struct udev_device *device, RfKillType rtype)
driver = udev_device_get_property_value(grandparent, "DRIVER");
}
}
if (!driver)
driver = "(unknown)";
ks->driver = g_strdup(driver);
if (g_strcmp0(subsys, "platform") == 0 || g_strcmp0(parent_subsys, "platform") == 0
|| g_strcmp0(subsys, "acpi") == 0 || g_strcmp0(parent_subsys, "acpi") == 0)
ks->platform = TRUE;
platform = FALSE;
if (nm_streq0(subsys, "platform") || nm_streq0(parent_subsys, "platform")
|| nm_streq0(subsys, "acpi") || nm_streq0(parent_subsys, "acpi"))
platform = TRUE;
ks = g_slice_new(Killswitch);
*ks = (Killswitch){
.name = g_strdup(udev_device_get_sysname(device)),
.seqnum = udev_device_get_seqnum(device),
.path = g_strdup(udev_device_get_syspath(device)),
.rtype = rtype,
.driver = g_strdup(driver),
.platform = platform,
};
return ks;
}
@ -131,54 +145,51 @@ killswitch_new(struct udev_device *device, RfKillType rtype)
static void
killswitch_destroy(Killswitch *ks)
{
g_return_if_fail(ks != NULL);
c_list_unlink_stale(&ks->killswitch_lst);
g_free(ks->name);
g_free(ks->path);
g_free(ks->driver);
memset(ks, 0, sizeof(Killswitch));
g_free(ks);
nm_g_slice_free(ks);
}
static RfKillState
static NMRfkillState
sysfs_state_to_nm_state(int sysfs_state)
{
switch (sysfs_state) {
case 0:
return RFKILL_SOFT_BLOCKED;
return NM_RFKILL_STATE_SOFT_BLOCKED;
case 1:
return RFKILL_UNBLOCKED;
return NM_RFKILL_STATE_UNBLOCKED;
case 2:
return RFKILL_HARD_BLOCKED;
return NM_RFKILL_STATE_HARD_BLOCKED;
default:
nm_log_warn(LOGD_RFKILL, "unhandled rfkill state %d", sysfs_state);
break;
}
return RFKILL_UNBLOCKED;
return NM_RFKILL_STATE_UNBLOCKED;
}
static void
recheck_killswitches(NMRfkillManager *self)
{
NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE(self);
GSList *iter;
RfKillState poll_states[RFKILL_TYPE_MAX];
RfKillState platform_states[RFKILL_TYPE_MAX];
gboolean platform_checked[RFKILL_TYPE_MAX];
Killswitch *ks;
NMRfkillState poll_states[NM_RFKILL_TYPE_MAX];
NMRfkillState platform_states[NM_RFKILL_TYPE_MAX];
gboolean platform_checked[NM_RFKILL_TYPE_MAX];
int i;
/* Default state is unblocked */
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
poll_states[i] = RFKILL_UNBLOCKED;
platform_states[i] = RFKILL_UNBLOCKED;
for (i = 0; i < NM_RFKILL_TYPE_MAX; i++) {
poll_states[i] = NM_RFKILL_STATE_UNBLOCKED;
platform_states[i] = NM_RFKILL_STATE_UNBLOCKED;
platform_checked[i] = FALSE;
}
/* Poll the states of all killswitches */
for (iter = priv->killswitches; iter; iter = g_slist_next(iter)) {
Killswitch *ks = iter->data;
c_list_for_each_entry (ks, &priv->killswitch_lst_head, killswitch_lst) {
struct udev_device *device;
RfKillState dev_state;
NMRfkillState dev_state;
int sysfs_state;
device = udev_device_new_from_subsystem_sysname(nm_udev_client_get_udev(priv->udev_client),
@ -196,7 +207,7 @@ recheck_killswitches(NMRfkillManager *self)
nm_log_dbg(LOGD_RFKILL,
"%s rfkill%s switch %s state now %d/%u",
rfkill_type_to_desc(ks->rtype),
nm_rfkill_type_to_string(ks->rtype),
ks->platform ? " platform" : "",
ks->name,
sysfs_state,
@ -210,27 +221,32 @@ recheck_killswitches(NMRfkillManager *self)
if (dev_state > platform_states[ks->rtype])
platform_states[ks->rtype] = dev_state;
}
udev_device_unref(device);
}
/* Log and emit change signal for final rfkill states */
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
for (i = 0; i < NM_RFKILL_TYPE_MAX; i++) {
if (platform_checked[i] == TRUE) {
/* blocked platform switch state overrides device state, otherwise
* let the device state stand. (bgo #655773)
*/
if (platform_states[i] != RFKILL_UNBLOCKED)
if (platform_states[i] != NM_RFKILL_STATE_UNBLOCKED)
poll_states[i] = platform_states[i];
}
if (poll_states[i] != priv->rfkill_states[i]) {
nm_log_dbg(LOGD_RFKILL,
"%s rfkill state now '%s'",
rfkill_type_to_desc(i),
rfkill_state_to_desc(poll_states[i]));
nm_rfkill_type_to_string(i),
nm_rfkill_state_to_string(poll_states[i]));
priv->rfkill_states[i] = poll_states[i];
g_signal_emit(self, signals[RFKILL_CHANGED], 0, i, priv->rfkill_states[i]);
g_signal_emit(self,
signals[RFKILL_CHANGED],
0,
(guint) i,
(guint) priv->rfkill_states[i]);
}
}
}
@ -239,52 +255,48 @@ static Killswitch *
killswitch_find_by_name(NMRfkillManager *self, const char *name)
{
NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE(self);
GSList *iter;
Killswitch *ks;
g_return_val_if_fail(name != NULL, NULL);
nm_assert(name);
for (iter = priv->killswitches; iter; iter = g_slist_next(iter)) {
Killswitch *candidate = iter->data;
if (!strcmp(name, candidate->name))
return candidate;
c_list_for_each_entry (ks, &priv->killswitch_lst_head, killswitch_lst) {
if (nm_streq(name, ks->name))
return ks;
}
return NULL;
}
static RfKillType
static NMRfkillType
rfkill_type_to_enum(const char *str)
{
g_return_val_if_fail(str != NULL, RFKILL_TYPE_UNKNOWN);
if (str) {
if (nm_streq(str, "wlan"))
return NM_RFKILL_TYPE_WLAN;
if (nm_streq(str, "wwan"))
return NM_RFKILL_TYPE_WWAN;
}
if (!strcmp(str, "wlan"))
return RFKILL_TYPE_WLAN;
else if (!strcmp(str, "wwan"))
return RFKILL_TYPE_WWAN;
return RFKILL_TYPE_UNKNOWN;
return NM_RFKILL_TYPE_UNKNOWN;
}
static void
add_one_killswitch(NMRfkillManager *self, struct udev_device *device)
{
NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE(self);
const char *str_type;
RfKillType rtype;
NMRfkillType rtype;
Killswitch *ks;
str_type = udev_device_get_property_value(device, "RFKILL_TYPE");
rtype = rfkill_type_to_enum(str_type);
if (rtype == RFKILL_TYPE_UNKNOWN)
rtype = rfkill_type_to_enum(udev_device_get_property_value(device, "RFKILL_TYPE"));
if (rtype == NM_RFKILL_TYPE_UNKNOWN)
return;
ks = killswitch_new(device, rtype);
priv->killswitches = g_slist_prepend(priv->killswitches, ks);
ks = killswitch_new(device, rtype);
c_list_link_front(&priv->killswitch_lst_head, &ks->killswitch_lst);
nm_log_info(LOGD_RFKILL,
"%s: found %s radio killswitch (at %s) (%sdriver %s)",
ks->name,
rfkill_type_to_desc(rtype),
nm_rfkill_type_to_string(rtype),
ks->path,
ks->platform ? "platform " : "",
ks->driver ?: "<unknown>");
@ -297,6 +309,7 @@ rfkill_add(NMRfkillManager *self, struct udev_device *device)
g_return_if_fail(device != NULL);
name = udev_device_get_sysname(device);
g_return_if_fail(name != NULL);
if (!killswitch_find_by_name(self, name))
@ -307,21 +320,20 @@ static void
rfkill_remove(NMRfkillManager *self, struct udev_device *device)
{
NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE(self);
GSList *iter;
Killswitch *ks;
const char *name;
g_return_if_fail(device != NULL);
name = udev_device_get_sysname(device);
g_return_if_fail(name != NULL);
for (iter = priv->killswitches; iter; iter = g_slist_next(iter)) {
Killswitch *ks = iter->data;
if (!strcmp(ks->name, name)) {
c_list_for_each_entry (ks, &priv->killswitch_lst_head, killswitch_lst) {
if (nm_streq(ks->name, name)) {
nm_log_info(LOGD_RFKILL, "radio killswitch %s disappeared", ks->path);
priv->killswitches = g_slist_remove(priv->killswitches, ks);
killswitch_destroy(ks);
break;
return;
}
}
}
@ -339,16 +351,16 @@ handle_uevent(NMUdevClient *client, struct udev_device *device, gpointer user_da
/* A bit paranoid */
subsys = udev_device_get_subsystem(device);
g_return_if_fail(!g_strcmp0(subsys, "rfkill"));
g_return_if_fail(nm_streq0(subsys, "rfkill"));
nm_log_dbg(LOGD_PLATFORM,
"udev rfkill event: action '%s' device '%s'",
action,
udev_device_get_sysname(device));
if (!strcmp(action, "add"))
if (nm_streq(action, "add"))
rfkill_add(self, device);
else if (!strcmp(action, "remove"))
else if (nm_streq(action, "remove"))
rfkill_remove(self, device);
recheck_killswitches(self);
@ -364,8 +376,10 @@ nm_rfkill_manager_init(NMRfkillManager *self)
struct udev_list_entry *iter;
guint i;
for (i = 0; i < RFKILL_TYPE_MAX; i++)
priv->rfkill_states[i] = RFKILL_UNBLOCKED;
c_list_init(&priv->killswitch_lst_head);
for (i = 0; i < NM_RFKILL_TYPE_MAX; i++)
priv->rfkill_states[i] = NM_RFKILL_STATE_UNBLOCKED;
priv->udev_client = nm_udev_client_new(NM_MAKE_STRV("rfkill"), handle_uevent, self);
@ -399,11 +413,10 @@ dispose(GObject *object)
{
NMRfkillManager *self = NM_RFKILL_MANAGER(object);
NMRfkillManagerPrivate *priv = NM_RFKILL_MANAGER_GET_PRIVATE(self);
Killswitch *ks;
if (priv->killswitches) {
g_slist_free_full(priv->killswitches, (GDestroyNotify) killswitch_destroy);
priv->killswitches = NULL;
}
while ((ks = c_list_first_entry(&priv->killswitch_lst_head, Killswitch, killswitch_lst)))
killswitch_destroy(ks);
priv->udev_client = nm_udev_client_destroy(priv->udev_client);
@ -426,6 +439,6 @@ nm_rfkill_manager_class_init(NMRfkillManagerClass *klass)
NULL,
G_TYPE_NONE,
2,
G_TYPE_UINT,
G_TYPE_UINT);
G_TYPE_UINT /* NMRfkillType */,
G_TYPE_UINT /* NMRfkillState */);
}

View file

@ -8,22 +8,24 @@
#define __NM_RFKILL_MANAGER_H__
typedef enum {
RFKILL_UNBLOCKED = 0,
RFKILL_SOFT_BLOCKED = 1,
RFKILL_HARD_BLOCKED = 2,
} RfKillState;
NM_RFKILL_STATE_UNBLOCKED = 0,
NM_RFKILL_STATE_SOFT_BLOCKED = 1,
NM_RFKILL_STATE_HARD_BLOCKED = 2,
} NMRfkillState;
typedef enum {
RFKILL_TYPE_WLAN = 0,
RFKILL_TYPE_WWAN = 1,
NM_RFKILL_TYPE_WLAN = 0,
NM_RFKILL_TYPE_WWAN = 1,
/* UNKNOWN and MAX should always be 1 more than
* the last rfkill type since RFKILL_TYPE_MAX is
* the last rfkill type since NM_RFKILL_TYPE_MAX is
* used as an array size.
*/
RFKILL_TYPE_UNKNOWN, /* KEEP LAST */
RFKILL_TYPE_MAX = RFKILL_TYPE_UNKNOWN,
} RfKillType;
NM_RFKILL_TYPE_UNKNOWN, /* KEEP LAST */
NM_RFKILL_TYPE_MAX = NM_RFKILL_TYPE_UNKNOWN,
} NMRfkillType;
const char *nm_rfkill_type_to_string(NMRfkillType rtype);
#define NM_TYPE_RFKILL_MANAGER (nm_rfkill_manager_get_type())
#define NM_RFKILL_MANAGER(obj) \
@ -43,6 +45,6 @@ GType nm_rfkill_manager_get_type(void);
NMRfkillManager *nm_rfkill_manager_new(void);
RfKillState nm_rfkill_manager_get_rfkill_state(NMRfkillManager *manager, RfKillType rtype);
NMRfkillState nm_rfkill_manager_get_rfkill_state(NMRfkillManager *manager, NMRfkillType rtype);
#endif /* __NM_RFKILL_MANAGER_H__ */