diff options
author | Dan Williams <dcbw@redhat.com> | 2007-06-22 02:01:42 +0000 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2007-06-22 02:01:42 +0000 |
commit | 908e17b09610cfbee3927d563b3ed3b88f7569a5 (patch) | |
tree | 0709e903b38793b41ea12b62f9c1e7481bca8b3d | |
parent | 1becbb498c52b9bffd1c2c1ce9847cac816545ec (diff) | |
download | NetworkManager-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-- | ChangeLog | 12 | ||||
-rw-r--r-- | callouts/mpp.py | 183 | ||||
-rw-r--r-- | src/NetworkManagerDbus.c | 196 | ||||
-rw-r--r-- | src/NetworkManagerDbus.h | 7 | ||||
-rw-r--r-- | src/nm-dbus-nm.c | 53 | ||||
-rw-r--r-- | src/nm-device-802-11-mesh-olpc.c | 287 |
6 files changed, 591 insertions, 147 deletions
@@ -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); |