Re: [PATCH] OLPC Mesh interface support
- From: Dan Williams <dcbw redhat com>
- To: Daniel Drake <dsd laptop org>
- Cc: networkmanager-list gnome org
- Subject: Re: [PATCH] OLPC Mesh interface support
- Date: Wed, 15 Jul 2009 14:15:22 -0400
On Wed, 2009-07-08 at 14:50 +0100, Daniel Drake wrote:
> Implement device and settings classes to support the OLPC mesh interface.
> Unlike NetworkManager-0.6, the logic for trying the available channels
> and anycasts will be implemented outside of NetworkManager (e.g. in sugar).
A few things... can you post the udev rules file so we can add that
too? I'd like to change that from NM_DEVICE_TYPE to ID_NM_OLPC_MESH to
be more in keeping with udev's property naming.
Second, the autoconnect inhibit stuff is pretty elegant the way you've
implemented it, but I'd like to see if we could implement it with the
inhibit stuff I've got going on in another branch (which is a property
on the device instead of a signal). If you can't do that then maybe I
can.
Third, we try not to let the devices themselves have direct access to
the manager for a few reasons (Tambet was the one who originally
architected it that way) so I'd like to either revisit that restriction
or have the manager pass the device list into the device creators and
then call device-added/removed functions. That basically duplicates
signals (bad) but doesn't require the manager object (good).
I'll try to poke Tambet on #3. OLPC is obviously the first device we've
had that is so tightly tied to another.
So this means I've applied 1, 2, 3 and 5, but not the
autoconnect-inhibit and not the main OLPC mesh patch yet.
Dan
> Based on earlier work by Sjoerd Simons.
> ---
> include/NetworkManager.h | 3 +-
> introspection/Makefile.am | 1 +
> introspection/nm-device-olpc-mesh.xml | 32 ++
> libnm-util/Makefile.am | 2 +
> libnm-util/libnm-util.ver | 4 +
> libnm-util/nm-connection.c | 6 +
> libnm-util/nm-setting-olpc-mesh.c | 265 +++++++++
> libnm-util/nm-setting-olpc-mesh.h | 52 ++
> src/Makefile.am | 6 +
> src/nm-device-olpc-mesh.c | 986 +++++++++++++++++++++++++++++++++
> src/nm-device-olpc-mesh.h | 85 +++
> src/nm-manager.c | 3 +
> src/nm-udev-manager.c | 14 +-
> 13 files changed, 1457 insertions(+), 2 deletions(-)
> create mode 100644 introspection/nm-device-olpc-mesh.xml
> create mode 100644 libnm-util/nm-setting-olpc-mesh.c
> create mode 100644 libnm-util/nm-setting-olpc-mesh.h
> create mode 100644 src/nm-device-olpc-mesh.c
> create mode 100644 src/nm-device-olpc-mesh.h
>
> For master branch
>
> diff --git a/include/NetworkManager.h b/include/NetworkManager.h
> index 997701e..96c162f 100644
> --- a/include/NetworkManager.h
> +++ b/include/NetworkManager.h
> @@ -76,7 +76,8 @@ typedef enum NMDeviceType
> NM_DEVICE_TYPE_WIFI,
> NM_DEVICE_TYPE_GSM,
> NM_DEVICE_TYPE_CDMA,
> - NM_DEVICE_TYPE_BT /* Bluetooth */
> + NM_DEVICE_TYPE_BT, /* Bluetooth */
> + NM_DEVICE_TYPE_OLPC_MESH
> } NMDeviceType;
>
> /* DEPRECATED TYPE NAMES */
> diff --git a/introspection/Makefile.am b/introspection/Makefile.am
> index cbd1578..c5b2e5a 100644
> --- a/introspection/Makefile.am
> +++ b/introspection/Makefile.am
> @@ -5,6 +5,7 @@ EXTRA_DIST = \
> vpn-errors.xml \
> nm-access-point.xml \
> nm-device-wifi.xml \
> + nm-device-olpc-mesh.xml \
> nm-device-ethernet.xml \
> nm-device-bt.xml \
> nm-device-cdma.xml \
> diff --git a/introspection/nm-device-olpc-mesh.xml b/introspection/nm-device-olpc-mesh.xml
> new file mode 100644
> index 0000000..7d326b6
> --- /dev/null
> +++ b/introspection/nm-device-olpc-mesh.xml
> @@ -0,0 +1,32 @@
> +<?xml version="1.0" encoding="UTF-8" ?>
> +
> +<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
> + <interface name="org.freedesktop.NetworkManager.Device.OlpcMesh">
> + <property name="HwAddress" type="s" access="read">
> + <tp:docstring>
> + The hardware address of the device.
> + </tp:docstring>
> + </property>
> + <property name="Companion" type="s" access="read">
> + <tp:docstring>
> + The object path of the companion device.
> + </tp:docstring>
> + </property>
> + <property name="ActiveChannel" type="o" access="read">
> + <tp:docstring>
> + The currently active channel.
> + </tp:docstring>
> + </property>
> +
> + <signal name="PropertiesChanged">
> + <arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
> + <tp:docstring>
> + A dictionary containing the FIXME: check changed parameters.
> + </tp:docstring>
> + </arg>
> + <tp:docstring>
> + Emitted when the wireless device's properties changed.
> + </tp:docstring>
> + </signal>
> + </interface>
> +</node>
> diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am
> index bc7befb..4004b10 100644
> --- a/libnm-util/Makefile.am
> +++ b/libnm-util/Makefile.am
> @@ -22,6 +22,7 @@ libnm_util_include_HEADERS = \
> nm-setting-serial.h \
> nm-setting-gsm.h \
> nm-setting-cdma.h \
> + nm-setting-olpc-mesh.h \
> nm-setting-wired.h \
> nm-setting-wireless.h \
> nm-setting-wireless-security.h \
> @@ -45,6 +46,7 @@ libnm_util_la_SOURCES= \
> nm-setting-serial.c \
> nm-setting-gsm.c \
> nm-setting-cdma.c \
> + nm-setting-olpc-mesh.c \
> nm-setting-wired.c \
> nm-setting-wireless.c \
> nm-setting-wireless-security.c \
> diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver
> index 4d372a7..289192d 100644
> --- a/libnm-util/libnm-util.ver
> +++ b/libnm-util/libnm-util.ver
> @@ -253,6 +253,10 @@ global:
> nm_setting_wireless_security_remove_pairwise;
> nm_setting_wireless_security_remove_proto;
> nm_setting_wireless_security_set_wep_key;
> + nm_setting_olpc_mesh_get_type;
> + nm_setting_olpc_mesh_get_ssid;
> + nm_setting_olpc_mesh_get_channel;
> + nm_setting_olpc_mesh_get_dhcp_anycast_address;
> nm_utils_deinit;
> nm_utils_escape_ssid;
> nm_utils_gvalue_hash_dup;
> diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c
> index e016023..15331c8 100644
> --- a/libnm-util/nm-connection.c
> +++ b/libnm-util/nm-connection.c
> @@ -41,6 +41,7 @@
> #include "nm-setting-wireless.h"
> #include "nm-setting-wireless-security.h"
> #include "nm-setting-vpn.h"
> +#include "nm-setting-olpc-mesh.h"
>
> #include "nm-setting-serial.h"
> #include "nm-setting-gsm.h"
> @@ -216,6 +217,11 @@ register_default_settings (void)
> NM_SETTING_WIRELESS_ERROR,
> 1);
>
> + register_one_setting (NM_SETTING_OLPC_MESH_SETTING_NAME,
> + NM_TYPE_SETTING_OLPC_MESH,
> + NM_SETTING_OLPC_MESH_ERROR,
> + 1);
> +
> register_one_setting (NM_SETTING_GSM_SETTING_NAME,
> NM_TYPE_SETTING_GSM,
> NM_SETTING_GSM_ERROR,
> diff --git a/libnm-util/nm-setting-olpc-mesh.c b/libnm-util/nm-setting-olpc-mesh.c
> new file mode 100644
> index 0000000..2202469
> --- /dev/null
> +++ b/libnm-util/nm-setting-olpc-mesh.c
> @@ -0,0 +1,265 @@
> +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
> +
> +/*
> + * Dan Williams <dcbw redhat com>
> + * Tambet Ingo <tambet gmail com>
> + * Sjoerd Simons <sjoerd simons collabora co uk>
> + * Daniel Drake <dsd laptop org>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, write to the
> + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
> + * Boston, MA 02110-1301 USA.
> + *
> + * (C) Copyright 2007 - 2008 Red Hat, Inc.
> + * (C) Copyright 2007 - 2008 Novell, Inc.
> + * (C) Copyright 2009 One Laptop per Child
> + */
> +
> +#include <string.h>
> +#include <netinet/ether.h>
> +#include <dbus/dbus-glib.h>
> +
> +#include "NetworkManager.h"
> +#include "nm-setting-olpc-mesh.h"
> +#include "nm-param-spec-specialized.h"
> +#include "nm-utils.h"
> +#include "nm-dbus-glib-types.h"
> +#include "nm-utils-private.h"
> +
> +GQuark
> +nm_setting_olpc_mesh_error_quark (void)
> +{
> + static GQuark quark;
> +
> + if (G_UNLIKELY (!quark))
> + quark = g_quark_from_static_string ("nm-setting-wireless-mesh-error-quark");
> + return quark;
> +}
> +
> +/* This should really be standard. */
> +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
> +
> +GType
> +nm_setting_olpc_mesh_error_get_type (void)
> +{
> + static GType etype = 0;
> +
> + if (etype == 0) {
> + static const GEnumValue values[] = {
> + /* Unknown error. */
> + ENUM_ENTRY (NM_SETTING_OLPC_MESH_ERROR_UNKNOWN, "UnknownError"),
> + /* The specified property was invalid. */
> + ENUM_ENTRY (NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY, "InvalidProperty"),
> + /* The specified property was missing and is required. */
> + ENUM_ENTRY (NM_SETTING_OLPC_MESH_ERROR_MISSING_PROPERTY, "MissingProperty"),
> + { 0, 0, 0 }
> + };
> + etype = g_enum_register_static ("NMSettingWirelessError", values);
> + }
> + return etype;
> +}
> +
> +static void nm_setting_olpc_mesh_init (NMSettingOlpcMesh *setting);
> +
> +G_DEFINE_TYPE (NMSettingOlpcMesh, nm_setting_olpc_mesh, NM_TYPE_SETTING)
> +
> +#define NM_SETTING_OLPC_MESH_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMeshPrivate))
> +
> +typedef struct {
> + GByteArray *ssid;
> + guint32 channel;
> + GByteArray *dhcp_anycast_addr;
> +} NMSettingOlpcMeshPrivate;
> +
> +enum {
> + PROP_0,
> + PROP_SSID,
> + PROP_CHANNEL,
> + PROP_DHCP_ANYCAST_ADDRESS,
> +
> + LAST_PROP
> +};
> +
> +static void
> +nm_setting_olpc_mesh_init (NMSettingOlpcMesh *setting)
> +{
> + g_object_set (setting, NM_SETTING_NAME, NM_SETTING_OLPC_MESH_SETTING_NAME, NULL);
> +}
> +
> +const GByteArray *
> +nm_setting_olpc_mesh_get_ssid (NMSettingOlpcMesh *setting)
> +{
> + g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (setting), NULL);
> +
> + return NM_SETTING_OLPC_MESH_GET_PRIVATE (setting)->ssid;
> +}
> +
> +guint32
> +nm_setting_olpc_mesh_get_channel (NMSettingOlpcMesh *setting)
> +{
> + g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (setting), 0);
> +
> + return NM_SETTING_OLPC_MESH_GET_PRIVATE (setting)->channel;
> +}
> +
> +const GByteArray *
> +nm_setting_olpc_mesh_get_dhcp_anycast_address (NMSettingOlpcMesh *setting)
> +{
> + g_return_val_if_fail (NM_IS_SETTING_OLPC_MESH (setting), NULL);
> +
> + return NM_SETTING_OLPC_MESH_GET_PRIVATE (setting)->dhcp_anycast_addr;
> +}
> +
> +static gboolean
> +verify (NMSetting *setting, GSList *all_settings, GError **error)
> +{
> + NMSettingOlpcMeshPrivate *priv = NM_SETTING_OLPC_MESH_GET_PRIVATE (setting);
> +
> + if (!priv->ssid) {
> + g_set_error (error,
> + NM_SETTING_OLPC_MESH_ERROR,
> + NM_SETTING_OLPC_MESH_ERROR_MISSING_PROPERTY,
> + NM_SETTING_OLPC_MESH_SSID);
> + return FALSE;
> + }
> +
> + if (!priv->ssid->len || priv->ssid->len > 32) {
> + g_set_error (error,
> + NM_SETTING_OLPC_MESH_ERROR,
> + NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY,
> + NM_SETTING_OLPC_MESH_SSID);
> + return FALSE;
> + }
> +
> + if (priv->channel == 0 || priv->channel > 13) {
> + g_set_error (error,
> + NM_SETTING_OLPC_MESH_ERROR,
> + NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY,
> + NM_SETTING_OLPC_MESH_CHANNEL);
> + return FALSE;
> + }
> +
> + if (priv->dhcp_anycast_addr && priv->dhcp_anycast_addr->len != ETH_ALEN) {
> + g_set_error (error,
> + NM_SETTING_OLPC_MESH_ERROR,
> + NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY,
> + NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS);
> + return FALSE;
> + }
> +
> + return TRUE;
> +}
> +
> +static void
> +finalize (GObject *object)
> +{
> + NMSettingOlpcMeshPrivate *priv = NM_SETTING_OLPC_MESH_GET_PRIVATE (object);
> +
> + if (priv->ssid)
> + g_byte_array_free (priv->ssid, TRUE);
> + if (priv->dhcp_anycast_addr)
> + g_byte_array_free (priv->dhcp_anycast_addr, TRUE);
> +
> + G_OBJECT_CLASS (nm_setting_olpc_mesh_parent_class)->finalize (object);
> +}
> +
> +static void
> +set_property (GObject *object, guint prop_id,
> + const GValue *value, GParamSpec *pspec)
> +{
> + NMSettingOlpcMeshPrivate *priv = NM_SETTING_OLPC_MESH_GET_PRIVATE (object);
> +
> + switch (prop_id) {
> + case PROP_SSID:
> + if (priv->ssid)
> + g_byte_array_free (priv->ssid, TRUE);
> + priv->ssid = g_value_dup_boxed (value);
> + break;
> + case PROP_CHANNEL:
> + priv->channel = g_value_get_uint (value);
> + break;
> + case PROP_DHCP_ANYCAST_ADDRESS:
> + if (priv->dhcp_anycast_addr)
> + g_byte_array_free (priv->dhcp_anycast_addr, TRUE);
> + priv->dhcp_anycast_addr = g_value_dup_boxed (value);
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
> + break;
> + }
> +}
> +
> +static void
> +get_property (GObject *object, guint prop_id,
> + GValue *value, GParamSpec *pspec)
> +{
> + NMSettingOlpcMesh *setting = NM_SETTING_OLPC_MESH (object);
> +
> + switch (prop_id) {
> + case PROP_SSID:
> + g_value_set_boxed (value, nm_setting_olpc_mesh_get_ssid (setting));
> + break;
> + case PROP_CHANNEL:
> + g_value_set_uint (value, nm_setting_olpc_mesh_get_channel (setting));
> + break;
> + case PROP_DHCP_ANYCAST_ADDRESS:
> + g_value_set_boxed (value, nm_setting_olpc_mesh_get_dhcp_anycast_address (setting));
> + break;
> + default:
> + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
> + break;
> + }
> +}
> +
> +static void
> +nm_setting_olpc_mesh_class_init (NMSettingOlpcMeshClass *setting_class)
> +{
> + GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
> + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
> +
> + g_type_class_add_private (setting_class, sizeof (NMSettingOlpcMeshPrivate));
> +
> + /* virtual methods */
> + object_class->set_property = set_property;
> + object_class->get_property = get_property;
> + object_class->finalize = finalize;
> + parent_class->verify = verify;
> +
> + /* Properties */
> + g_object_class_install_property
> + (object_class, PROP_SSID,
> + _nm_param_spec_specialized (NM_SETTING_OLPC_MESH_SSID,
> + "SSID",
> + "SSID",
> + DBUS_TYPE_G_UCHAR_ARRAY,
> + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
> +
> + g_object_class_install_property
> + (object_class, PROP_CHANNEL,
> + g_param_spec_uint (NM_SETTING_OLPC_MESH_CHANNEL,
> + "Channel",
> + "Channel",
> + 0, G_MAXUINT32, 0,
> + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | NM_SETTING_PARAM_SERIALIZE));
> +
> +
> + g_object_class_install_property
> + (object_class, PROP_DHCP_ANYCAST_ADDRESS,
> + _nm_param_spec_specialized (NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS,
> + "Anycast DHCP MAC address",
> + "Anycast DHCP MAC address",
> + DBUS_TYPE_G_UCHAR_ARRAY,
> + G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
> +
> +}
> diff --git a/libnm-util/nm-setting-olpc-mesh.h b/libnm-util/nm-setting-olpc-mesh.h
> new file mode 100644
> index 0000000..173853d
> --- /dev/null
> +++ b/libnm-util/nm-setting-olpc-mesh.h
> @@ -0,0 +1,52 @@
> +/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
> +
> +#ifndef NM_SETTING_OLPC_MESH_H
> +#define NM_SETTING_OLPC_MESH_H
> +
> +#include <nm-setting.h>
> +
> +G_BEGIN_DECLS
> +
> +#define NM_TYPE_SETTING_OLPC_MESH (nm_setting_olpc_mesh_get_type ())
> +#define NM_SETTING_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMesh))
> +#define NM_SETTING_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMeshClass))
> +#define NM_IS_SETTING_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_OLPC_MESH))
> +#define NM_IS_SETTING_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SETTING_OLPC_MESH))
> +#define NM_SETTING_OLPC_MESH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_OLPC_MESH, NMSettingOlpcMeshClass))
> +
> +#define NM_SETTING_OLPC_MESH_SETTING_NAME "802-11-olpc-mesh"
> +
> +typedef enum
> +{
> + NM_SETTING_OLPC_MESH_ERROR_UNKNOWN = 0,
> + NM_SETTING_OLPC_MESH_ERROR_INVALID_PROPERTY,
> + NM_SETTING_OLPC_MESH_ERROR_MISSING_PROPERTY
> +} NMSettingOlpcMeshError;
> +
> +#define NM_TYPE_SETTING_OLPC_MESH_ERROR (nm_setting_olpc_mesh_error_get_type ())
> +GType nm_setting_olpc_mesh_error_get_type (void);
> +
> +#define NM_SETTING_OLPC_MESH_ERROR nm_setting_olpc_mesh_error_quark ()
> +GQuark nm_setting_olpc_mesh_error_quark (void);
> +
> +#define NM_SETTING_OLPC_MESH_SSID "ssid"
> +#define NM_SETTING_OLPC_MESH_CHANNEL "channel"
> +#define NM_SETTING_OLPC_MESH_DHCP_ANYCAST_ADDRESS "dhcp-anycast-address"
> +
> +typedef struct {
> + NMSetting parent;
> +} NMSettingOlpcMesh;
> +
> +typedef struct {
> + NMSettingClass parent;
> +} NMSettingOlpcMeshClass;
> +
> +GType nm_setting_olpc_mesh_get_type (void);
> +
> +const GByteArray *nm_setting_olpc_mesh_get_ssid (NMSettingOlpcMesh *setting);
> +guint32 nm_setting_olpc_mesh_get_channel (NMSettingOlpcMesh *setting);
> +const GByteArray *nm_setting_olpc_mesh_get_dhcp_anycast_address (NMSettingOlpcMesh *setting);
> +
> +G_END_DECLS
> +
> +#endif /* NM_SETTING_OLPC_MESH_H */
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 79c2a2e..d37fbea 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -68,6 +68,8 @@ NetworkManager_SOURCES = \
> nm-device-ethernet.h \
> nm-device-wifi.c \
> nm-device-wifi.h \
> + nm-device-olpc-mesh.c \
> + nm-device-olpc-mesh.h \
> nm-device-bt.c \
> nm-device-bt.h \
> NetworkManagerAP.c \
> @@ -126,6 +128,9 @@ nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml
> nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml
> dbus-binding-tool --prefix=nm_device_bt --mode=glib-server --output=$@ $<
>
> +nm-device-olpc-mesh-glue.h: $(top_srcdir)/introspection/nm-device-olpc-mesh.xml
> + dbus-binding-tool --prefix=nm_device_olpc_mesh --mode=glib-server --output=$@ $<
> +
> nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml
> dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $<
>
> @@ -141,6 +146,7 @@ BUILT_SOURCES = \
> nm-device-interface-glue.h \
> nm-device-ethernet-glue.h \
> nm-device-wifi-glue.h \
> + nm-device-olpc-mesh-glue.h \
> nm-device-bt-glue.h \
> nm-ip4-config-glue.h \
> nm-active-connection-glue.h \
> diff --git a/src/nm-device-olpc-mesh.c b/src/nm-device-olpc-mesh.c
> new file mode 100644
> index 0000000..bd65188
> --- /dev/null
> +++ b/src/nm-device-olpc-mesh.c
> @@ -0,0 +1,986 @@
> +/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + *
> + * (C) Copyright 2005 - 2008 Red Hat, Inc.
> + * (C) Copyright 2008 Collabora Ltd.
> + * (C) Copyright 2009 One Laptop per Child
> + */
> +
> +#include <glib.h>
> +#include <glib/gi18n.h>
> +#include <dbus/dbus.h>
> +#include <netinet/in.h>
> +#include <string.h>
> +#include <net/ethernet.h>
> +#include <iwlib.h>
> +#include <sys/stat.h>
> +#include <sys/wait.h>
> +#include <signal.h>
> +#include <unistd.h>
> +
> +#include "nm-device.h"
> +#include "nm-device-wifi.h"
> +#include "nm-device-olpc-mesh.h"
> +#include "nm-device-interface.h"
> +#include "nm-device-private.h"
> +#include "nm-utils.h"
> +#include "NetworkManagerUtils.h"
> +#include "NetworkManagerPolicy.h"
> +#include "nm-activation-request.h"
> +#include "nm-properties-changed-signal.h"
> +#include "nm-setting-connection.h"
> +#include "nm-setting-olpc-mesh.h"
> +#include "NetworkManagerSystem.h"
> +#include "nm-manager.h"
> +
> +#include "nm-device-olpc-mesh-glue.h"
> +
> +static void nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self,
> + const GByteArray * ssid);
> +
> +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_HW_ADDRESS,
> + PROP_COMPANION,
> + PROP_ACTIVE_CHANNEL,
> + PROP_IFINDEX,
> +
> + LAST_PROP
> +};
> +
> +enum {
> + PROPERTIES_CHANGED,
> +
> + LAST_SIGNAL
> +};
> +
> +static guint signals[LAST_SIGNAL] = { 0 };
> +
> +typedef enum
> +{
> + NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH = 0,
> + NM_OLPC_MESH_ERROR_CONNECTION_INVALID,
> + NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE,
> +} NMOlpcMeshError;
> +
> +#define NM_OLPC_MESH_ERROR (nm_olpc_mesh_error_quark ())
> +#define NM_TYPE_OLPC_MESH_ERROR (nm_olpc_mesh_error_get_type ())
> +
> +
> +struct _NMDeviceOlpcMeshPrivate
> +{
> + gboolean dispose_has_run;
> +
> + struct ether_addr hw_addr;
> + guint32 ifindex;
> +
> + GByteArray * ssid;
> +
> + gint8 num_freqs;
> + guint32 freqs[IW_MAX_FREQUENCIES];
> +
> + guint8 we_version;
> + gboolean up;
> +
> + NMDevice * companion;
> + gboolean stage1_waiting;
> + guint device_added_cb;
> +};
> +
> +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;
> +}
> +
> +/* This should really be standard. */
> +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
> +
> +static GType
> +nm_olpc_mesh_error_get_type (void)
> +{
> + static GType etype = 0;
> +
> + if (etype == 0) {
> + static const GEnumValue values[] = {
> + /* Connection was not a wireless connection. */
> + ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_NOT_MESH, "ConnectionNotMesh"),
> + /* Connection was not a valid wireless connection. */
> + ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_INVALID, "ConnectionInvalid"),
> + /* Connection does not apply to this device. */
> + ENUM_ENTRY (NM_OLPC_MESH_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"),
> + { 0, 0, 0 }
> + };
> + etype = g_enum_register_static ("NMOlpcMeshError", values);
> + }
> + return etype;
> +}
> +
> +static guint32
> +real_get_generic_capabilities (NMDevice *dev)
> +{
> + int fd;
> + guint32 caps = NM_DEVICE_CAP_NONE;
> + struct iw_range range;
> + struct iwreq wrq;
> + const char *iface = nm_device_get_iface (dev);
> +
> + /* Check for Wireless Extensions support >= 16 for wireless devices */
> +
> + fd = socket (PF_INET, SOCK_DGRAM, 0);
> + if (fd < 0) {
> + nm_warning ("couldn't open control socket.");
> + goto out;
> + }
> +
> + memset (&wrq, 0, sizeof (struct iwreq));
> + memset (&range, 0, sizeof (struct iw_range));
> + strncpy (wrq.ifr_name, iface, IFNAMSIZ);
> + wrq.u.data.pointer = (caddr_t) ⦥
> + wrq.u.data.length = sizeof (struct iw_range);
> +
> + if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0) {
> + nm_warning ("couldn't get driver range information.");
> + goto out;
> + }
> +
> + if ((wrq.u.data.length < 300) || (range.we_version_compiled < 16)) {
> + nm_warning ("%s: driver's Wireless Extensions version (%d) is too old.",
> + iface, range.we_version_compiled);
> + goto out;
> + } else {
> + caps |= NM_DEVICE_CAP_NM_SUPPORTED;
> + }
> +
> +out:
> + if (fd >= 0)
> + close (fd);
> + return caps;
> +}
> +
> +static void
> +nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self)
> +{
> + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
> +
> + priv->dispose_has_run = FALSE;
> + priv->we_version = 0;
> + priv->companion = NULL;
> + priv->stage1_waiting = FALSE;
> +
> + memset (&(priv->hw_addr), 0, sizeof (struct ether_addr));
> +}
> +
> +static guint32 iw_freq_to_uint32 (struct iw_freq *freq)
> +{
> + if (freq->e == 0) {
> + /* Some drivers report channel not frequency. Convert to a
> + * frequency; but this assumes that the device is in b/g mode.
> + */
> + if ((freq->m >= 1) && (freq->m <= 13))
> + return 2407 + (5 * freq->m);
> + else if (freq->m == 14)
> + return 2484;
> + }
> +
> + return (guint32) (((double) freq->m) * pow (10, freq->e) / 1000000);
> +}
> +
> +
> +/* Until a new wireless-tools comes out that has the defs and the structure,
> + * need to copy them here.
> + */
> +/* Scan capability flags - in (struct iw_range *)->scan_capa */
> +#define NM_IW_SCAN_CAPA_NONE 0x00
> +#define NM_IW_SCAN_CAPA_ESSID 0x01
> +
> +struct iw_range_with_scan_capa
> +{
> + guint32 throughput;
> + guint32 min_nwid;
> + guint32 max_nwid;
> + guint16 old_num_channels;
> + guint8 old_num_frequency;
> +
> + guint8 scan_capa;
> +/* don't need the rest... */
> +};
> +
> +
> +
> +
> +static GObject*
> +constructor (GType type,
> + guint n_construct_params,
> + GObjectConstructParam *construct_params)
> +{
> + GObject *object;
> + GObjectClass *klass;
> + NMDeviceOlpcMesh *self;
> + NMDeviceOlpcMeshPrivate *priv;
> + const char *iface;
> + int fd;
> + struct iw_range range;
> + struct iwreq wrq;
> + int i;
> +
> + 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);
> +
> + iface = nm_device_get_iface (NM_DEVICE (self));
> + fd = socket (PF_INET, SOCK_DGRAM, 0);
> + if (fd < 0)
> + goto error;
> +
> + memset (&wrq, 0, sizeof (struct iwreq));
> + memset (&range, 0, sizeof (struct iw_range));
> + strncpy (wrq.ifr_name, iface, IFNAMSIZ);
> + wrq.u.data.pointer = (caddr_t) ⦥
> + wrq.u.data.length = sizeof (struct iw_range);
> +
> + if (ioctl (fd, SIOCGIWRANGE, &wrq) < 0)
> + goto error;
> +
> + priv->num_freqs = MIN (range.num_frequency, IW_MAX_FREQUENCIES);
> + for (i = 0; i < priv->num_freqs; i++)
> + priv->freqs[i] = iw_freq_to_uint32 (&range.freq[i]);
> +
> + priv->we_version = range.we_version_compiled;
> +
> + close (fd);
> +
> + /* shorter timeout for mesh connectivity */
> + nm_device_set_dhcp_timeout (NM_DEVICE (self), 20);
> + return object;
> +
> +error:
> + if (fd >= 0)
> + close (fd);
> + g_object_unref (object);
> + return NULL;
> +}
> +
> +static gboolean
> +real_hw_is_up (NMDevice *device)
> +{
> + return nm_system_device_is_up (device);
> +}
> +
> +static gboolean
> +real_hw_bring_up (NMDevice *dev, gboolean *no_firmware)
> +{
> + return nm_system_device_set_up_down (dev, TRUE, no_firmware);
> +}
> +
> +static void
> +real_hw_take_down (NMDevice *dev)
> +{
> + nm_system_device_set_up_down (dev, FALSE, NULL);
> +}
> +
> +static gboolean
> +real_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
> +real_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
> +real_take_down (NMDevice *dev)
> +{
> + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev);
> +
> + device_cleanup (self);
> +}
> +
> +static gboolean
> +real_check_connection_compatible (NMDevice *device,
> + NMConnection *connection,
> + GError **error)
> +{
> + NMSettingConnection *s_con;
> + NMSettingOlpcMesh *s_mesh;
> +
> + s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_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_SETTING_OLPC_MESH (nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH));
> + 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;
> +}
> +
> +/*
> + * nm_device_olpc_mesh_get_address
> + *
> + * Get a device's hardware address
> + *
> + */
> +static void
> +nm_device_olpc_mesh_get_address (NMDeviceOlpcMesh *self,
> + struct ether_addr *addr)
> +{
> + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
> + g_return_if_fail (self != NULL);
> + g_return_if_fail (addr != NULL);
> +
> + memcpy (addr, &(priv->hw_addr), sizeof (struct ether_addr));
> +}
> +
> +static int
> +create_socket_with_request (NMDevice *self, struct iwreq *req)
> +{
> + int sk;
> + const char * iface;
> +
> + g_return_val_if_fail (self != NULL, -1);
> +
> + sk = socket (AF_INET, SOCK_DGRAM, 0);
> + if (!sk) {
> + nm_error ("Couldn't create socket: %d.", errno);
> + return -1;
> + }
> +
> + memset (req, 0, sizeof (struct iwreq));
> + iface = nm_device_get_iface (NM_DEVICE (self));
> + strncpy (req->ifr_name, iface, IFNAMSIZ);
> +
> + return sk;
> +}
> +
> +static guint32
> +nm_device_olpc_mesh_get_channel (NMDeviceOlpcMesh *self)
> +{
> + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
> + int sk;
> + struct iwreq req;
> + int ret = 0;
> + int i;
> + guint32 freq;
> +
> + sk = create_socket_with_request (NM_DEVICE (self), &req);
> + if (sk == -1)
> + return 0;
> +
> + if ((ioctl (sk, SIOCGIWFREQ, &req)) != 0) {
> + nm_warning ("%s: failed to get channel (errno: %d))",
> + nm_device_get_iface (NM_DEVICE (self)), errno);
> + goto out;
> + }
> +
> + freq = iw_freq_to_uint32 (&req.u.freq);
> +
> + for (i = 0 ; i < priv->num_freqs; i++) {
> + if (freq == priv->freqs[i])
> + break;
> + }
> + if (i < priv->num_freqs)
> + ret = i + 1;
> +
> +out:
> + if (sk >= 0)
> + close (sk);
> + return ret;
> +}
> +
> +static void
> +nm_device_olpc_mesh_set_channel (NMDeviceOlpcMesh *self, guint32 channel)
> +{
> + int sk;
> + struct iwreq req;
> +
> + if (nm_device_olpc_mesh_get_channel (self) == channel)
> + return;
> +
> + sk = create_socket_with_request (NM_DEVICE (self), &req);
> + if (sk < 0)
> + return;
> +
> + if (channel > 0) {
> + req.u.freq.flags = IW_FREQ_FIXED;
> + req.u.freq.e = 0;
> + req.u.freq.m = channel;
> + }
> +
> + if (ioctl (sk, SIOCSIWFREQ, &req) != 0)
> + nm_warning ("%s: failed to set to channel %d (errno: %d))",
> + nm_device_get_iface (NM_DEVICE (self)), channel, errno);
> + else
> + g_object_notify (G_OBJECT (self), NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL);
> +
> + close (sk);
> +}
> +
> +static void
> +nm_device_olpc_mesh_set_ssid (NMDeviceOlpcMesh *self,
> + const GByteArray * ssid)
> +{
> + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
> + int sk;
> + struct iwreq wrq;
> + const char * iface;
> + guint32 len = 0;
> + char buf[IW_ESSID_MAX_SIZE + 1];
> +
> + g_return_if_fail (self != NULL);
> +
> + sk = socket (AF_INET, SOCK_DGRAM, 0);
> + if (!sk) {
> + nm_error ("Couldn't create socket: %d.", errno);
> + return;
> + }
> +
> + iface = nm_device_get_iface (NM_DEVICE (self));
> +
> + memset (buf, 0, sizeof (buf));
> + if (ssid) {
> + len = ssid->len;
> + memcpy (buf, ssid->data, MIN (sizeof (buf) - 1, len));
> + }
> + wrq.u.essid.pointer = (caddr_t) buf;
> +
> + if (priv->we_version < 21) {
> + /* For historic reasons, set SSID length to include one extra
> + * character, C string nul termination, even though SSID is
> + * really an octet string that should not be presented as a C
> + * string. Some Linux drivers decrement the length by one and
> + * can thus end up missing the last octet of the SSID if the
> + * length is not incremented here. WE-21 changes this to
> + * explicitly require the length _not_ to include nul
> + * termination. */
> + if (len)
> + len++;
> + }
> + wrq.u.essid.length = len;
> + wrq.u.essid.flags = (len > 0) ? 1 : 0; /* 1=enable SSID, 0=disable/any */
> +
> + strncpy (wrq.ifr_name, iface, IFNAMSIZ);
> +
> + if (ioctl (sk, SIOCSIWESSID, &wrq) < 0) {
> + if (errno != ENODEV) {
> + nm_warning ("error setting SSID to '%s' for device %s: %s",
> + ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(null)",
> + iface, strerror (errno));
> + }
> + }
> +
> + close (sk);
> +}
> +
> +
> +guint32
> +nm_device_olpc_mesh_get_ifindex (NMDeviceOlpcMesh *self)
> +{
> + g_return_val_if_fail (self != NULL, FALSE);
> +
> + return NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->ifindex;
> +}
> +
> +/****************************************************************************/
> +
> +static void
> +real_update_hw_address (NMDevice *dev)
> +{
> + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev);
> + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
> + struct ifreq req;
> + int ret, fd;
> +
> + fd = socket (PF_INET, SOCK_DGRAM, 0);
> + if (fd < 0) {
> + g_warning ("could not open control socket.");
> + return;
> + }
> +
> + memset (&req, 0, sizeof (struct ifreq));
> + strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
> + ret = ioctl (fd, SIOCGIFHWADDR, &req);
> + if (ret) {
> + nm_warning ("%s: (%s) error getting hardware address: %d",
> + __func__, nm_device_get_iface (dev), errno);
> + goto out;
> + }
> +
> + if (memcmp (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr))) {
> + memcpy (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr));
> + g_object_notify (G_OBJECT (dev), NM_DEVICE_OLPC_MESH_HW_ADDRESS);
> + }
> +
> +out:
> + close (fd);
> +}
> +
> +
> +static NMActStageReturn
> +real_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_warning ("disconnecting companion device");
> + nm_device_state_changed (NM_DEVICE (priv->companion),
> + NM_DEVICE_STATE_DISCONNECTED,
> + NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED);
> + nm_warning ("companion disconnected");
> + }
> +
> +
> + /* 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 NMActStageReturn
> +real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason)
> +{
> + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev);
> + NMConnection *connection;
> + NMSettingOlpcMesh *s_mesh;
> + NMActRequest *req;
> + guint32 channel;
> + const GByteArray *anycast_addr_array;
> + guint8 *anycast_addr = NULL;
> +
> + req = nm_device_get_act_request (dev);
> + g_assert (req);
> +
> + connection = nm_act_request_get_connection (req);
> + g_assert (connection);
> +
> + s_mesh = NM_SETTING_OLPC_MESH (nm_connection_get_setting (connection,
> + NM_TYPE_SETTING_OLPC_MESH));
> + g_assert (s_mesh);
> +
> + channel = nm_setting_olpc_mesh_get_channel (s_mesh);
> + if (channel != 0)
> + nm_device_olpc_mesh_set_channel (self, channel);
> + nm_device_olpc_mesh_set_ssid (self, 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 NMActStageReturn
> +real_act_stage4_ip_config_timeout (NMDevice *dev,
> + NMIP4Config **config,
> + NMDeviceStateReason *reason)
> +{
> + return NM_ACT_STAGE_RETURN_FAILURE;
> +}
> +
> +
> +static void
> +nm_device_olpc_mesh_dispose (GObject *object)
> +{
> + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object);
> + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
> +
> + if (priv->dispose_has_run) {
> + G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object);
> + return;
> + }
> +
> + priv->dispose_has_run = TRUE;
> +
> + device_cleanup (self);
> +
> + if (priv->device_added_cb != 0)
> + g_source_remove (priv->device_added_cb);
> +
> + priv->device_added_cb = 0;
> +
> + 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);
> + struct ether_addr hw_addr;
> +
> + switch (prop_id) {
> + case PROP_HW_ADDRESS:
> + nm_device_olpc_mesh_get_address (device, &hw_addr);
> + g_value_take_string (value, nm_ether_ntop (&hw_addr));
> + break;
> + case PROP_COMPANION:
> + g_value_set_string (value, nm_device_get_path (priv->companion));
> + break;
> + case PROP_ACTIVE_CHANNEL:
> + g_value_set_uint (value, nm_device_olpc_mesh_get_channel (device));
> + break;
> + case PROP_IFINDEX:
> + g_value_set_uint (value, nm_device_olpc_mesh_get_ifindex (device));
> + 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)
> +{
> + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (object);
> +
> + switch (prop_id) {
> + case PROP_IFINDEX:
> + /* construct-only */
> + priv->ifindex = g_value_get_uint (value);
> + break;
> + 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 = nm_device_olpc_mesh_dispose;
> +
> + parent_class->get_type_capabilities = NULL;
> + parent_class->get_generic_capabilities = real_get_generic_capabilities;
> + parent_class->hw_is_up = real_hw_is_up;
> + parent_class->hw_bring_up = real_hw_bring_up;
> + parent_class->hw_take_down = real_hw_take_down;
> + parent_class->is_up = real_is_up;
> + parent_class->bring_up = real_bring_up;
> + parent_class->take_down = real_take_down;
> + parent_class->update_hw_address = real_update_hw_address;
> + parent_class->check_connection_compatible = real_check_connection_compatible;
> +
> + parent_class->act_stage1_prepare = real_act_stage1_prepare;
> + parent_class->act_stage2_config = real_act_stage2_config;
> + parent_class->act_stage4_ip_config_timeout = real_act_stage4_ip_config_timeout;
> +
> + /* Properties */
> + g_object_class_install_property
> + (object_class, PROP_HW_ADDRESS,
> + g_param_spec_string (NM_DEVICE_OLPC_MESH_HW_ADDRESS,
> + "MAC Address",
> + "Hardware MAC address",
> + NULL,
> + G_PARAM_READABLE));
> + g_object_class_install_property
> + (object_class, PROP_COMPANION,
> + g_param_spec_string (NM_DEVICE_OLPC_MESH_COMPANION,
> + "Companion device",
> + "Companion device object path",
> + NULL,
> + 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));
> +
> + g_object_class_install_property (object_class, PROP_IFINDEX,
> + g_param_spec_uint (NM_DEVICE_OLPC_MESH_IFINDEX,
> + "Ifindex",
> + "Interface index",
> + 0, G_MAXUINT32, 0,
> + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
> +
> + signals[PROPERTIES_CHANGED] =
> + nm_properties_changed_signal_new (object_class,
> + G_STRUCT_OFFSET (NMDeviceOlpcMeshClass, properties_changed));
> +
> + dbus_g_object_type_install_info (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_debug ("disconnecting mesh due to companion connectivity");
> + 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;
> +
> + g_object_get (G_OBJECT (self), NM_DEVICE_INTERFACE_STATE, &state, NULL);
> +
> + /* Don't allow the companion to scan while configure 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;
> +
> + g_object_get (G_OBJECT (self), NM_DEVICE_INTERFACE_STATE, &state, NULL);
> +
> + /* 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);
> + struct ether_addr their_addr;
> +
> + if (!NM_IS_DEVICE_WIFI (other))
> + return FALSE;
> +
> + nm_device_wifi_get_address (NM_DEVICE_WIFI (other), &their_addr);
> +
> + if (memcmp (priv->hw_addr.ether_addr_octet,
> + their_addr.ether_addr_octet, ETH_ALEN) != 0) {
> + return FALSE;
> + }
> +
> + /* FIXME detect when our companion leaves */
> + priv->companion = other;
> +
> + g_source_remove (priv->device_added_cb);
> + priv->device_added_cb = 0;
> +
> + nm_device_state_changed (NM_DEVICE (self),
> + NM_DEVICE_STATE_DISCONNECTED,
> + NM_DEVICE_STATE_REASON_NONE);
> +
> + nm_debug ("Found companion device: %s", nm_device_get_iface (other));
> +
> + g_signal_connect (G_OBJECT (other), "state-changed",
> + G_CALLBACK (companion_state_changed_cb), self);
> + g_signal_connect (G_OBJECT (other), "notify::scanning",
> + G_CALLBACK (companion_notify_cb), self);
> + g_signal_connect (G_OBJECT (other), "scanning-allowed",
> + G_CALLBACK (companion_scan_allowed_cb), self);
> + g_signal_connect (G_OBJECT (other), "autoconnect-allowed",
> + G_CALLBACK (companion_autoconnect_allowed_cb), self);
> +
> + return TRUE;
> +}
> +
> +static void
> +device_added_cb (NMDevice *other, gpointer user_data)
> +{
> + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data);
> +
> + is_companion (self, other);
> +}
> +
> +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_cb != 0)
> + return FALSE;
> +
> + manager = nm_manager_get (NULL, NULL);
> +
> + priv->device_added_cb = g_signal_connect (manager, "device-added",
> + G_CALLBACK (device_added_cb), self);
> +
> + list = nm_manager_get_devices (manager);
> + for (; list != NULL ; list = list->next)
> + if (is_companion (self, NM_DEVICE (list->data)))
> + break;
> +
> + g_object_unref (manager);
> +
> + return FALSE;
> +}
> +
> +static void
> +state_changed_cb (NMDevice *device, NMDeviceState state, gpointer user_data)
> +{
> + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device);
> +
> + switch (state) {
> + case NM_DEVICE_STATE_UNMANAGED:
> + break;
> + case NM_DEVICE_STATE_UNAVAILABLE:
> + /* If transitioning to UNAVAILBLE 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,
> + guint32 ifindex)
> +{
> + GObject *obj;
> +
> + g_return_val_if_fail (udi != NULL, NULL);
> + g_return_val_if_fail (iface != NULL, NULL);
> + g_return_val_if_fail (driver != NULL, NULL);
> +
> + obj = g_object_new (NM_TYPE_DEVICE_OLPC_MESH,
> + NM_DEVICE_INTERFACE_UDI, udi,
> + NM_DEVICE_INTERFACE_IFACE, iface,
> + NM_DEVICE_INTERFACE_DRIVER, driver,
> + NM_DEVICE_OLPC_MESH_IFINDEX, ifindex,
> + NM_DEVICE_INTERFACE_TYPE_DESC, "802.11 OLPC Mesh",
> + NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_OLPC_MESH,
> + NULL);
> + if (obj == NULL)
> + return NULL;
> +
> + g_signal_connect (obj, "state-changed",
> + G_CALLBACK (state_changed_cb),
> + NULL);
> +
> + return NM_DEVICE (obj);
> +}
> diff --git a/src/nm-device-olpc-mesh.h b/src/nm-device-olpc-mesh.h
> new file mode 100644
> index 0000000..f26085d
> --- /dev/null
> +++ b/src/nm-device-olpc-mesh.h
> @@ -0,0 +1,85 @@
> +/* -*- 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + *
> + * (C) Copyright 2005 Red Hat, Inc.
> + * (C) Copyright 2008 Collabora Ltd.
> + * (C) Copyright 2009 One Laptop per Child
> + */
> +
> +#ifndef NM_DEVICE_OLPC_MESH_H
> +#define NM_DEVICE_OLPC_MESH_H
> +
> +#include <glib-object.h>
> +#include <dbus/dbus.h>
> +
> +#include "nm-device.h"
> +
> +G_BEGIN_DECLS
> +
> +#define NM_TYPE_DEVICE_OLPC_MESH (nm_device_olpc_mesh_get_type ())
> +#define NM_DEVICE_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMesh))
> +#define NM_DEVICE_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass))
> +#define NM_IS_DEVICE_OLPC_MESH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_OLPC_MESH))
> +#define NM_IS_DEVICE_OLPC_MESH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_OLPC_MESH))
> +#define NM_DEVICE_OLPC_MESH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_OLPC_MESH, NMDeviceOlpcMeshClass))
> +
> +#define NM_DEVICE_OLPC_MESH_HW_ADDRESS "hw-address"
> +#define NM_DEVICE_OLPC_MESH_COMPANION "companion"
> +#define NM_DEVICE_OLPC_MESH_BITRATE "bitrate"
> +#define NM_DEVICE_OLPC_MESH_ACTIVE_CHANNEL "active-channel"
> +#define NM_DEVICE_OLPC_MESH_IFINDEX "ifindex"
> +
> +#ifndef NM_DEVICE_OLPC_MESH_DEFINED
> +#define NM_DEVICE_OLPC_MESH_DEFINED
> +typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh;
> +#endif
> +
> +typedef struct _NMDeviceOlpcMeshClass NMDeviceOlpcMeshClass;
> +typedef struct _NMDeviceOlpcMeshPrivate NMDeviceOlpcMeshPrivate;
> +
> +struct _NMDeviceOlpcMesh
> +{
> + NMDevice parent;
> +};
> +
> +struct _NMDeviceOlpcMeshClass
> +{
> + NMDeviceClass parent;
> +
> + /* Signals */
> + void (*properties_changed) (NMDeviceOlpcMesh *device,
> + GHashTable *properties);
> +};
> +
> +
> +GType nm_device_olpc_mesh_get_type (void);
> +
> +NMDevice *nm_device_olpc_mesh_new (const char *udi,
> + const char *iface,
> + const char *driver,
> + guint32 ifindex);
> +
> +guint32 nm_device_olpc_mesh_get_ifindex (NMDeviceOlpcMesh *self);
> +
> +G_END_DECLS
> +
> +#endif /* NM_DEVICE_OLPC_MESH_H */
> diff --git a/src/nm-manager.c b/src/nm-manager.c
> index ff205b7..48705ac 100644
> --- a/src/nm-manager.c
> +++ b/src/nm-manager.c
> @@ -35,6 +35,7 @@
> #include "nm-device-private.h"
> #include "nm-device-ethernet.h"
> #include "nm-device-wifi.h"
> +#include "nm-device-olpc-mesh.h"
> #include "NetworkManagerSystem.h"
> #include "nm-properties-changed-signal.h"
> #include "nm-setting-bluetooth.h"
> @@ -1368,6 +1369,8 @@ find_device_by_ifindex (NMManager *self, guint32 ifindex)
> candidate_idx = nm_device_ethernet_get_ifindex (NM_DEVICE_ETHERNET (device));
> else if (NM_IS_DEVICE_WIFI (device))
> candidate_idx = nm_device_wifi_get_ifindex (NM_DEVICE_WIFI (device));
> + else if (NM_IS_DEVICE_OLPC_MESH (device))
> + candidate_idx = nm_device_olpc_mesh_get_ifindex (NM_DEVICE_OLPC_MESH (device));
>
> if (candidate_idx == ifindex)
> return device;
> diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c
> index c9a184d..082ee35 100644
> --- a/src/nm-udev-manager.c
> +++ b/src/nm-udev-manager.c
> @@ -36,6 +36,7 @@
> #include "nm-utils.h"
> #include "NetworkManagerUtils.h"
> #include "nm-device-wifi.h"
> +#include "nm-device-olpc-mesh.h"
> #include "nm-device-ethernet.h"
>
> typedef struct {
> @@ -271,6 +272,15 @@ is_wireless (GUdevDevice *device)
> return is_wifi;
> }
>
> +static gboolean
> +is_olpc_mesh (GUdevDevice *device)
> +{
> + const gchar *prop = g_udev_device_get_property (device, "NM_DEVICE_TYPE");
> + if (!prop)
> + return FALSE;
> + return strcmp(prop, "olpcmesh") == 0;
> +}
> +
> static GObject *
> device_creator (NMUdevManager *manager,
> GUdevDevice *udev_device,
> @@ -311,7 +321,9 @@ device_creator (NMUdevManager *manager,
> return NULL;
> }
>
> - if (is_wireless (udev_device))
> + if (is_olpc_mesh (udev_device)) /* must be before is_wireless */
> + device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver, ifindex);
> + else if (is_wireless (udev_device))
> device = (GObject *) nm_device_wifi_new (path, ifname, driver, ifindex);
> else
> device = (GObject *) nm_device_ethernet_new (path, ifname, driver, ifindex);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]