NetworkManager/src/devices/nm-device-olpc-mesh.c
Dan Williams be807819b0 core: clean up and simplify device capabilities handling
This is really, really old 2007-era code.  Any NMDevice that gets
created is already supported, so there's no reason to have every
device set NM_DEVICE_CAP_NM_SUPPORTED.  For those subclasses that
only set that capability, we can remove the subclass method
entirely.  Next, it turns out that the "type capabilities" code
wasn't used anywhere, so remove that too.  Lastly, "cipsec"
interfaces haven't been used on linux in about 5 years (they
were created by the Cisco binary-only IPSec kernel module for
Cisco VPNs long before vpnc and openswan came around) so we can
remove that code too.
2013-05-20 16:38:34 -03:00

725 lines
22 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* Dan Williams <dcbw@redhat.com>
* Sjoerd Simons <sjoerd.simons@collabora.co.uk>
* Daniel Drake <dsd@laptop.org>
*
* 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.
*
* (C) Copyright 2005 - 2011 Red Hat, Inc.
* (C) Copyright 2008 Collabora Ltd.
* (C) Copyright 2009 One Laptop per Child
*/
#include "config.h"
#include <glib.h>
#include <glib/gi18n.h>
#include <dbus/dbus.h>
#include <netinet/in.h>
#include <string.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <signal.h>
#include <unistd.h>
#include <linux/if.h>
#include <sys/ioctl.h>
#include <errno.h>
#include "nm-device.h"
#include "nm-device-wifi.h"
#include "nm-device-olpc-mesh.h"
#include "nm-device-private.h"
#include "nm-utils.h"
#include "nm-logging.h"
#include "NetworkManagerUtils.h"
#include "nm-activation-request.h"
#include "nm-setting-connection.h"
#include "nm-setting-olpc-mesh.h"
#include "nm-system.h"
#include "nm-manager.h"
#include "nm-enum-types.h"
#include "nm-dbus-manager.h"
#include "wifi-utils.h"
#if HAVE_WEXT
#include "wifi-utils-wext.h"
#endif
/* This is a bug; but we can't really change API now... */
#include "NetworkManagerVPN.h"
#include "nm-device-olpc-mesh-glue.h"
G_DEFINE_TYPE (NMDeviceOlpcMesh, nm_device_olpc_mesh, NM_TYPE_DEVICE)
#define NM_DEVICE_OLPC_MESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshPrivate))
enum {
PROP_0,
PROP_COMPANION,
PROP_ACTIVE_CHANNEL,
LAST_PROP
};
#define NM_OLPC_MESH_ERROR (nm_olpc_mesh_error_quark ())
struct _NMDeviceOlpcMeshPrivate
{
gboolean dispose_has_run;
GByteArray * ssid;
WifiData * wifi_data;
gboolean up;
NMDevice * companion;
gboolean stage1_waiting;
guint device_added_id;
guint device_removed_id;
guint cmp_state_changed_id;
guint cmp_scanning_id;
guint cmp_scanning_allowed_id;
guint cmp_autoconnect_allowed_id;
};
static void state_changed (NMDevice *device, NMDeviceState new_state,
NMDeviceState old_state, NMDeviceStateReason reason);
static GQuark
nm_olpc_mesh_error_quark (void)
{
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string ("nm-mesh-error");
return quark;
}
static void
nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
priv->dispose_has_run = FALSE;
priv->companion = NULL;
priv->stage1_waiting = FALSE;
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
{
GObject *object;
GObjectClass *klass;
NMDeviceOlpcMesh *self;
NMDeviceOlpcMeshPrivate *priv;
klass = G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class);
object = klass->constructor (type, n_construct_params, construct_params);
if (!object)
return NULL;
self = NM_DEVICE_OLPC_MESH (object);
priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d",
nm_device_get_iface (NM_DEVICE (self)),
nm_device_get_ifindex (NM_DEVICE (self)));
/*
* The kernel driver now uses nl80211, but we force use of WEXT because
* the cfg80211 interactions are not quite ready to support access to
* mesh control through nl80211 just yet.
*/
#if HAVE_WEXT
priv->wifi_data = wifi_wext_init (nm_device_get_iface (NM_DEVICE (self)),
nm_device_get_ifindex (NM_DEVICE (self)),
FALSE);
#endif
if (priv->wifi_data == NULL) {
nm_log_warn (LOGD_HW | LOGD_OLPC_MESH, "(%s): failed to initialize WiFi driver",
nm_device_get_iface (NM_DEVICE (self)));
g_object_unref (object);
return NULL;
}
/* shorter timeout for mesh connectivity */
nm_device_set_dhcp_timeout (NM_DEVICE (self), 20);
return object;
}
static gboolean
is_up (NMDevice *device)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
return priv->up;
}
static gboolean
bring_up (NMDevice *dev)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
priv->up = TRUE;
return TRUE;
}
static void
device_cleanup (NMDeviceOlpcMesh *self)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
if (priv->ssid) {
g_byte_array_free (priv->ssid, TRUE);
priv->ssid = NULL;
}
priv->up = FALSE;
}
static void
take_down (NMDevice *dev)
{
device_cleanup (NM_DEVICE_OLPC_MESH (dev));
}
static gboolean
check_connection_compatible (NMDevice *device,
NMConnection *connection,
GError **error)
{
NMSettingConnection *s_con;
NMSettingOlpcMesh *s_mesh;
if (!NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->check_connection_compatible (device, connection, error))
return FALSE;
s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_OLPC_MESH_SETTING_NAME)) {
g_set_error (error,
NM_OLPC_MESH_ERROR, NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH,
"The connection was not a Mesh connection.");
return FALSE;
}
s_mesh = nm_connection_get_setting_olpc_mesh (connection);
if (!s_mesh) {
g_set_error (error,
NM_OLPC_MESH_ERROR, NM_OLPC_MESH_ERROR_CONNECTION_INVALID,
"The connection was not a valid Mesh connection.");
return FALSE;
}
return TRUE;
}
static gboolean
can_auto_connect (NMDevice *device,
NMConnection *connection,
char **specific_object)
{
return FALSE;
}
#define DEFAULT_SSID "olpc-mesh"
static gboolean
complete_connection (NMDevice *device,
NMConnection *connection,
const char *specific_object,
const GSList *existing_connections,
GError **error)
{
NMSettingOlpcMesh *s_mesh;
GByteArray *tmp;
s_mesh = nm_connection_get_setting_olpc_mesh (connection);
if (!s_mesh) {
s_mesh = (NMSettingOlpcMesh *) nm_setting_olpc_mesh_new ();
nm_connection_add_setting (connection, NM_SETTING (s_mesh));
}
if (!nm_setting_olpc_mesh_get_ssid (s_mesh)) {
tmp = g_byte_array_sized_new (strlen (DEFAULT_SSID));
g_byte_array_append (tmp, (const guint8 *) DEFAULT_SSID, strlen (DEFAULT_SSID));
g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_SSID, tmp, NULL);
g_byte_array_free (tmp, TRUE);
}
if (!nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh)) {
const guint8 anycast[ETH_ALEN] = { 0xC0, 0x27, 0xC0, 0x27, 0xC0, 0x27 };
tmp = g_byte_array_sized_new (ETH_ALEN);
g_byte_array_append (tmp, anycast, sizeof (anycast));
g_object_set (G_OBJECT (s_mesh), NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS, tmp, NULL);
g_byte_array_free (tmp, TRUE);
}
nm_utils_complete_generic (connection,
NM_SETTING_OLPC_MESH_SETTING_NAME,
existing_connections,
_("Mesh %d"),
NULL,
FALSE); /* No IPv6 by default */
return TRUE;
}
/****************************************************************************/
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (dev);
gboolean scanning;
/* disconnect companion device, if it is connected */
if (nm_device_get_act_request (NM_DEVICE (priv->companion))) {
nm_log_info (LOGD_OLPC_MESH, "(%s): disconnecting companion device %s",
nm_device_get_iface (dev),
nm_device_get_iface (priv->companion));
/* FIXME: VPN stuff here is a bug; but we can't really change API now... */
nm_device_state_changed (NM_DEVICE (priv->companion),
NM_DEVICE_STATE_DISCONNECTED,
NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED);
nm_log_info (LOGD_OLPC_MESH, "(%s): companion %s disconnected",
nm_device_get_iface (dev),
nm_device_get_iface (priv->companion));
}
/* wait with continuing configuration untill the companion device is done scanning */
g_object_get (priv->companion, "scanning", &scanning, NULL);
if (scanning) {
priv->stage1_waiting = TRUE;
return NM_ACT_STAGE_RETURN_POSTPONE;
}
return NM_ACT_STAGE_RETURN_SUCCESS;
}
static void
_mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
if (wifi_utils_get_mesh_channel (priv->wifi_data) != channel) {
if (wifi_utils_set_mesh_channel (priv->wifi_data, channel))
g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL);
}
}
static NMActStageReturn
act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
NMConnection *connection;
NMSettingOlpcMesh *s_mesh;
guint32 channel;
const GByteArray *anycast_addr_array;
guint8 *anycast_addr = NULL;
connection = nm_device_get_connection (dev);
g_assert (connection);
s_mesh = nm_connection_get_setting_olpc_mesh (connection);
g_assert (s_mesh);
channel = nm_setting_olpc_mesh_get_channel (s_mesh);
if (channel != 0)
_mesh_set_channel (self, channel);
wifi_utils_set_mesh_ssid (priv->wifi_data, nm_setting_olpc_mesh_get_ssid (s_mesh));
anycast_addr_array = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh);
if (anycast_addr_array)
anycast_addr = anycast_addr_array->data;
nm_device_set_dhcp_anycast_address (dev, anycast_addr);
return NM_ACT_STAGE_RETURN_SUCCESS;
}
static void
companion_cleanup (NMDeviceOlpcMesh *self)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
if (priv->companion == NULL)
return;
if (priv->cmp_state_changed_id) {
g_signal_handler_disconnect (priv->companion, priv->cmp_state_changed_id);
priv->cmp_state_changed_id = 0;
}
if (priv->cmp_scanning_id) {
g_signal_handler_disconnect (priv->companion, priv->cmp_scanning_id);
priv->cmp_scanning_id = 0;
}
if (priv->cmp_scanning_allowed_id) {
g_signal_handler_disconnect (priv->companion, priv->cmp_scanning_allowed_id);
priv->cmp_scanning_allowed_id = 0;
}
if (priv->cmp_autoconnect_allowed_id) {
g_signal_handler_disconnect (priv->companion, priv->cmp_autoconnect_allowed_id);
priv->cmp_autoconnect_allowed_id = 0;
}
priv->companion = NULL;
g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_COMPANION);
}
static void
dispose (GObject *object)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
NMManager *manager;
if (priv->dispose_has_run) {
G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object);
return;
}
priv->dispose_has_run = TRUE;
if (priv->wifi_data)
wifi_utils_deinit (priv->wifi_data);
device_cleanup (self);
companion_cleanup (self);
manager = nm_manager_get ();
if (priv->device_added_id)
g_signal_handler_disconnect (manager, priv->device_added_id);
if (priv->device_removed_id)
g_signal_handler_disconnect (manager, priv->device_removed_id);
g_object_unref (manager);
G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object);
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMDeviceOlpcMesh *device = NM_DEVICE_OLPC_MESH (object);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device);
switch (prop_id) {
case PROP_COMPANION:
if (priv->companion)
g_value_set_boxed (value, nm_device_get_path (priv->companion));
else
g_value_set_boxed (value, "/");
break;
case PROP_ACTIVE_CHANNEL:
g_value_set_uint (value, wifi_utils_get_mesh_channel (priv->wifi_data));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
g_type_class_add_private (object_class, sizeof (NMDeviceOlpcMeshPrivate));
object_class->constructor = constructor;
object_class->get_property = get_property;
object_class->set_property = set_property;
object_class->dispose = dispose;
parent_class->is_up = is_up;
parent_class->bring_up = bring_up;
parent_class->take_down = take_down;
parent_class->check_connection_compatible = check_connection_compatible;
parent_class->can_auto_connect = can_auto_connect;
parent_class->complete_connection = complete_connection;
parent_class->act_stage1_prepare = act_stage1_prepare;
parent_class->act_stage2_config = act_stage2_config;
parent_class->state_changed = state_changed;
/* Properties */
g_object_class_install_property
(object_class, PROP_COMPANION,
g_param_spec_boxed (NM_DEVICE_OLPC_MESH_COMPANION,
"Companion device",
"Companion device object path",
DBUS_TYPE_G_OBJECT_PATH,
G_PARAM_READABLE));
g_object_class_install_property
(object_class, PROP_ACTIVE_CHANNEL,
g_param_spec_uint (NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL,
"Active channel",
"Active channel",
0, G_MAXUINT32, 0,
G_PARAM_READABLE));
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
G_TYPE_FROM_CLASS (klass),
&dbus_glib_nm_device_olpc_mesh_object_info);
dbus_g_error_domain_register (NM_OLPC_MESH_ERROR, NULL,
NM_TYPE_OLPC_MESH_ERROR);
}
static void
companion_notify_cb (NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_data)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
gboolean scanning;
if (!priv->stage1_waiting)
return;
g_object_get (companion, "scanning", &scanning, NULL);
if (!scanning) {
priv->stage1_waiting = FALSE;
nm_device_activate_schedule_stage2_device_config (NM_DEVICE (self));
}
}
/* disconnect from mesh if someone starts using the companion */
static void
companion_state_changed_cb (NMDeviceWifi *companion,
NMDeviceState state,
NMDeviceState old_state,
NMDeviceStateReason reason,
gpointer user_data)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
NMDeviceState self_state = nm_device_get_state (NM_DEVICE (self));
if ( self_state < NM_DEVICE_STATE_PREPARE
|| self_state > NM_DEVICE_STATE_ACTIVATED
|| state < NM_DEVICE_STATE_PREPARE
|| state > NM_DEVICE_STATE_ACTIVATED)
return;
nm_log_dbg (LOGD_OLPC_MESH, "(%s): disconnecting mesh due to companion connectivity",
nm_device_get_iface (NM_DEVICE (self)));
/* FIXME: VPN stuff here is a bug; but we can't really change API now... */
nm_device_state_changed (NM_DEVICE (self),
NM_DEVICE_STATE_DISCONNECTED,
NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED);
}
static gboolean
companion_scan_allowed_cb (NMDeviceWifi *companion, gpointer user_data)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
NMDeviceState state = nm_device_get_state (NM_DEVICE (self));
/* Don't allow the companion to scan while configuring the mesh interface */
return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_IP_CONFIG);
}
static gboolean
companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
NMDeviceState state = nm_device_get_state (NM_DEVICE (self));
/* Don't allow the companion to autoconnect while a mesh connection is
* active */
return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_ACTIVATED);
}
static gboolean
is_companion (NMDeviceOlpcMesh *self, NMDevice *other)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
const guint8 *my_addr, *their_addr;
guint their_addr_len;
NMManager *manager;
if (!NM_IS_DEVICE_WIFI (other))
return FALSE;
my_addr = nm_device_get_hw_address (NM_DEVICE (self), NULL);
their_addr = nm_device_get_hw_address (other, &their_addr_len);
if ( (their_addr_len != ETH_ALEN)
|| (memcmp (my_addr, their_addr, ETH_ALEN) != 0))
return FALSE;
priv->companion = other;
/* When we've found the companion, stop listening for other devices */
manager = nm_manager_get ();
if (priv->device_added_id) {
g_signal_handler_disconnect (manager, priv->device_added_id);
priv->device_added_id = 0;
}
g_object_unref (manager);
nm_device_state_changed (NM_DEVICE (self),
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
nm_log_info (LOGD_OLPC_MESH, "(%s): found companion WiFi device %s",
nm_device_get_iface (NM_DEVICE (self)),
nm_device_get_iface (other));
priv->cmp_state_changed_id = g_signal_connect (G_OBJECT (other), "state-changed",
G_CALLBACK (companion_state_changed_cb), self);
priv->cmp_scanning_id = g_signal_connect (G_OBJECT (other), "notify::scanning",
G_CALLBACK (companion_notify_cb), self);
priv->cmp_scanning_allowed_id = g_signal_connect (G_OBJECT (other), "scanning-allowed",
G_CALLBACK (companion_scan_allowed_cb), self);
priv->cmp_autoconnect_allowed_id = g_signal_connect (G_OBJECT (other), "autoconnect-allowed",
G_CALLBACK (companion_autoconnect_allowed_cb), self);
g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_COMPANION);
return TRUE;
}
static void
device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
is_companion (self, other);
}
static void
device_removed_cb (NMManager *manager, NMDevice *other, gpointer user_data)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
if (other == NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->companion)
companion_cleanup (self);
}
static gboolean
check_companion_cb (gpointer user_data)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
NMManager *manager;
GSList *list;
if (priv->companion != NULL) {
nm_device_state_changed (NM_DEVICE (user_data),
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
return FALSE;
}
if (priv->device_added_id != 0)
return FALSE;
manager = nm_manager_get ();
priv->device_added_id = g_signal_connect (manager, "device-added",
G_CALLBACK (device_added_cb), self);
if (!priv->device_removed_id) {
priv->device_removed_id = g_signal_connect (manager, "device-removed",
G_CALLBACK (device_removed_cb), self);
}
/* Try to find the companion if it's already known to the NMManager */
for (list = nm_manager_get_devices (manager); list ; list = g_slist_next (list)) {
if (is_companion (self, NM_DEVICE (list->data)))
break;
}
g_object_unref (manager);
return FALSE;
}
static void
state_changed (NMDevice *device, NMDeviceState new_state,
NMDeviceState old_state, NMDeviceStateReason reason)
{
NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
switch (new_state) {
case NM_DEVICE_STATE_UNMANAGED:
break;
case NM_DEVICE_STATE_UNAVAILABLE:
/* If transitioning to UNAVAILABLE and the companion device is known then
* transition to DISCONNECTED otherwise wait for our companion.
*/
g_idle_add (check_companion_cb, self);
break;
case NM_DEVICE_STATE_ACTIVATED:
break;
case NM_DEVICE_STATE_FAILED:
break;
case NM_DEVICE_STATE_DISCONNECTED:
break;
default:
break;
}
}
NMDevice *
nm_device_olpc_mesh_new (const char *udi,
const char *iface,
const char *driver)
{
g_return_val_if_fail (udi != NULL, NULL);
g_return_val_if_fail (iface != NULL, NULL);
g_return_val_if_fail (driver != NULL, NULL);
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_OLPC_MESH,
NM_DEVICE_UDI, udi,
NM_DEVICE_IFACE, iface,
NM_DEVICE_DRIVER, driver,
NM_DEVICE_TYPE_DESC, "802.11 OLPC Mesh",
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_OLPC_MESH,
NULL);
}