summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2007-06-22 02:01:42 +0000
committerDan Williams <dcbw@redhat.com>2007-06-22 02:01:42 +0000
commit908e17b09610cfbee3927d563b3ed3b88f7569a5 (patch)
tree0709e903b38793b41ea12b62f9c1e7481bca8b3d
parent1becbb498c52b9bffd1c2c1ce9847cac816545ec (diff)
downloadNetworkManager-908e17b09610cfbee3927d563b3ed3b88f7569a5.tar.gz
2007-06-21 Dan Williams <dcbw@redhat.com>
Big mesh update - Send MeshReady and MeshDown events so that the dispatcher can start mesh portal functionality correctly - Rework the avahi-autoipd handling code to spawn avahi-autoipd with using a custom action script, and to listen for avahi-autoipd event signals - Make MPP functionality actually work - Add the mpp.py script that the dispatcher uses - Handle memory allocation failures more gracefully git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/branches/nm-0-6-olpc@2613 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
-rw-r--r--ChangeLog12
-rw-r--r--callouts/mpp.py183
-rw-r--r--src/NetworkManagerDbus.c196
-rw-r--r--src/NetworkManagerDbus.h7
-rw-r--r--src/nm-dbus-nm.c53
-rw-r--r--src/nm-device-802-11-mesh-olpc.c287
6 files changed, 591 insertions, 147 deletions
diff --git a/ChangeLog b/ChangeLog
index 31e8e75ced..a812cf7c45 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
2007-06-21 Dan Williams <dcbw@redhat.com>
+ Big mesh update
+
+ - Send MeshReady and MeshDown events so that the dispatcher can start
+ mesh portal functionality correctly
+ - Rework the avahi-autoipd handling code to spawn avahi-autoipd with using
+ a custom action script, and to listen for avahi-autoipd event signals
+ - Make MPP functionality actually work
+ - Add the mpp.py script that the dispatcher uses
+ - Handle memory allocation failures more gracefully
+
+2007-06-21 Dan Williams <dcbw@redhat.com>
+
* dispatcher-daemon/NetworkManagerDispatcher.c
- Add MESH_READY and MESH_DOWN events
- Keep a cache of interface <-> object path mappings, so that when NM
diff --git a/callouts/mpp.py b/callouts/mpp.py
new file mode 100644
index 0000000000..a6cfab6779
--- /dev/null
+++ b/callouts/mpp.py
@@ -0,0 +1,183 @@
+#!/usr/bin/python
+# 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 2007 One Laptop Per Child
+#
+
+import commands, sys, syslog, os
+
+def get_ip4_address(iface):
+ import socket
+ import fcntl
+ import struct
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ fd = s.fileno()
+ SIOCGIFADDR = 0x8915
+ addr = fcntl.ioctl(fd, SIOCGIFADDR, struct.pack('256s', iface[:15]))[20:24]
+ s.close()
+ return socket.inet_ntoa(addr)
+
+def get_hw_address(iface):
+ import struct
+ import fcntl
+ import socket
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ fd = s.fileno()
+ SIOCGIFHWADDR = 0x8927
+ req = fcntl.ioctl(fd, SIOCGIFHWADDR, struct.pack('16s16s', iface, ''))
+ s.close()
+ ignore1, ignore2, addr_high, addr_low = struct.unpack('>16sHHL8x', req)
+ addr = (long(addr_high)<<32) + addr_low
+ b0 = addr & 0xFF
+ b1 = (addr >> 8) & 0xFF
+ b2 = (addr >> 16) & 0xFF
+ b3 = (addr >> 24) & 0xFF
+ b4 = (addr >> 32) & 0xFF
+ b5 = (addr >> 40) & 0xFF
+ return "%02X:%02X:%02X:%02X:%02X:%02X" % (b5, b4, b3, b2, b1, b0)
+
+def set_anycast(mask, mesh_dev):
+ commands.getstatusoutput('echo "%s" > /sys/class/net/%s/anycast_mask' % (mask, mesh_dev))
+
+def ipt(args):
+ (s, o) = commands.getstatusoutput("/sbin/iptables %s" % args)
+ if (s != 0):
+ syslog("Error executing iptables command '%s': %s" % (args, o))
+
+def masq_start(extif, intif):
+ os.system('echo "1" > /proc/sys/net/ipv4/ip_forward')
+ os.system('echo "1" > /proc/sys/net/ipv4/ip_dynaddr')
+
+ modules = ["ip_tables", "ip_conntrack", "ip_conntrack_ftp", "ip_conntrack_irc",
+ "iptable_nat", "ip_nat_ftp", "ip_nat_irc"]
+
+ os.system("/sbin/modprobe " + " ".join(modules))
+
+ ipt("-P INPUT ACCEPT")
+ ipt("-F INPUT")
+ ipt("-P OUTPUT ACCEPT")
+ ipt("-F OUTPUT")
+ ipt("-P FORWARD DROP")
+ ipt("-F FORWARD")
+ ipt("-t nat -F")
+
+ # FWD: Allow all connections OUT and only existing and related ones IN
+ ipt("-A FORWARD -i %s -o %s -m state --state ESTABLISHED,RELATED -j ACCEPT" % (extif, intif))
+ ipt("-A FORWARD -i %s -o %s -j ACCEPT" % (extif, intif))
+ ipt("-A FORWARD -i %s -o %s -j ACCEPT" % (intif, extif))
+ #ipt("-A FORWARD -j LOG")
+
+ # Enabling SNAT (MASQUERADE) functionality on $EXTIF
+ ipt("-t nat -A POSTROUTING -o %s -j MASQUERADE" % extif)
+
+def masq_stop():
+ ipt("-F INPUT")
+ ipt("-F OUTPUT")
+ ipt("-P FORWARD DROP")
+ ipt("-F FORWARD")
+ ipt("-F -t nat")
+
+ # Delete all User-specified chains
+ ipt("-X")
+
+ # Reset all IPTABLES counters
+ ipt("-Z")
+
+def mpp_start(mesh_dev, primary_dev):
+ dns_file = file('/etc/resolv.conf','r')
+ dns_addresses = ""
+ for line in dns_file.readlines():
+ if len(line.split()) >= 2 and line.split()[0] == "nameserver":
+ dns_addresses += line.split()[1] + ", "
+ dns_addresses = dns_addresses[:len(dns_addresses) - 2]
+ dns_file.close()
+
+ mesh_ip4_addr = get_ip4_address(mesh_dev)
+ if not mesh_ip4_addr or not len(mesh_ip4_addr):
+ return
+
+ primary_hw_addr = get_hw_address(primary_dev).lower()
+
+ #copy parameters to the DHCP conf file
+ dhcpd_conf_text = """#Custom DHCP daemon configuration file - XO as MPP
+ddns-update-style interim;
+
+# free the addresses quickly, clients ignore them anyway
+default-lease-time 60;
+max-lease-time 60;
+
+option domain-name-servers %s;
+
+# Ignore requests from ourselves. Because the 8388's mesh interface has
+# the same MAC address as the eth interface, dhclient gets confused
+class "me" {
+ match if hardware = 01:%s;
+}
+
+subnet 169.254.0.0 netmask 255.255.0.0 {
+ pool {
+ deny members of "me";
+ option routers %s;
+ # range of link-local addresses, won't be used by XO's
+ range 169.254.0.1 169.254.255.254;
+ }
+}
+""" % (dns_addresses, primary_hw_addr, mesh_ip4_addr)
+
+ fd = open("/etc/dhcpd.conf","w")
+ fd.write(dhcpd_conf_text)
+ fd.flush()
+ fd.close()
+
+ masq_start(primary_dev, mesh_dev)
+
+ # Start MPP functionality in mesh firmware
+ set_anycast("0x2", mesh_dev) # mask for xo-as-mpp
+
+ # Tell dhcpd to only listen on the mesh interface
+ fd = open("/etc/sysconfig/dhcpd", "w")
+ fd.write('DHCPDARGS="%s"' % mesh_dev)
+ fd.close()
+ (s, o) = commands.getstatusoutput("service dhcpd restart")
+
+def mpp_stop(mesh_dev, primary_dev):
+ masq_stop()
+
+ (s, o) = commands.getstatusoutput("service dhcpd stop")
+ try:
+ os.remove("/etc/sysconfig/dhcpd")
+ os.remove("/etc/dhcpd.conf")
+ except OSError, e:
+ pass
+
+ # Stop MPP functionality in mesh firmware
+ set_anycast("0x0", mesh_dev) # mask for off
+
+
+def main():
+ if len(sys.argv) < 4:
+ sys.exit()
+
+ mesh_dev = sys.argv[1]
+ action = sys.argv[2]
+ primary_dev = sys.argv[3]
+
+ if action == "meshready":
+ mpp_start(mesh_dev, primary_dev)
+ elif action == "meshdown":
+ mpp_stop(mesh_dev, primary_dev)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/NetworkManagerDbus.c b/src/NetworkManagerDbus.c
index 5df8ee8a11..24ac04bf10 100644
--- a/src/NetworkManagerDbus.c
+++ b/src/NetworkManagerDbus.c
@@ -279,10 +279,118 @@ void nm_dbus_schedule_device_status_change_signal (NMData *data, NMDevice *dev,
cb_data->status = status;
source = g_idle_source_new ();
- g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
- g_source_set_callback (source, nm_dbus_signal_device_status_change, cb_data, NULL);
- g_source_attach (source, data->main_context);
- g_source_unref (source);
+ if (source) {
+ g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
+ g_source_set_callback (source, nm_dbus_signal_device_status_change, cb_data, NULL);
+ g_source_attach (source, data->main_context);
+ g_source_unref (source);
+ }
+}
+
+
+typedef struct NMMeshChangeData
+{
+ NMData * data;
+ NMDevice * mesh_dev;
+ NMDevice * primary_dev;
+ MeshDeviceStatus status;
+} NMMeshChangeData;
+
+
+/*
+ * nm_dbus_signal_mesh_device_change
+ *
+ * Notifies the bus that a particular mesh device has had a status change
+ *
+ */
+static gboolean
+nm_dbus_signal_mesh_device_change (gpointer user_data)
+{
+ NMMeshChangeData * cb_data = (NMMeshChangeData *)user_data;
+ DBusMessage * message = NULL;
+ char * mesh_dev_path = NULL;
+ char * primary_dev_path = NULL;
+ const char * sig;
+ int i = 0;
+
+ g_return_val_if_fail (cb_data->data, FALSE);
+ g_return_val_if_fail (cb_data->data->dbus_connection, FALSE);
+ g_return_val_if_fail (cb_data->mesh_dev, FALSE);
+ g_return_val_if_fail (cb_data->primary_dev, FALSE);
+
+ switch (cb_data->status) {
+ case MESH_READY:
+ sig = "MeshReady";
+ break;
+ case MESH_DOWN:
+ sig = "MeshDown";
+ break;
+ default:
+ nm_info ("%s: invalid mesh status %d", __func__, cb_data->status);
+ goto out;
+ break;
+ }
+
+ if (!(mesh_dev_path = nm_dbus_get_object_path_for_device (cb_data->mesh_dev)))
+ goto out;
+
+ if (!(primary_dev_path = nm_dbus_get_object_path_for_device (cb_data->primary_dev)))
+ goto out;
+
+ message = dbus_message_new_signal (NM_DBUS_PATH, NM_DBUS_INTERFACE, sig);
+ if (!message) {
+ nm_warning ("%s(): Not enough memory for new dbus message!", __func__);
+ goto out;
+ }
+
+ dbus_message_append_args (message,
+ DBUS_TYPE_OBJECT_PATH, &mesh_dev_path,
+ DBUS_TYPE_OBJECT_PATH, &primary_dev_path,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send (cb_data->data->dbus_connection, message, NULL))
+ nm_warning ("%s(): Could not raise the signal!", __func__);
+
+ out:
+ if (message)
+ dbus_message_unref (message);
+
+ g_free (mesh_dev_path);
+ g_free (primary_dev_path);
+ g_object_unref (G_OBJECT (cb_data->mesh_dev));
+ g_object_unref (G_OBJECT (cb_data->primary_dev));
+ g_free (cb_data);
+
+ return FALSE;
+}
+
+
+void
+nm_dbus_schedule_mesh_device_change_signal (NMData *data,
+ NMDevice *mesh_dev,
+ NMDevice *primary_dev,
+ MeshDeviceStatus status)
+{
+ NMMeshChangeData * cb_data = NULL;
+ GSource * source;
+
+ g_return_if_fail (data != NULL);
+ g_return_if_fail (mesh_dev != NULL);
+ g_return_if_fail (primary_dev != NULL);
+
+ cb_data = g_malloc0 (sizeof (NMMeshChangeData));
+ cb_data->data = data;
+ cb_data->mesh_dev = g_object_ref (G_OBJECT (mesh_dev));
+ cb_data->primary_dev = g_object_ref (G_OBJECT (primary_dev));
+ cb_data->status = status;
+
+ source = g_idle_source_new ();
+ if (source) {
+ g_source_set_priority (source, G_PRIORITY_HIGH_IDLE);
+ g_source_set_callback (source, nm_dbus_signal_mesh_device_change, cb_data, NULL);
+ g_source_attach (source, data->main_context);
+ g_source_unref (source);
+ }
}
@@ -433,6 +541,65 @@ out:
g_free (dev_path);
}
+#define AUTOIPD_CALLOUT_INTERFACE "org.freedesktop.NetworkManager.avahiautoipd"
+
+static gboolean
+nm_dbus_autoip_process_signal (NMData * data, DBusMessage * message)
+{
+ const char * object_path;
+ gboolean handled = FALSE;
+ DBusError error;
+ NMDevice * dev;
+ char * event = NULL;
+ char * iface = NULL;
+ char * ip4_addr = NULL;
+
+ dbus_error_init (&error);
+
+ g_return_val_if_fail (data != NULL, FALSE);
+ g_return_val_if_fail (message != NULL, FALSE);
+
+ object_path = dbus_message_get_path (message);
+ if (!object_path || strcmp (object_path, "/")) {
+ nm_warning ("Invalid object path from avahi-autoipd event: %s",
+ object_path ? object_path : "(null)");
+ goto out;
+ }
+
+ if (!dbus_message_get_args (message,
+ &error,
+ DBUS_TYPE_STRING, &event,
+ DBUS_TYPE_STRING, &iface,
+ DBUS_TYPE_STRING, &ip4_addr,
+ DBUS_TYPE_INVALID)) {
+ nm_warning ("Invalid mesage arguments from avahi-autoipd: (%s) %s",
+ error.name,
+ error.message);
+ goto out;
+ }
+
+ if ( (strcmp (event, "BIND") != 0)
+ && (strcmp (event, "CONFLICT") != 0)
+ && (strcmp (event, "UNBIND") != 0)
+ && (strcmp (event, "STOP") != 0)) {
+ nm_warning ("Invalid mesage event from avahi-autoipd: %s", event);
+ goto out;
+ }
+
+ dev = nm_get_device_by_iface (data, iface);
+ if (!dev) {
+ nm_warning ("Invalid autoip bind for device %s: device unknown.",
+ iface);
+ goto out;
+ }
+
+ nm_device_handle_autoip_event (dev, event, ip4_addr);
+
+out:
+ dbus_error_free (&error);
+ return handled;
+}
+
/*
* nm_dbus_signal_filter
@@ -443,6 +610,7 @@ out:
static DBusHandlerResult nm_dbus_signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data)
{
NMData * data = (NMData *)user_data;
+ const char * interface;
const char * object_path;
const char * method;
gboolean handled = FALSE;
@@ -453,13 +621,19 @@ static DBusHandlerResult nm_dbus_signal_filter (DBusConnection *connection, DBus
g_return_val_if_fail (message != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
method = dbus_message_get_member (message);
+ interface = dbus_message_get_interface (message);
if (!(object_path = dbus_message_get_path (message)))
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- /* nm_debug ("nm_dbus_nmi_filter() got method %s for path %s", method, object_path); */
+#if 0
+ nm_debug ("Got interface='%s', method='%s', path='%s'",
+ interface ? interface : "(null)",
+ method ? method : "(null)",
+ object_path ? object_path : "(null)");
+#endif
dbus_error_init (&error);
@@ -554,10 +728,13 @@ static DBusHandlerResult nm_dbus_signal_filter (DBusConnection *connection, DBus
handled = TRUE;
}
}
- else if (nm_dhcp_manager_process_signal (data->dhcp_manager, message) == TRUE)
+ else if (dbus_message_is_signal (message, AUTOIPD_CALLOUT_INTERFACE, "AutoIP4Event")) {
+ handled = nm_dbus_autoip_process_signal (data, message);
+ } else if (nm_dhcp_manager_process_signal (data->dhcp_manager, message) == TRUE) {
handled = TRUE;
- else if (nm_vpn_manager_process_signal (data->vpn_manager, message) == TRUE)
+ } else if (nm_vpn_manager_process_signal (data->vpn_manager, message) == TRUE) {
handled = TRUE;
+ }
if (dbus_error_is_set (&error))
dbus_error_free (&error);
@@ -823,6 +1000,11 @@ DBusConnection *nm_dbus_init (NMData *data)
"sender='" DBUS_SERVICE_DBUS "'",
NULL);
+ dbus_bus_add_match (connection,
+ "type='signal',"
+ "interface='" AUTOIPD_CALLOUT_INTERFACE "'",
+ NULL);
+
if ((owner = get_name_owner (connection, NMI_DBUS_SERVICE)))
{
char *match = get_nmi_match_string (owner);
diff --git a/src/NetworkManagerDbus.h b/src/NetworkManagerDbus.h
index 8646b66cb6..5bc08deedc 100644
--- a/src/NetworkManagerDbus.h
+++ b/src/NetworkManagerDbus.h
@@ -46,6 +46,11 @@ typedef enum
DEVICE_CARRIER_OFF
} DeviceStatus;
+typedef enum
+{
+ MESH_READY,
+ MESH_DOWN,
+} MeshDeviceStatus;
static inline gboolean message_is_error (DBusMessage *msg)
{
@@ -75,4 +80,6 @@ NMState nm_get_app_state_from_data (NMData *data);
DBusMessage * nm_dbus_create_error_message (DBusMessage *message, const char *exception_namespace, const char *exception, const char *format, ...);
+void nm_dbus_schedule_mesh_device_change_signal (NMData *data, NMDevice *mesh_dev, NMDevice *primary_dev, MeshDeviceStatus status);
+
#endif
diff --git a/src/nm-dbus-nm.c b/src/nm-dbus-nm.c
index b19882e295..77edd5976a 100644
--- a/src/nm-dbus-nm.c
+++ b/src/nm-dbus-nm.c
@@ -663,58 +663,6 @@ static DBusMessage *nm_dbus_nm_get_state (DBusConnection *connection, DBusMessag
}
-static DBusMessage *
-nm_dbus_nm_autoip_event (DBusConnection *connection,
- DBusMessage *message,
- NMDbusCBData *data)
-{
- DBusError error;
- NMDevice * dev;
- char * event = NULL;
- char * iface = NULL;
- char * ip4_addr = NULL;
-
- g_return_val_if_fail (data != NULL, NULL);
- g_return_val_if_fail (data->data != NULL, NULL);
- g_return_val_if_fail (connection != NULL, NULL);
- g_return_val_if_fail (message != NULL, NULL);
-
- dbus_error_init (&error);
- if (!dbus_message_get_args (message,
- &error,
- DBUS_TYPE_STRING, &event,
- DBUS_TYPE_STRING, &iface,
- DBUS_TYPE_STRING, &ip4_addr,
- DBUS_TYPE_INVALID)) {
- nm_warning ("Invalid mesage arguments from avahi-autoipd: (%s) %s",
- error.name,
- error.message);
- goto out;
- }
-
- if ( (strcmp (event, "BIND") != 0)
- && (strcmp (event, "CONFLICT") != 0)
- && (strcmp (event, "UNBIND") != 0)
- && (strcmp (event, "STOP") != 0)) {
- nm_warning ("Invalid mesage event from avahi-autoipd: %s", event);
- goto out;
- }
-
- dev = nm_get_device_by_iface (data->data, iface);
- if (!dev) {
- nm_warning ("Invalid autoip bind for device %s: device unknown.",
- iface);
- goto out;
- }
-
- nm_device_handle_autoip_event (dev, event, ip4_addr);
-
-out:
- dbus_error_free (&error);
- return NULL;
-}
-
-
/*
* nm_dbus_nm_methods_setup
*
@@ -738,7 +686,6 @@ NMDbusMethodList *nm_dbus_nm_methods_setup (void)
nm_dbus_method_list_add_method (list, "state", nm_dbus_nm_get_state);
nm_dbus_method_list_add_method (list, "createTestDevice", nm_dbus_nm_create_test_device);
nm_dbus_method_list_add_method (list, "removeTestDevice", nm_dbus_nm_remove_test_device);
- nm_dbus_method_list_add_method (list, "autoipEvent", nm_dbus_nm_autoip_event);
return (list);
}
diff --git a/src/nm-device-802-11-mesh-olpc.c b/src/nm-device-802-11-mesh-olpc.c
index 4534bf97d5..077067888c 100644
--- a/src/nm-device-802-11-mesh-olpc.c
+++ b/src/nm-device-802-11-mesh-olpc.c
@@ -39,6 +39,8 @@
#include "NetworkManagerSystem.h"
#include "NetworkManagerPolicy.h"
+#define MESH_SSID "olpc-mesh"
+#define MPP_DEFAULT_CHANNEL 1
#define IPV4LL_NETWORK 0xA9FE0000L
#define IPV4LL_NETMASK 0xFFFF0000L
@@ -47,10 +49,10 @@
#define MESH_DHCP_TIMEOUT 15 /* in seconds */
-#define SCHOOL_ANYCAST_IP4 "172.31.255.254"
-#define SCHOOL_ANYCAST_MAC "c0:27:c0:27:c0:00"
-#define XO_ANYCAST_IP4 "172.31.255.253"
-#define XO_ANYCAST_MAC "c0:27:c0:27:c0:01"
+#define ETC_DHCLIENT_CONF_PATH "/etc/dhclient.conf"
+
+#define SCHOOL_ANYCAST_MAC "c0:27:c0:27:c0:01"
+#define XO_ANYCAST_MAC "c0:27:c0:27:c0:02"
static void channel_failure_handler (NMDevice80211MeshOLPC *self, NMActRequest *req);
static void aipd_cleanup (NMDevice80211MeshOLPC *self);
@@ -62,6 +64,9 @@ static gboolean aipd_exec (NMDevice80211MeshOLPC *self);
static gboolean aipd_monitor_start (NMDevice80211MeshOLPC *self);
static void real_deactivate_quickly (NMDevice *dev);
static void assoc_timeout_cleanup (NMDevice80211MeshOLPC * self);
+static gboolean is_mpp_active (NMDevice80211MeshOLPC *self);
+static gboolean mpp_autoip_start (NMDevice80211MeshOLPC *self);
+static gboolean assoc_timeout_start (NMDevice80211MeshOLPC *self);
#define NM_DEVICE_802_11_MESH_OLPC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_802_11_MESH_OLPC, NMDevice80211MeshOLPCPrivate))
@@ -85,6 +90,7 @@ struct _ethdev {
struct _mpp {
/* Device with the primary connection */
NMDevice * primary;
+ gboolean associated;
/* Attach to device activated signals */
GHashTable * activated_ids;
@@ -159,26 +165,38 @@ wireless_event_cb_data_free (WirelessEventCBData *data)
g_free (data);
}
-static void
-handle_association_event (NMDevice80211MeshOLPC * self)
+static gboolean
+handle_association_event (gpointer user_data)
{
- NMActRequest * req;
- NMActStage stage;
+ NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data);
- g_return_if_fail (self != NULL);
+ g_return_val_if_fail (self != NULL, FALSE);
- if (!nm_device_is_activating (NM_DEVICE (self)))
- return;
+ assoc_timeout_cleanup (self);
- req = nm_device_get_act_request (NM_DEVICE (self));
- g_return_if_fail (req != NULL);
+ nm_info ("%s: got association event from driver.",
+ nm_device_get_iface (NM_DEVICE (self)));
- stage = nm_act_request_get_stage (req);
- if (stage != NM_ACT_STAGE_DEVICE_CONFIG)
- return;
+ if (nm_device_is_activating (NM_DEVICE (self))) {
+ NMActRequest * req = nm_device_get_act_request (NM_DEVICE (self));
+ NMActStage stage;
- assoc_timeout_cleanup (self);
- nm_device_activate_schedule_stage3_ip_config_start (req);
+ if (!req)
+ goto out;
+
+ stage = nm_act_request_get_stage (req);
+ if (stage != NM_ACT_STAGE_DEVICE_CONFIG)
+ goto out;
+
+ nm_device_activate_schedule_stage3_ip_config_start (req);
+ } else if (is_mpp_active (self) && !self->priv->mpp.associated) {
+ self->priv->mpp.associated = TRUE;
+ mpp_autoip_start (self);
+ }
+
+out:
+ g_object_unref (self);
+ return FALSE;
}
static gboolean
@@ -221,7 +239,13 @@ wireless_event_helper (gpointer user_data)
/* disassociated */
} else {
/* associated */
- handle_association_event (self);
+ GSource * source = g_idle_source_new ();
+ if (source) {
+ g_object_ref (self);
+ g_source_set_callback (source, handle_association_event, self, NULL);
+ g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self)));
+ g_source_unref (source);
+ }
}
}
pos += iwe->len;
@@ -248,6 +272,10 @@ nm_device_802_11_mesh_olpc_wireless_event (NmNetlinkMonitor *monitor,
return;
cb_data = g_malloc0 (sizeof (WirelessEventCBData));
+ if (!cb_data) {
+ nm_info ("%s: couldn't allocate memory for callback data.", __func__);
+ goto out;
+ }
cb_data->self = NM_DEVICE_802_11_MESH_OLPC(g_object_ref (G_OBJECT (self)));
cb_data->ethdev = NM_DEVICE_802_11_WIRELESS (g_object_ref (obj));
cb_data->data = g_malloc (data_len);
@@ -255,10 +283,18 @@ nm_device_802_11_mesh_olpc_wireless_event (NmNetlinkMonitor *monitor,
cb_data->len = data_len;
source = g_idle_source_new ();
+ if (!source) {
+ nm_info ("%s: couldn't allocate memory for callback source.", __func__);
+ goto out;
+ }
+
g_source_set_callback (source, (GSourceFunc) wireless_event_helper,
cb_data, (GDestroyNotify) wireless_event_cb_data_free);
g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self)));
g_source_unref (source);
+
+out:
+ return;
}
@@ -302,7 +338,7 @@ real_init (NMDevice *dev)
self->priv->is_initialized = TRUE;
self->priv->capabilities = 0;
- self->priv->step = MESH_S3_XO_MPP;
+ self->priv->step = MESH_S1_SCHOOL_MPP;
self->priv->channel = 1;
self->priv->assoc_timeout = NULL;
self->priv->wireless_event_id = 0;
@@ -644,6 +680,9 @@ real_deactivate_quickly (NMDevice *dev)
mpp_cleanup (self);
aipd_cleanup (self);
assoc_timeout_cleanup (self);
+
+ /* Remove any dhclient.conf file we may have created for mshX */
+ remove (ETC_DHCLIENT_CONF_PATH);
}
@@ -802,6 +841,10 @@ set_80211_ssid (NMDevice80211Wireless *dev,
safe_len = 0;
} else {
safe_ssid = g_malloc0 (IW_ESSID_MAX_SIZE + 1);
+ if (!safe_ssid) {
+ nm_info ("%s: couldn't allocate memory for SSID.", __func__);
+ goto out;
+ }
memcpy (safe_ssid, ssid, safe_len);
}
@@ -809,7 +852,7 @@ set_80211_ssid (NMDevice80211Wireless *dev,
if (!sk) {
nm_warning ("%s: failed to open device socket.",
nm_device_get_iface (NM_DEVICE (dev)));
- return FALSE;
+ goto out;
}
wrqu.u.essid.pointer = (caddr_t) safe_ssid;
@@ -824,14 +867,16 @@ set_80211_ssid (NMDevice80211Wireless *dev,
nm_warning ("%s: failed to set SSID (errno: %d).",
nm_device_get_iface (NM_DEVICE (dev)),
errno);
- goto out;
+ goto free_sock;
}
success = TRUE;
+free_sock:
+ nm_dev_sock_close (sk);
+
out:
g_free (safe_ssid);
- nm_dev_sock_close (sk);
return success;
}
@@ -959,6 +1004,14 @@ mpp_cleanup (NMDevice80211MeshOLPC *self)
NMIP4Config * config;
if (self->priv->mpp.primary) {
+ NMData * data = nm_device_get_app_data (NM_DEVICE (self));
+ if (self->priv->mpp.associated) {
+ nm_dbus_schedule_mesh_device_change_signal (data,
+ NM_DEVICE (self),
+ NM_DEVICE (self->priv->mpp.primary),
+ MESH_DOWN);
+ }
+
g_object_unref (self->priv->mpp.primary);
self->priv->mpp.primary = NULL;
}
@@ -970,6 +1023,8 @@ mpp_cleanup (NMDevice80211MeshOLPC *self)
nm_system_device_flush_routes (NM_DEVICE (self));
nm_system_device_flush_addresses (NM_DEVICE (self));
nm_device_update_ip4_address (NM_DEVICE (self));
+
+ self->priv->mpp.associated = FALSE;
}
static void
@@ -977,6 +1032,7 @@ mpp_aipd_timeout (NMDevice80211MeshOLPC *self)
{
g_return_if_fail (self != NULL);
+ aipd_cleanup (self);
mpp_cleanup (self);
}
@@ -984,6 +1040,7 @@ static void
mpp_autoip_success (NMDevice80211MeshOLPC *self)
{
NMIP4Config * config;
+ NMData * data;
g_return_if_fail (self != NULL);
g_return_if_fail (self->priv->mpp.primary != NULL);
@@ -997,7 +1054,31 @@ mpp_autoip_success (NMDevice80211MeshOLPC *self)
nm_system_device_set_from_ip4_config (NM_DEVICE (self), TRUE);
-
+ data = nm_device_get_app_data (NM_DEVICE (self));
+ nm_dbus_schedule_mesh_device_change_signal (data,
+ NM_DEVICE (self),
+ NM_DEVICE (self->priv->mpp.primary),
+ MESH_READY);
+}
+
+static gboolean
+mpp_autoip_start (NMDevice80211MeshOLPC *self)
+{
+ const char * iface = nm_device_get_iface (NM_DEVICE (self));
+ gboolean success = FALSE;
+
+ /* Get an autoip address */
+ if (aipd_exec (self)) {
+ if (aipd_monitor_start (self)) {
+ success = TRUE;
+ } else {
+ aipd_cleanup (self);
+ nm_warning ("%s: MPP couldn't monitor avahi-autoipd.", iface);
+ }
+ } else {
+ nm_warning ("%s: MPP couldn't start avahi-autoipd.", iface);
+ }
+ return success;
}
static void
@@ -1018,20 +1099,38 @@ mpp_device_activated_cb (GObject * obj,
g_object_ref (self->priv->mpp.primary);
iface = nm_device_get_iface (NM_DEVICE (self));
- nm_debug ("%s: will become MPP for %s",
- iface,
- nm_device_get_iface (self->priv->mpp.primary));
- /* Get an autoip address */
- if (aipd_exec (self)) {
- if (!aipd_monitor_start (self)) {
- aipd_cleanup (self);
- nm_warning ("%s: MPP couldn't monitor avahi-autoipd.", iface);
- }
+ /* If the primary device isn't the companion ethernet device of this
+ * mesh device, then we need to set up other 802.11 things like
+ * channel, ssid, and mode that the eth device normally sets up itself.
+ */
+ if (primary_dev == NM_DEVICE (self->priv->ethdev.dev)) {
+ if (!mpp_autoip_start (self))
+ goto out;
} else {
- nm_warning ("%s: MPP couldn't start avahi-autoipd.", iface);
+ if (!clear_80211_keys (self->priv->ethdev.dev))
+ goto out;
+
+ if (!set_80211_mode (self->priv->ethdev.dev, IW_MODE_ADHOC))
+ goto out;
+
+ self->priv->channel = MPP_DEFAULT_CHANNEL;
+ if (!set_80211_channel (self->priv->ethdev.dev,
+ self->priv->channel,
+ &self->priv->range))
+ goto out;
+
+ if (!set_80211_ssid (self->priv->ethdev.dev, MESH_SSID, strlen (MESH_SSID)))
+ goto out;
+
+ assoc_timeout_start (self);
}
+ nm_info ("%s: will become MPP for %s on channel %d",
+ iface,
+ nm_device_get_iface (self->priv->mpp.primary),
+ self->priv->channel);
+
out:
return;
}
@@ -1049,11 +1148,12 @@ mpp_device_deactivated_cb (GObject * obj,
if (primary_dev != self->priv->mpp.primary)
return;
- nm_debug ("%s: will stop being an MPP for %s",
- nm_device_get_iface (NM_DEVICE (self)),
- nm_device_get_iface (self->priv->mpp.primary));
+ nm_info ("%s: will stop being an MPP for %s",
+ nm_device_get_iface (NM_DEVICE (self)),
+ nm_device_get_iface (self->priv->mpp.primary));
mpp_cleanup (self);
+ aipd_cleanup (self);
}
@@ -1120,8 +1220,6 @@ aipd_watch_cb (GPid pid,
aipd_cleanup (self);
-/* nm_device_set_active_link (dev, FALSE); */
-
return FALSE;
}
@@ -1139,14 +1237,16 @@ aipd_child_setup (gpointer user_data G_GNUC_UNUSED)
static gboolean
aipd_exec (NMDevice80211MeshOLPC *self)
{
- char * argv[3];
+ char * argv[5];
GError * error = NULL;
GPid pid = -1;
gboolean success = FALSE;
argv[0] = "/usr/sbin/avahi-autoipd";
- argv[1] = (char *) nm_device_get_iface (NM_DEVICE (self));
- argv[2] = NULL;
+ argv[1] = "--script";
+ argv[2] = SYSCONFDIR "/NetworkManager/callouts/nm-avahi-autoipd.action";
+ argv[3] = (char *) nm_device_get_iface (NM_DEVICE (self));
+ argv[4] = NULL;
success = g_spawn_async ("/", argv, NULL, 0,
&aipd_child_setup, NULL, &pid, &error);
@@ -1270,9 +1370,10 @@ channel_failure_handler (NMDevice80211MeshOLPC *self, NMActRequest *req)
self->priv->channel++;
break;
default:
- nm_info ("%s: %s/%d unhandled step %d\n",
+ nm_info ("%s: unhandled step %d",
nm_device_get_iface (NM_DEVICE (self)),
- __func__, __LINE__, self->priv->step);
+ self->priv->step);
+ g_assert_not_reached ();
break;
}
@@ -1326,23 +1427,30 @@ assoc_timeout_cb (gpointer user_data)
g_return_val_if_fail (self != NULL, FALSE);
- if ( !self->priv->assoc_timeout
- || !nm_device_is_activating (NM_DEVICE (self)))
+ if (!self->priv->assoc_timeout)
goto out;
- req = nm_device_get_act_request (NM_DEVICE (self));
- g_return_val_if_fail (req != NULL, FALSE);
+ if (nm_device_is_activating (NM_DEVICE (self))) {
+ req = nm_device_get_act_request (NM_DEVICE (self));
+ g_return_val_if_fail (req != NULL, FALSE);
- stage = nm_act_request_get_stage (req);
- if (stage != NM_ACT_STAGE_DEVICE_CONFIG)
- goto out;
+ stage = nm_act_request_get_stage (req);
+ if (stage != NM_ACT_STAGE_DEVICE_CONFIG)
+ goto out;
- nm_info ("Activation (%s/mesh) Stage 2 of 6 (Device Configure) association "
- "timed out on channel %d.",
- nm_device_get_iface (NM_DEVICE (self)),
- self->priv->channel);
+ nm_info ("Activation (%s/mesh) Stage 2 of 6 (Device Configure) association "
+ "timed out on channel %d.",
+ nm_device_get_iface (NM_DEVICE (self)),
+ self->priv->channel);
- channel_failure_handler (self, req);
+ channel_failure_handler (self, req);
+ } else if (is_mpp_active (self)) {
+ nm_info ("%s: association timed out on channel %d during MPP setup.",
+ nm_device_get_iface (NM_DEVICE (self)),
+ self->priv->channel);
+ mpp_cleanup (self);
+ assoc_timeout_cleanup (self);
+ }
out:
return FALSE;
@@ -1363,7 +1471,7 @@ assoc_timeout_start (NMDevice80211MeshOLPC *self)
g_return_val_if_fail (self != NULL, FALSE);
- self->priv->assoc_timeout = g_timeout_source_new (3000);
+ self->priv->assoc_timeout = g_timeout_source_new (6000);
if (!self->priv->assoc_timeout)
goto out;
@@ -1386,7 +1494,6 @@ real_act_stage2_config (NMDevice *dev,
{
NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev);
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
- GSource * source;
if (!clear_80211_keys (self->priv->ethdev.dev))
goto out;
@@ -1401,7 +1508,6 @@ real_act_stage2_config (NMDevice *dev,
goto out;
}
-#define MESH_SSID "olpc-mesh"
if (!set_80211_ssid (self->priv->ethdev.dev, MESH_SSID, strlen (MESH_SSID)))
goto out;
@@ -1410,6 +1516,8 @@ real_act_stage2_config (NMDevice *dev,
nm_device_get_iface (NM_DEVICE (self)),
self->priv->channel);
+ assoc_timeout_start (self);
+
ret = NM_ACT_STAGE_RETURN_POSTPONE;
out:
@@ -1418,12 +1526,10 @@ out:
#define BUF_SIZE 100
-#define ETC_DHCLIENT_CONF_PATH "/etc/dhclient.conf"
static NMActStageReturn
setup_for_mpp (NMDevice80211MeshOLPC * self,
NMActRequest * req,
- const char * ip4,
const char * mac)
{
NMDevice80211MeshOLPCClass * klass;
@@ -1433,22 +1539,10 @@ setup_for_mpp (NMDevice80211MeshOLPC * self,
char buf[BUF_SIZE];
int fd, written;
-#if 0
- nm_system_device_add_route_via_device_with_iface (iface, ip4);
-
- snprintf (buf, BUF_SIZE, "/sbin/arp -s %s %s", ip4, mac);
- if (nm_spawn_process (buf)) {
- nm_warning ("Activation (%s/mesh): couldn't create anycast ARP"
- " mapping for MPP discovery.",
- iface);
- goto out;
- }
-#endif
-
snprintf (buf, BUF_SIZE,
"interface \"%s\" {\n"
" initial-interval 1;\n"
- " anycast-mac ethernet %s\n"
+ " anycast-mac ethernet %s;\n"
"}\n",
iface, mac);
@@ -1490,10 +1584,10 @@ real_act_stage3_ip_config_start (NMDevice *dev,
switch (self->priv->step) {
case MESH_S1_SCHOOL_MPP:
- ret = setup_for_mpp (self, req, SCHOOL_ANYCAST_IP4, SCHOOL_ANYCAST_MAC);
+ ret = setup_for_mpp (self, req, SCHOOL_ANYCAST_MAC);
break;
case MESH_S3_XO_MPP:
- ret = setup_for_mpp (self, req, XO_ANYCAST_IP4, XO_ANYCAST_MAC);
+ ret = setup_for_mpp (self, req, XO_ANYCAST_MAC);
break;
case MESH_S4_P2P_MESH:
if (!aipd_exec (self)) {
@@ -1509,9 +1603,10 @@ real_act_stage3_ip_config_start (NMDevice *dev,
ret = NM_ACT_STAGE_RETURN_POSTPONE;
break;
default:
- nm_info ("%s: %s/%d unhandled step %d\n",
- nm_device_get_iface (dev),
- __func__, __LINE__, self->priv->step);
+ nm_info ("%s: unhandled step %d",
+ nm_device_get_iface (NM_DEVICE (self)),
+ self->priv->step);
+ g_assert_not_reached ();
break;
}
@@ -1545,17 +1640,30 @@ real_act_stage4_get_ip4_config (NMDevice *dev,
NMDevice80211MeshOLPCClass * klass;
NMDeviceClass * parent_class;
const char * iface = nm_device_get_iface (dev);
+ NMData * data = nm_device_get_app_data (dev);
g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE);
switch (self->priv->step) {
case MESH_S1_SCHOOL_MPP:
+ /* Chain up to parent */
+ klass = NM_DEVICE_802_11_MESH_OLPC_GET_CLASS (self);
+ parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass));
+ ret = parent_class->act_stage4_get_ip4_config (dev, req, &real_config);
+ if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
+ goto out;
+ break;
case MESH_S3_XO_MPP:
/* Chain up to parent */
klass = NM_DEVICE_802_11_MESH_OLPC_GET_CLASS (self);
parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass));
ret = parent_class->act_stage4_get_ip4_config (dev, req, &real_config);
+ /* Kill dhclient; we don't need it anymore after MPP discovery here
+ * because we're ignoring the returned lease.
+ */
+ nm_dhcp_manager_cancel_transaction (data->dhcp_manager, req);
+ sleep (1);
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
goto out;
break;
@@ -1567,9 +1675,10 @@ real_act_stage4_get_ip4_config (NMDevice *dev,
nm_ip4_config_set_gateway (real_config, 0);
break;
default:
- nm_info ("%s: %s/%d unhandled step %d\n",
+ nm_info ("%s: unhandled step %d",
nm_device_get_iface (NM_DEVICE (self)),
- __func__, __LINE__, self->priv->step);
+ self->priv->step);
+ g_assert_not_reached ();
break;
}
@@ -1639,7 +1748,6 @@ apply_autoip_address (NMDevice80211MeshOLPC *self, guint32 addr)
nm_ip4_config_set_address (ip4_config, addr);
nm_ip4_config_set_netmask (ip4_config, (guint32)(ntohl (IPV4LL_NETMASK)));
nm_ip4_config_set_broadcast (ip4_config, (guint32)(ntohl (IPV4LL_BROADCAST)));
- nm_ip4_config_set_gateway (ip4_config, 0);
return TRUE;
}
@@ -1687,13 +1795,15 @@ handle_activation_autoip_event (NMDevice80211MeshOLPC *self,
channel_failure_handler (self, req);
else
nm_device_activate_schedule_stage5_ip_config_commit (req);
+ break;
case MESH_S4_P2P_MESH:
nm_device_activate_schedule_stage4_ip_config_get (req);
break;
default:
- nm_info ("%s: %s/%d unhandled step %d\n",
+ nm_info ("%s: unhandled step %d",
nm_device_get_iface (NM_DEVICE (self)),
- __func__, __LINE__, self->priv->step);
+ self->priv->step);
+ g_assert_not_reached ();
break;
}
}
@@ -1795,9 +1905,11 @@ real_notify_no_best_device (NMDevice *dev)
g_return_if_fail (self != NULL);
source = g_idle_source_new ();
- g_source_set_callback (source, handle_no_best_device, dev, NULL);
- g_source_attach (source, nm_device_get_main_context (dev));
- g_source_unref (source);
+ if (source) {
+ g_source_set_callback (source, handle_no_best_device, dev, NULL);
+ g_source_attach (source, nm_device_get_main_context (dev));
+ g_source_unref (source);
+ }
}
@@ -1809,6 +1921,7 @@ real_handle_autoip_event (NMDevice *dev,
NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev);
NMActRequest * req = nm_device_get_act_request (dev);
+ nm_info ("%s: got autoip event '%s' for '%s'\n", nm_device_get_iface (NM_DEVICE (self)), event, addr);
if (nm_device_is_activating (NM_DEVICE (self))) {
if (req) {
handle_activation_autoip_event (self, req, event, addr);