mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 18:30:11 +01:00
690 lines
19 KiB
C
690 lines
19 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/* NetworkManager -- Network link manager
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Copyright (C) 2009 - 2011 Red Hat, Inc.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.h>
|
|
|
|
#include "wireless-helper.h"
|
|
|
|
#include <gudev/gudev.h>
|
|
|
|
#include "nm-udev-manager.h"
|
|
#include "nm-marshal.h"
|
|
#include "nm-logging.h"
|
|
#include "NetworkManagerUtils.h"
|
|
#include "nm-device-wifi.h"
|
|
#include "nm-device-olpc-mesh.h"
|
|
#include "nm-device-ethernet.h"
|
|
#if WITH_WIMAX
|
|
#include "nm-device-wimax.h"
|
|
#endif
|
|
|
|
typedef struct {
|
|
GUdevClient *client;
|
|
|
|
/* Authoritative rfkill state (RFKILL_* enum) */
|
|
RfKillState rfkill_states[RFKILL_TYPE_MAX];
|
|
GSList *killswitches;
|
|
|
|
gboolean disposed;
|
|
} NMUdevManagerPrivate;
|
|
|
|
#define NM_UDEV_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_UDEV_MANAGER, NMUdevManagerPrivate))
|
|
|
|
G_DEFINE_TYPE (NMUdevManager, nm_udev_manager, G_TYPE_OBJECT)
|
|
|
|
enum {
|
|
DEVICE_ADDED,
|
|
DEVICE_REMOVED,
|
|
RFKILL_CHANGED,
|
|
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
typedef struct {
|
|
char *name;
|
|
guint64 seqnum;
|
|
char *path;
|
|
char *driver;
|
|
RfKillType rtype;
|
|
gint state;
|
|
gboolean platform;
|
|
} Killswitch;
|
|
|
|
RfKillState
|
|
nm_udev_manager_get_rfkill_state (NMUdevManager *self, RfKillType rtype)
|
|
{
|
|
g_return_val_if_fail (self != NULL, RFKILL_UNBLOCKED);
|
|
g_return_val_if_fail (rtype < RFKILL_TYPE_MAX, RFKILL_UNBLOCKED);
|
|
|
|
return NM_UDEV_MANAGER_GET_PRIVATE (self)->rfkill_states[rtype];
|
|
}
|
|
|
|
static const char *
|
|
rfkill_type_to_desc (RfKillType rtype)
|
|
{
|
|
if (rtype == 0)
|
|
return "WiFi";
|
|
else if (rtype == 1)
|
|
return "WWAN";
|
|
else if (rtype == 2)
|
|
return "WiMAX";
|
|
return "unknown";
|
|
}
|
|
|
|
static const char *
|
|
rfkill_state_to_desc (RfKillState rstate)
|
|
{
|
|
if (rstate == 0)
|
|
return "unblocked";
|
|
else if (rstate == 1)
|
|
return "soft-blocked";
|
|
else if (rstate == 2)
|
|
return "hard-blocked";
|
|
return "unknown";
|
|
}
|
|
|
|
static Killswitch *
|
|
killswitch_new (GUdevDevice *device, RfKillType rtype)
|
|
{
|
|
Killswitch *ks;
|
|
GUdevDevice *parent = NULL, *grandparent = NULL;
|
|
const char *driver, *subsys, *parent_subsys = NULL;
|
|
|
|
ks = g_malloc0 (sizeof (Killswitch));
|
|
ks->name = g_strdup (g_udev_device_get_name (device));
|
|
ks->seqnum = g_udev_device_get_seqnum (device);
|
|
ks->path = g_strdup (g_udev_device_get_sysfs_path (device));
|
|
ks->rtype = rtype;
|
|
|
|
driver = g_udev_device_get_property (device, "DRIVER");
|
|
subsys = g_udev_device_get_subsystem (device);
|
|
|
|
/* Check parent for various attributes */
|
|
parent = g_udev_device_get_parent (device);
|
|
if (parent) {
|
|
parent_subsys = g_udev_device_get_subsystem (parent);
|
|
if (!driver)
|
|
driver = g_udev_device_get_property (parent, "DRIVER");
|
|
if (!driver) {
|
|
/* Sigh; try the grandparent */
|
|
grandparent = g_udev_device_get_parent (parent);
|
|
if (grandparent)
|
|
driver = g_udev_device_get_property (parent, "DRIVER");
|
|
}
|
|
}
|
|
|
|
if (!driver)
|
|
driver = "(unknown)";
|
|
ks->driver = g_strdup (driver);
|
|
|
|
if (g_strcmp0 (subsys, "platform") == 0 || g_strcmp0 (parent_subsys, "platform") == 0)
|
|
ks->platform = TRUE;
|
|
|
|
if (grandparent)
|
|
g_object_unref (grandparent);
|
|
if (parent)
|
|
g_object_unref (parent);
|
|
return ks;
|
|
}
|
|
|
|
static void
|
|
killswitch_destroy (Killswitch *ks)
|
|
{
|
|
g_return_if_fail (ks != NULL);
|
|
|
|
g_free (ks->name);
|
|
g_free (ks->path);
|
|
g_free (ks->driver);
|
|
memset (ks, 0, sizeof (Killswitch));
|
|
g_free (ks);
|
|
}
|
|
|
|
NMUdevManager *
|
|
nm_udev_manager_new (void)
|
|
{
|
|
return NM_UDEV_MANAGER (g_object_new (NM_TYPE_UDEV_MANAGER, NULL));
|
|
}
|
|
|
|
static RfKillState
|
|
sysfs_state_to_nm_state (gint sysfs_state)
|
|
{
|
|
switch (sysfs_state) {
|
|
case 0:
|
|
return RFKILL_SOFT_BLOCKED;
|
|
case 1:
|
|
return RFKILL_UNBLOCKED;
|
|
case 2:
|
|
return RFKILL_HARD_BLOCKED;
|
|
default:
|
|
nm_log_warn (LOGD_RFKILL, "unhandled rfkill state %d", sysfs_state);
|
|
break;
|
|
}
|
|
return RFKILL_UNBLOCKED;
|
|
}
|
|
|
|
static void
|
|
recheck_killswitches (NMUdevManager *self)
|
|
{
|
|
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
|
GSList *iter;
|
|
RfKillState poll_states[RFKILL_TYPE_MAX];
|
|
gboolean platform_checked[RFKILL_TYPE_MAX];
|
|
int i;
|
|
|
|
/* Default state is unblocked */
|
|
for (i = 0; i < RFKILL_TYPE_MAX; i++) {
|
|
poll_states[i] = RFKILL_UNBLOCKED;
|
|
platform_checked[i] = FALSE;
|
|
}
|
|
|
|
/* Perform two passes here; the first pass is for non-platform switches,
|
|
* which typically if hardkilled cannot be changed except by a physical
|
|
* hardware switch. The second pass checks platform killswitches, which
|
|
* take precedence over device killswitches, because typically platform
|
|
* killswitches control device killswitches. That is, a hardblocked device
|
|
* switch can often be unblocked by a platform switch. Thus if we have
|
|
* a hardblocked device switch and a softblocked platform switch, the
|
|
* combined state should be softblocked since the platform switch can be
|
|
* unblocked to change the device switch.
|
|
*/
|
|
|
|
/* Device switches first */
|
|
for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
|
|
Killswitch *ks = iter->data;
|
|
GUdevDevice *device;
|
|
RfKillState dev_state;
|
|
int sysfs_state;
|
|
|
|
if (ks->platform == FALSE) {
|
|
device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
|
|
if (device) {
|
|
sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
|
|
dev_state = sysfs_state_to_nm_state (sysfs_state);
|
|
if (dev_state > poll_states[ks->rtype])
|
|
poll_states[ks->rtype] = dev_state;
|
|
g_object_unref (device);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Platform switches next; their state overwrites device state */
|
|
for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
|
|
Killswitch *ks = iter->data;
|
|
GUdevDevice *device;
|
|
RfKillState dev_state;
|
|
int sysfs_state;
|
|
|
|
if (ks->platform == TRUE) {
|
|
device = g_udev_client_query_by_subsystem_and_name (priv->client, "rfkill", ks->name);
|
|
if (device) {
|
|
sysfs_state = g_udev_device_get_property_as_int (device, "RFKILL_STATE");
|
|
dev_state = sysfs_state_to_nm_state (sysfs_state);
|
|
|
|
if (platform_checked[ks->rtype] == FALSE) {
|
|
/* Overwrite device state with platform state for first
|
|
* platform switch found.
|
|
*/
|
|
poll_states[ks->rtype] = dev_state;
|
|
platform_checked[ks->rtype] = TRUE;
|
|
} else {
|
|
/* If there are multiple platform switches of the same type,
|
|
* take the "worst" state for all of that type.
|
|
*/
|
|
if (dev_state > poll_states[ks->rtype])
|
|
poll_states[ks->rtype] = dev_state;
|
|
}
|
|
g_object_unref (device);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Log and emit change signal for final rfkill states */
|
|
for (i = 0; i < RFKILL_TYPE_MAX; 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]));
|
|
|
|
priv->rfkill_states[i] = poll_states[i];
|
|
g_signal_emit (self, signals[RFKILL_CHANGED], 0, i, priv->rfkill_states[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static Killswitch *
|
|
killswitch_find_by_name (NMUdevManager *self, const char *name)
|
|
{
|
|
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
|
GSList *iter;
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
for (iter = priv->killswitches; iter; iter = g_slist_next (iter)) {
|
|
Killswitch *candidate = iter->data;
|
|
|
|
if (!strcmp (name, candidate->name))
|
|
return candidate;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static const RfKillType
|
|
rfkill_type_to_enum (const char *str)
|
|
{
|
|
g_return_val_if_fail (str != NULL, RFKILL_TYPE_UNKNOWN);
|
|
|
|
if (!strcmp (str, "wlan"))
|
|
return RFKILL_TYPE_WLAN;
|
|
else if (!strcmp (str, "wwan"))
|
|
return RFKILL_TYPE_WWAN;
|
|
else if (!strcmp (str, "wimax"))
|
|
return RFKILL_TYPE_WIMAX;
|
|
|
|
return RFKILL_TYPE_UNKNOWN;
|
|
}
|
|
|
|
static void
|
|
add_one_killswitch (NMUdevManager *self, GUdevDevice *device)
|
|
{
|
|
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
|
const char *str_type;
|
|
RfKillType rtype;
|
|
Killswitch *ks;
|
|
|
|
str_type = g_udev_device_get_property (device, "RFKILL_TYPE");
|
|
rtype = rfkill_type_to_enum (str_type);
|
|
if (rtype == RFKILL_TYPE_UNKNOWN)
|
|
return;
|
|
|
|
ks = killswitch_new (device, rtype);
|
|
priv->killswitches = g_slist_prepend (priv->killswitches, ks);
|
|
|
|
nm_log_info (LOGD_RFKILL, "found %s radio killswitch %s (at %s) (driver %s)",
|
|
rfkill_type_to_desc (rtype),
|
|
ks->name,
|
|
ks->path,
|
|
ks->driver ? ks->driver : "<unknown>");
|
|
}
|
|
|
|
static void
|
|
rfkill_add (NMUdevManager *self, GUdevDevice *device)
|
|
{
|
|
const char *name;
|
|
|
|
g_return_if_fail (device != NULL);
|
|
name = g_udev_device_get_name (device);
|
|
g_return_if_fail (name != NULL);
|
|
|
|
if (!killswitch_find_by_name (self, name))
|
|
add_one_killswitch (self, device);
|
|
}
|
|
|
|
static void
|
|
rfkill_remove (NMUdevManager *self,
|
|
GUdevDevice *device)
|
|
{
|
|
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
|
GSList *iter;
|
|
const char *name;
|
|
|
|
g_return_if_fail (device != NULL);
|
|
name = g_udev_device_get_name (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)) {
|
|
nm_log_info (LOGD_RFKILL, "radio killswitch %s disappeared", ks->path);
|
|
priv->killswitches = g_slist_remove (priv->killswitches, ks);
|
|
killswitch_destroy (ks);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
is_wireless (GUdevDevice *device)
|
|
{
|
|
char phy80211_path[255];
|
|
struct stat s;
|
|
int fd;
|
|
struct iwreq iwr;
|
|
const char *ifname, *path;
|
|
gboolean is_wifi = FALSE;
|
|
|
|
ifname = g_udev_device_get_name (device);
|
|
g_assert (ifname);
|
|
|
|
fd = socket (PF_INET, SOCK_DGRAM, 0);
|
|
if (fd == -1)
|
|
return FALSE;
|
|
|
|
strncpy (iwr.ifr_ifrn.ifrn_name, ifname, IFNAMSIZ);
|
|
|
|
path = g_udev_device_get_sysfs_path (device);
|
|
snprintf (phy80211_path, sizeof (phy80211_path), "%s/phy80211", path);
|
|
|
|
if ( (ioctl (fd, SIOCGIWNAME, &iwr) == 0)
|
|
|| (stat (phy80211_path, &s) == 0 && (s.st_mode & S_IFDIR)))
|
|
is_wifi = TRUE;
|
|
|
|
close (fd);
|
|
return is_wifi;
|
|
}
|
|
|
|
static gboolean
|
|
is_olpc_mesh (GUdevDevice *device)
|
|
{
|
|
const gchar *prop = g_udev_device_get_property (device, "ID_NM_OLPC_MESH");
|
|
return (prop != NULL);
|
|
}
|
|
|
|
static gboolean
|
|
is_wimax (const char *driver)
|
|
{
|
|
/* FIXME: check 'DEVTYPE' instead; but since we only support Intel
|
|
* WiMAX devices for now this is appropriate.
|
|
*/
|
|
return g_strcmp0 (driver, "i2400m_usb") == 0;
|
|
}
|
|
|
|
static GObject *
|
|
device_creator (NMUdevManager *manager,
|
|
GUdevDevice *udev_device,
|
|
gboolean sleeping)
|
|
{
|
|
GObject *device = NULL;
|
|
const char *ifname, *driver, *path, *subsys;
|
|
GUdevDevice *parent = NULL, *grandparent = NULL;
|
|
gint ifindex;
|
|
|
|
ifname = g_udev_device_get_name (udev_device);
|
|
g_assert (ifname);
|
|
|
|
path = g_udev_device_get_sysfs_path (udev_device);
|
|
if (!path) {
|
|
nm_log_warn (LOGD_HW, "couldn't determine device path; ignoring...");
|
|
return NULL;
|
|
}
|
|
|
|
driver = g_udev_device_get_driver (udev_device);
|
|
if (!driver) {
|
|
/* Try the parent */
|
|
parent = g_udev_device_get_parent (udev_device);
|
|
if (parent) {
|
|
driver = g_udev_device_get_driver (parent);
|
|
if (!driver) {
|
|
/* try the grandparent if it's an ibmebus device or if the
|
|
* subsys is NULL which usually indicates some sort of
|
|
* platform device like a 'gadget' net interface.
|
|
*/
|
|
subsys = g_udev_device_get_subsystem (parent);
|
|
if ( (g_strcmp0 (subsys, "ibmebus") == 0)
|
|
|| (subsys == NULL)) {
|
|
grandparent = g_udev_device_get_parent (parent);
|
|
if (grandparent)
|
|
driver = g_udev_device_get_driver (grandparent);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!driver) {
|
|
if (g_str_has_prefix (ifname, "easytether")) {
|
|
driver = "easytether";
|
|
} else {
|
|
nm_log_warn (LOGD_HW, "%s: couldn't determine device driver; ignoring...", path);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
ifindex = g_udev_device_get_sysfs_attr_as_int (udev_device, "ifindex");
|
|
if (ifindex <= 0) {
|
|
nm_log_warn (LOGD_HW, "%s: device had invalid ifindex %d; ignoring...", path, (guint32) ifindex);
|
|
goto out;
|
|
}
|
|
|
|
if (is_olpc_mesh (udev_device)) /* must be before is_wireless */
|
|
device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver);
|
|
else if (is_wireless (udev_device))
|
|
device = (GObject *) nm_device_wifi_new (path, ifname, driver);
|
|
else if (is_wimax (driver)) {
|
|
#if WITH_WIMAX
|
|
device = (GObject *) nm_device_wimax_new (path, ifname, driver);
|
|
#endif
|
|
} else
|
|
device = (GObject *) nm_device_ethernet_new (path, ifname, driver);
|
|
|
|
out:
|
|
if (grandparent)
|
|
g_object_unref (grandparent);
|
|
if (parent)
|
|
g_object_unref (parent);
|
|
return device;
|
|
}
|
|
|
|
static void
|
|
net_add (NMUdevManager *self, GUdevDevice *device)
|
|
{
|
|
gint etype;
|
|
const char *iface;
|
|
const char *tmp;
|
|
gboolean is_ctc;
|
|
|
|
g_return_if_fail (device != NULL);
|
|
|
|
iface = g_udev_device_get_name (device);
|
|
if (!iface) {
|
|
nm_log_dbg (LOGD_HW, "failed to get device's interface");
|
|
return;
|
|
}
|
|
|
|
etype = g_udev_device_get_sysfs_attr_as_int (device, "type");
|
|
is_ctc = (strncmp (iface, "ctc", 3) == 0) && (etype == 256);
|
|
|
|
/* Ignore devices that don't report Ethernet encapsulation, except for
|
|
* s390 CTC-type devices that report 256 for some reason.
|
|
* FIXME: use something other than interface name to detect CTC here.
|
|
*/
|
|
if ((etype != 1) && (is_ctc == FALSE)) {
|
|
nm_log_dbg (LOGD_HW, "ignoring interface with type %d", etype);
|
|
return;
|
|
}
|
|
|
|
/* Not all ethernet devices are immediately usable; newer mobile broadband
|
|
* devices (Ericsson, Option, Sierra) require setup on the tty before the
|
|
* ethernet device is usable. 2.6.33 and later kernels set the 'DEVTYPE'
|
|
* uevent variable which we can use to ignore the interface as a NMDevice
|
|
* subclass. ModemManager will pick it up though and so we'll handle it
|
|
* through the mobile broadband stuff.
|
|
*/
|
|
tmp = g_udev_device_get_property (device, "DEVTYPE");
|
|
if (g_strcmp0 (tmp, "wwan") == 0) {
|
|
nm_log_dbg (LOGD_HW, "ignoring interface with devtype '%s'", tmp);
|
|
return;
|
|
}
|
|
|
|
/* Ignore Nokia cdc-ether interfaces in PC-Suite mode since we need to
|
|
* talk phonet to use them, which ModemManager doesn't do yet.
|
|
*/
|
|
tmp = g_udev_device_get_property (device, "ID_VENDOR_ID");
|
|
if (g_strcmp0 (tmp, "0421") == 0) { /* Nokia vendor ID */
|
|
tmp = g_udev_device_get_property (device, "ID_MODEL");
|
|
if (tmp && (strstr (tmp, "PC-Suite") || strstr (tmp, "PC Suite"))) {
|
|
nm_log_dbg (LOGD_HW, "ignoring Nokia PC-Suite ethernet interface");
|
|
return;
|
|
}
|
|
}
|
|
|
|
g_signal_emit (self, signals[DEVICE_ADDED], 0, device, device_creator);
|
|
}
|
|
|
|
static void
|
|
net_remove (NMUdevManager *self, GUdevDevice *device)
|
|
{
|
|
g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
|
|
}
|
|
|
|
void
|
|
nm_udev_manager_query_devices (NMUdevManager *self)
|
|
{
|
|
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
|
GList *devices, *iter;
|
|
|
|
g_return_if_fail (self != NULL);
|
|
g_return_if_fail (NM_IS_UDEV_MANAGER (self));
|
|
|
|
devices = g_udev_client_query_by_subsystem (priv->client, "net");
|
|
for (iter = devices; iter; iter = g_list_next (iter)) {
|
|
net_add (self, G_UDEV_DEVICE (iter->data));
|
|
g_object_unref (G_UDEV_DEVICE (iter->data));
|
|
}
|
|
g_list_free (devices);
|
|
}
|
|
|
|
static void
|
|
handle_uevent (GUdevClient *client,
|
|
const char *action,
|
|
GUdevDevice *device,
|
|
gpointer user_data)
|
|
{
|
|
NMUdevManager *self = NM_UDEV_MANAGER (user_data);
|
|
const char *subsys;
|
|
|
|
g_return_if_fail (action != NULL);
|
|
|
|
/* A bit paranoid */
|
|
subsys = g_udev_device_get_subsystem (device);
|
|
g_return_if_fail (subsys != NULL);
|
|
|
|
nm_log_dbg (LOGD_HW, "UDEV event: action '%s' subsys '%s' device '%s'",
|
|
action, subsys, g_udev_device_get_name (device));
|
|
|
|
g_return_if_fail (!strcmp (subsys, "rfkill") || !strcmp (subsys, "net"));
|
|
|
|
if (!strcmp (action, "add")) {
|
|
if (!strcmp (subsys, "rfkill"))
|
|
rfkill_add (self, device);
|
|
else if (!strcmp (subsys, "net"))
|
|
net_add (self, device);
|
|
} else if (!strcmp (action, "remove")) {
|
|
if (!strcmp (subsys, "rfkill"))
|
|
rfkill_remove (self, device);
|
|
else if (!strcmp (subsys, "net"))
|
|
net_remove (self, device);
|
|
}
|
|
|
|
recheck_killswitches (self);
|
|
}
|
|
|
|
static void
|
|
nm_udev_manager_init (NMUdevManager *self)
|
|
{
|
|
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
|
const char *subsys[3] = { "rfkill", "net", NULL };
|
|
GList *switches, *iter;
|
|
guint32 i;
|
|
|
|
for (i = 0; i < RFKILL_TYPE_MAX; i++)
|
|
priv->rfkill_states[i] = RFKILL_UNBLOCKED;
|
|
|
|
priv->client = g_udev_client_new (subsys);
|
|
g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self);
|
|
|
|
switches = g_udev_client_query_by_subsystem (priv->client, "rfkill");
|
|
for (iter = switches; iter; iter = g_list_next (iter)) {
|
|
add_one_killswitch (self, G_UDEV_DEVICE (iter->data));
|
|
g_object_unref (G_UDEV_DEVICE (iter->data));
|
|
}
|
|
g_list_free (switches);
|
|
|
|
recheck_killswitches (self);
|
|
}
|
|
|
|
static void
|
|
dispose (GObject *object)
|
|
{
|
|
NMUdevManager *self = NM_UDEV_MANAGER (object);
|
|
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
|
|
|
|
if (priv->disposed) {
|
|
G_OBJECT_CLASS (nm_udev_manager_parent_class)->dispose (object);
|
|
return;
|
|
}
|
|
priv->disposed = TRUE;
|
|
|
|
g_object_unref (priv->client);
|
|
|
|
g_slist_foreach (priv->killswitches, (GFunc) killswitch_destroy, NULL);
|
|
g_slist_free (priv->killswitches);
|
|
|
|
G_OBJECT_CLASS (nm_udev_manager_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
nm_udev_manager_class_init (NMUdevManagerClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
g_type_class_add_private (klass, sizeof (NMUdevManagerPrivate));
|
|
|
|
/* virtual methods */
|
|
object_class->dispose = dispose;
|
|
|
|
/* Signals */
|
|
signals[DEVICE_ADDED] =
|
|
g_signal_new ("device-added",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMUdevManagerClass, device_added),
|
|
NULL, NULL,
|
|
_nm_marshal_VOID__POINTER_POINTER,
|
|
G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
|
|
|
|
signals[DEVICE_REMOVED] =
|
|
g_signal_new ("device-removed",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMUdevManagerClass, device_removed),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__POINTER,
|
|
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
|
|
|
signals[RFKILL_CHANGED] =
|
|
g_signal_new ("rfkill-changed",
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (NMUdevManagerClass, rfkill_changed),
|
|
NULL, NULL,
|
|
_nm_marshal_VOID__UINT_UINT,
|
|
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
|
|
}
|
|
|