mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 02:10:09 +01:00
core/rfkill: merge branch 'th/rfkill-cleanup'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1079
This commit is contained in:
commit
60153308fe
10 changed files with 417 additions and 408 deletions
|
|
@ -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,
|
||||
"",
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
"",
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
"",
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
"",
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
"",
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
"",
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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 */);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue