diff options
author | Dan Williams <dcbw@redhat.com> | 2007-06-10 03:06:01 +0000 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2007-06-10 03:06:01 +0000 |
commit | eccdd55def63c97319b5356219633fb103fb96aa (patch) | |
tree | 2a10496a796266e1dc1010c161542d3f570773ad | |
parent | 7e906f9abdaf9f674b6599e9075a7e1c3fd62e3f (diff) | |
download | NetworkManager-eccdd55def63c97319b5356219633fb103fb96aa.tar.gz |
2007-06-09 Dan Williams <dcbw@redhat.com>
* Rework to enable auto-MPP functionality. Whenever a non-mesh device is
activated, the mesh device will acquire an IPv4 autoip address so that
an external program can begin MPP functionality on the mesh interface.
* DHCP is now being used instead of the MPP server hack, and there
is no "mesh search" step any more.
* Driver changes also require that most
wireless operations (channel changes, keys, ssids, etc) be done on the
eth device, not the mesh device.
* Remove the "post-ip" stage #6; since MPP functionality is now provided
by DHCP, it's useless
git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/branches/nm-0-6-olpc@2582 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | include/NetworkManager.h | 1 | ||||
-rw-r--r-- | src/NetworkManagerPolicy.c | 39 | ||||
-rw-r--r-- | src/NetworkManagerPolicy.h | 2 | ||||
-rw-r--r-- | src/NetworkManagerSystem.c | 35 | ||||
-rw-r--r-- | src/NetworkManagerSystem.h | 2 | ||||
-rw-r--r-- | src/nm-device-802-11-mesh-olpc.c | 1800 | ||||
-rw-r--r-- | src/nm-device-802-11-wireless.c | 5 | ||||
-rw-r--r-- | src/nm-device.c | 190 | ||||
-rw-r--r-- | src/nm-device.h | 12 | ||||
-rw-r--r-- | src/vpn-manager/nm-vpn-connection.c | 2 |
11 files changed, 1052 insertions, 1052 deletions
@@ -1,3 +1,19 @@ +2007-06-09 Dan Williams <dcbw@redhat.com> + + * Rework to enable auto-MPP functionality. Whenever a non-mesh device is + activated, the mesh device will acquire an IPv4 autoip address so that + an external program can begin MPP functionality on the mesh interface. + + * DHCP is now being used instead of the MPP server hack, and there + is no "mesh search" step any more. + + * Driver changes also require that most + wireless operations (channel changes, keys, ssids, etc) be done on the + eth device, not the mesh device. + + * Remove the "post-ip" stage #6; since MPP functionality is now provided + by DHCP, it's useless + 2007-04-06 Dan Williams <dcbw@redhat.com> * src/NetworkManager.c diff --git a/include/NetworkManager.h b/include/NetworkManager.h index 2e11a2857d..07e7dcf1c3 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -190,7 +190,6 @@ typedef enum NMActStage NM_ACT_STAGE_IP_CONFIG_START, NM_ACT_STAGE_IP_CONFIG_GET, NM_ACT_STAGE_IP_CONFIG_COMMIT, - NM_ACT_STAGE_POST_IP_START, NM_ACT_STAGE_ACTIVATED, NM_ACT_STAGE_FAILED, NM_ACT_STAGE_CANCELLED diff --git a/src/NetworkManagerPolicy.c b/src/NetworkManagerPolicy.c index 4bfc486458..542cb7fb79 100644 --- a/src/NetworkManagerPolicy.c +++ b/src/NetworkManagerPolicy.c @@ -41,6 +41,20 @@ #include "nm-device-802-3-ethernet.h" +/* List of devices interested in knowing when there is + * no best device to be activated. + */ +static GSList * nbd_notifiers = NULL; + + +void nm_policy_add_nbd_notifier (NMDevice *dev) +{ + g_return_if_fail (dev != NULL); + + nbd_notifiers = g_slist_append (nbd_notifiers, dev); +} + + /* * nm_policy_activation_finish * @@ -269,10 +283,10 @@ static NMDevice * nm_policy_auto_get_best_device (NMData *data, NMAccessPoint ** } } - if (best_mesh_dev) - highest_priority_dev = NM_DEVICE (best_mesh_dev); - else if (best_wired_dev) + if (best_wired_dev) highest_priority_dev = NM_DEVICE (best_wired_dev); + else if (best_mesh_dev) + highest_priority_dev = NM_DEVICE (best_mesh_dev); else if (best_wireless_dev) { *ap = nm_device_802_11_wireless_get_best_ap (best_wireless_dev); @@ -283,9 +297,24 @@ static NMDevice * nm_policy_auto_get_best_device (NMData *data, NMAccessPoint ** highest_priority_dev = NM_DEVICE (best_wireless_dev); } + if (!highest_priority_dev) { + GSList * elt; + + /* Alert interested listeners that there is no best device + * to activate. + */ + for (elt = nbd_notifiers; elt; elt = g_slist_next (elt)) { + NMDevice * notify_dev = NM_DEVICE (elt->data); + nm_device_notify_no_best_device (notify_dev); + } + } + #if 0 - nm_info ("AUTO: Best wired device = %s, best wireless device = %s (%s)", best_wired_dev ? nm_device_get_iface (best_wired_dev) : "(null)", - best_wireless_dev ? nm_device_get_iface (best_wireless_dev) : "(null)", (best_wireless_dev && *ap) ? nm_ap_get_essid (*ap) : "null" ); + nm_info ("AUTO: Best wired = %s, best wireless = %s (%s), best mesh = %s", + best_wired_dev ? nm_device_get_iface (best_wired_dev) : "(null)", + best_wireless_dev ? nm_device_get_iface (best_wireless_dev) : "(null)", + (best_wireless_dev && *ap) ? nm_ap_get_essid (*ap) : "null", + best_mesh_dev ? nm_device_get_iface (best_mesh_dev) : "(null)"); #endif return highest_priority_dev; diff --git a/src/NetworkManagerPolicy.h b/src/NetworkManagerPolicy.h index eb11228ac6..d927e1d6a3 100644 --- a/src/NetworkManagerPolicy.h +++ b/src/NetworkManagerPolicy.h @@ -37,4 +37,6 @@ void nm_policy_schedule_device_ap_lists_update_from_allowed (NMData *app_data) void nm_policy_schedule_activation_finish (NMActRequest *req); void nm_policy_schedule_activation_failed (NMActRequest *req); +void nm_policy_add_nbd_notifier (NMDevice *dev); + #endif diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index 4717beddf7..d6d0aa3393 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -292,7 +292,7 @@ nm_system_get_iface_from_rtnl_index (int rtnl_index) * Set IPv4 configuration of the device from an NMIP4Config object. * */ -gboolean nm_system_device_set_from_ip4_config (NMDevice *dev) +gboolean nm_system_device_set_from_ip4_config (NMDevice *dev, gboolean secondary) { NMData * app_data; NMIP4Config * config; @@ -312,28 +312,41 @@ gboolean nm_system_device_set_from_ip4_config (NMDevice *dev) if (!nlh) return FALSE; - nm_system_delete_default_route (); + if (!secondary) + nm_system_delete_default_route (); nm_system_device_flush_addresses (dev); nm_system_device_flush_routes (dev); - nm_system_flush_arp_cache (); + if (!secondary) + nm_system_flush_arp_cache (); - if ((addr = nm_ip4_config_to_rtnl_addr (config, NM_RTNL_ADDR_DEFAULT))) - { + if ((addr = nm_ip4_config_to_rtnl_addr (config, NM_RTNL_ADDR_DEFAULT))) { iface_to_rtnl_index (nm_device_get_iface (dev), nlh, addr); if ((err = rtnl_addr_add (nlh, addr, 0)) < 0) - nm_warning ("nm_system_device_set_from_ip4_config(%s): error %d returned from rtnl_addr_add():\n%s", nm_device_get_iface (dev), err, nl_geterror()); + nm_warning ("%s(%s): error %d returned from rtnl_addr_add():\n%s", + __func__, + nm_device_get_iface (dev), + err, + nl_geterror()); rtnl_addr_put (addr); + } else { + nm_warning ("%s(%s): couldn't create rtnl address!\n", + __func__, + nm_device_get_iface (dev)); } - else - nm_warning ("nm_system_device_set_from_ip4_config(): couldn't create rtnl address!\n"); nl_close (nlh); nl_handle_destroy (nlh); - sleep (1); - nm_system_device_set_ip4_route (dev, nm_ip4_config_get_gateway (config), 0, 0, nm_ip4_config_get_mss (config)); + if (!secondary) { + sleep (1); + nm_system_device_set_ip4_route (dev, + nm_ip4_config_get_gateway (config), + 0, + 0, + nm_ip4_config_get_mss (config)); - nm_named_manager_add_ip4_config (app_data->named_manager, config); + nm_named_manager_add_ip4_config (app_data->named_manager, config); + } return TRUE; } diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index ccd020ab06..ffb470f1ec 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -67,7 +67,7 @@ gboolean nm_system_device_get_use_dhcp (NMDevice *dev); gboolean nm_system_device_get_disabled (NMDevice *dev); -gboolean nm_system_device_set_from_ip4_config (NMDevice *dev); +gboolean nm_system_device_set_from_ip4_config (NMDevice *dev, gboolean secondary); gboolean nm_system_vpn_device_set_from_ip4_config (NMNamedManager *named, NMDevice *active_device, const char *iface, NMIP4Config *config, char **routes, int num_routes); gboolean nm_system_vpn_device_unset_from_ip4_config (NMNamedManager *named, NMDevice *active_device, const char *iface, NMIP4Config *config); diff --git a/src/nm-device-802-11-mesh-olpc.c b/src/nm-device-802-11-mesh-olpc.c index b6c0a2112c..4534bf97d5 100644 --- a/src/nm-device-802-11-mesh-olpc.c +++ b/src/nm-device-802-11-mesh-olpc.c @@ -40,27 +40,32 @@ #include "NetworkManagerPolicy.h" -#if USE_AUTOIP #define IPV4LL_NETWORK 0xA9FE0000L #define IPV4LL_NETMASK 0xFFFF0000L #define IPV4LL_HOSTMASK 0x0000FFFFL #define IPV4LL_BROADCAST 0xA9FEFFFFL -#else -#define MESH_DHCP_TIMEOUT 30 /* in seconds */ -#endif +#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" -static void mesh_search_cleanup (NMDevice80211MeshOLPC *self); -#if USE_AUTOIP +static void channel_failure_handler (NMDevice80211MeshOLPC *self, NMActRequest *req); static void aipd_cleanup (NMDevice80211MeshOLPC *self); -#endif -static void mpp_discovery_cleanup (NMDevice80211MeshOLPC *self); -static gboolean mpp_discovery_send_rreq (NMDevice80211MeshOLPC *self); +static void mpp_clear_hash_tables (NMDevice80211MeshOLPC *self); +static void mpp_device_activated_cb (GObject *obj, gpointer user_data); +static void mpp_device_deactivated_cb (GObject *obj, gpointer user_data); +static void mpp_cleanup (NMDevice80211MeshOLPC *self); +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); #define NM_DEVICE_802_11_MESH_OLPC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_802_11_MESH_OLPC, NMDevice80211MeshOLPCPrivate)) -#if USE_AUTOIP struct _autoipd { GPid pid; @@ -69,31 +74,27 @@ struct _autoipd guint32 ip4_addr; }; -#endif struct _ethdev { NMDevice80211Wireless * dev; gulong scan_started_id; gulong scan_done_id; - gulong activation_started_id; - gulong activation_done_id; gboolean scanning; }; -struct _msearch { - GSource * check; - guint32 check_tries; +struct _mpp { + /* Device with the primary connection */ + NMDevice * primary; - GHashTable * fwt; + /* Attach to device activated signals */ + GHashTable * activated_ids; + GHashTable * deactivated_ids; }; -struct _mpp { - GIOChannel * chan; - GSource * chan_src; - int sk; - guint32 tries; - GSource * timeout_src; -}; +#define MESH_S1_SCHOOL_MPP 1 +#define MESH_S2_AP 2 +#define MESH_S3_XO_MPP 3 +#define MESH_S4_P2P_MESH 4 struct _NMDevice80211MeshOLPCPrivate { @@ -102,53 +103,165 @@ struct _NMDevice80211MeshOLPCPrivate guint32 capabilities; - struct _ethdev ethdev; -#if USE_AUTOIP - struct _autoipd aipd; -#endif - struct _mpp mpp; - struct _msearch msearch; + gulong wireless_event_id; + GSource * assoc_timeout; + + struct _ethdev ethdev; + struct _autoipd aipd; + struct _mpp mpp; - /* Theory of operation: + /* Steps: + * + * 1. For each channel in [1, 6, 11]: + * a. try DHCP + * b. if DHCP times out, try next channel + * c. if DHCP response includes a non-link-local IP address, + * then CONNECTED/DONE + * + * 2. Try last successful AP connection + * a. if success then CONNECTED/DONE * - * There are 2 attempts to connect to a mesh. Each attempt - * goes through channels 1, 6, and 11. The first attempt tries mesh - * 'discovery' by checking the mesh firmware forwarding table for changes - * to quickly identify the presence of a mesh on the channel. The second - * attempt just tries to do MPP discovery on each channel in case there - * are not enough mesh members sending traffic during the mesh discovery - * in the first attempt. + * 3. For each channel in [1...14] + * a. try DHCP + * b. if DHCP times out, try next channel + * c. if DHCP response includes a link-local IP address, + * then acquire autoip address and apply DHCP settings (except for + * IP address), CONNECTED/DONE * - * 1) Attempt #1 - for each channel of [1, 6, 11]: - * a) Switch to channel - * b) Does the mesh forwarding table change? - * - Yes: go to (1c) - * - No: another channel to try? - * - Yes: next channel, go to (1a) - * - No: go to (2) - * c) Get an auto-ip address - * d) Does an MPP exist (determined via MPP discovery)? - * - Yes: Done - * - No: another channel to try? - * - Yes: next channel, go to (1a) - * - No: go to (2) - * 2) Attempt #2 - for each channel of [1, 6, 11]: - * a) Switch to channel - * b) Get an auto-ip address - * c) Does an MPP exist (determined via MPP discovery)? - * - Yes: Done - * - No: another channel to try? - * - Yes: next channel, go to (1a) - * - No: fail activation + * 4. Jump to channel 1 + * a. acquire autoip address, CONNECTED/DONE */ - guint32 channel; - guint32 num_channels_tried; - guint32 attempt; + + guint32 step; /* 1, 2, 3, or 4 from behavior description above */ + guint32 channel; struct iw_range range; }; +typedef struct WirelessEventCBData +{ + NMDevice80211MeshOLPC * self; + NMDevice80211Wireless * ethdev; + char * data; + int len; +} WirelessEventCBData; + +static void +wireless_event_cb_data_free (WirelessEventCBData *data) +{ + if (!data) + return; + + g_object_unref (data->self); + g_object_unref (data->ethdev); + g_free (data->data); + g_free (data); +} + +static void +handle_association_event (NMDevice80211MeshOLPC * self) +{ + NMActRequest * req; + NMActStage stage; + + g_return_if_fail (self != NULL); + + if (!nm_device_is_activating (NM_DEVICE (self))) + return; + + req = nm_device_get_act_request (NM_DEVICE (self)); + g_return_if_fail (req != NULL); + + stage = nm_act_request_get_stage (req); + if (stage != NM_ACT_STAGE_DEVICE_CONFIG) + return; + + assoc_timeout_cleanup (self); + nm_device_activate_schedule_stage3_ip_config_start (req); +} + +static gboolean +wireless_event_helper (gpointer user_data) +{ + NMDevice80211MeshOLPC * self; + WirelessEventCBData * cb_data; + struct iw_event iwe_buf, *iwe = &iwe_buf; + char *pos, *end, *custom, *addr; + const char badaddr1[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const char badaddr2[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + const char badaddr3[ETH_ALEN] = { 0x44, 0x44, 0x44, 0x44, 0x44, 0x44 }; + + cb_data = (WirelessEventCBData *) user_data; + g_return_val_if_fail (cb_data != NULL, FALSE); + g_return_val_if_fail (cb_data->data != NULL, FALSE); + g_return_val_if_fail (cb_data->len >= 0, FALSE); + + self = cb_data->self; + pos = cb_data->data; + end = cb_data->data + cb_data->len; + + while (pos + IW_EV_LCP_LEN <= end) { + /* Event data may be unaligned, so make a local, aligned copy + * before processing. + */ + memcpy (&iwe_buf, pos, IW_EV_LCP_LEN); + if (iwe->len <= IW_EV_LCP_LEN) + break; + + custom = pos + IW_EV_POINT_LEN; + memcpy (&iwe_buf, pos, sizeof (struct iw_event)); + custom += IW_EV_POINT_OFF; + + if (iwe->cmd == SIOCGIWAP) { + addr = iwe->u.ap_addr.sa_data; + if ( !memcmp (addr, badaddr1, ETH_ALEN) + || !memcmp (addr, badaddr2, ETH_ALEN) + || !memcmp (addr, badaddr3, ETH_ALEN)) { + /* disassociated */ + } else { + /* associated */ + handle_association_event (self); + } + } + pos += iwe->len; + } + + return FALSE; +} + +static void +nm_device_802_11_mesh_olpc_wireless_event (NmNetlinkMonitor *monitor, + GObject *obj, + char *data, + int data_len, + NMDevice80211MeshOLPC * self) +{ + GSource * source; + WirelessEventCBData * cb_data; + + g_return_if_fail (obj != NULL); + g_return_if_fail (self != NULL); + + /* Make sure signal is for our eth dev */ + if (NM_DEVICE (self->priv->ethdev.dev) != NM_DEVICE (obj)) + return; + + cb_data = g_malloc0 (sizeof (WirelessEventCBData)); + 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); + memcpy (cb_data->data, data, data_len); + cb_data->len = data_len; + + source = g_idle_source_new (); + 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); +} + + static void nm_device_802_11_mesh_olpc_init (NMDevice80211MeshOLPC * self) { @@ -157,6 +270,7 @@ nm_device_802_11_mesh_olpc_init (NMDevice80211MeshOLPC * self) self->priv->is_initialized = FALSE; } +#if 0 guint32 get_random_channel (void) { GRand * rand; @@ -174,6 +288,7 @@ guint32 get_random_channel (void) /* Return a random channel of [1, 6, 11] */ return ((num % 3) * 5) + 1; } +#endif static void real_init (NMDevice *dev) @@ -181,12 +296,26 @@ real_init (NMDevice *dev) NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); struct iwreq wrq; NMSock * sk; + NMData * app_data = nm_device_get_app_data (dev); + NmNetlinkMonitor * monitor; self->priv->is_initialized = TRUE; self->priv->capabilities = 0; - self->priv->channel = get_random_channel (); - self->priv->num_channels_tried = 0; - self->priv->attempt = 1; + + self->priv->step = MESH_S3_XO_MPP; + self->priv->channel = 1; + self->priv->assoc_timeout = NULL; + self->priv->wireless_event_id = 0; + + self->priv->mpp.activated_ids = g_hash_table_new (g_direct_hash, + g_direct_equal); + self->priv->mpp.deactivated_ids = g_hash_table_new (g_direct_hash, + g_direct_equal); + if ( !self->priv->mpp.activated_ids + || !self->priv->mpp.deactivated_ids) { + nm_warning ("%s: couldn't allocate MPP tables."); + mpp_clear_hash_tables (self); + } sk = nm_dev_sock_open (NM_DEVICE (dev), DEV_WIRELESS, __func__, NULL); if (sk) { @@ -203,6 +332,16 @@ real_init (NMDevice *dev) nm_warning ("%s: couldn't open device socket.", nm_device_get_iface (dev)); } + + /* Mesh device is interested when there is no best device so that it + * can jump to the next step in the meta-activation if needed. + */ + nm_policy_add_nbd_notifier (NM_DEVICE (self)); + + monitor = app_data->netlink_monitor; + self->priv->wireless_event_id = + g_signal_connect (G_OBJECT (monitor), "wireless-event", + G_CALLBACK (nm_device_802_11_mesh_olpc_wireless_event), self); } static gboolean @@ -217,9 +356,9 @@ ethdev_scan_approval_hook (NMDevice80211Wireless *ethdev, if (nm_device_is_activating (NM_DEVICE (self))) return FALSE; -fprintf (stderr, "%s: allowing scan for %s\n", - nm_device_get_iface (NM_DEVICE (self)), - nm_device_get_iface (NM_DEVICE (ethdev))); + nm_info ("%s: allowing scan for %s", + nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (ethdev))); return TRUE; } @@ -234,7 +373,7 @@ ethdev_scan_started_cb (GObject * obj, g_return_if_fail (self != NULL); g_return_if_fail (ethdev != NULL); - fprintf (stderr, "%s: scan started event for %s\n", + nm_info ("%s: scan started event for %s", nm_device_get_iface (NM_DEVICE (self)), nm_device_get_iface (NM_DEVICE (ethdev))); @@ -251,7 +390,7 @@ ethdev_scan_done_cb (GObject * obj, g_return_if_fail (self != NULL); g_return_if_fail (ethdev != NULL); - fprintf (stderr, "%s: scan done event for %s\n", + nm_info ("%s: scan done event for %s", nm_device_get_iface (NM_DEVICE (self)), nm_device_get_iface (NM_DEVICE (ethdev))); @@ -266,36 +405,6 @@ ethdev_scan_done_cb (GObject * obj, } static void -ethdev_activation_started_cb (GObject * obj, - gpointer user_data) -{ - NMDevice80211Wireless * ethdev = NM_DEVICE_802_11_WIRELESS (obj); - NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data); - - g_return_if_fail (self != NULL); - g_return_if_fail (ethdev != NULL); - - fprintf (stderr, "%s: activation started event for %s\n", - nm_device_get_iface (NM_DEVICE (self)), - nm_device_get_iface (NM_DEVICE (ethdev))); -} - -static void -ethdev_activation_done_cb (GObject * obj, - gpointer user_data) -{ - NMDevice80211Wireless * ethdev = NM_DEVICE_802_11_WIRELESS (obj); - NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data); - - g_return_if_fail (self != NULL); - g_return_if_fail (ethdev != NULL); - - fprintf (stderr, "%s: activation done event for %s\n", - nm_device_get_iface (NM_DEVICE (self)), - nm_device_get_iface (NM_DEVICE (ethdev))); -} - -static void setup_ethdev (NMDevice80211MeshOLPC *self, NMDevice80211Wireless *ethdev) { @@ -327,16 +436,6 @@ setup_ethdev (NMDevice80211MeshOLPC *self, "scan-done", G_CALLBACK (ethdev_scan_done_cb), self); - ethdev_rec->activation_started_id = - g_signal_connect (G_OBJECT (NM_DEVICE (ethdev)), - "activation-started", - G_CALLBACK (ethdev_activation_started_cb), - self); - ethdev_rec->activation_done_id = - g_signal_connect (G_OBJECT (NM_DEVICE (ethdev)), - "activation-done", - G_CALLBACK (ethdev_activation_done_cb), - self); } static void @@ -356,10 +455,6 @@ cleanup_ethdev (NMDevice80211MeshOLPC *self) ethdev_rec->scan_started_id = 0; g_signal_handler_disconnect (G_OBJECT (ethdev), ethdev_rec->scan_done_id); ethdev_rec->scan_done_id = 0; - g_signal_handler_disconnect (G_OBJECT (ethdev), ethdev_rec->activation_started_id); - ethdev_rec->activation_started_id = 0; - g_signal_handler_disconnect (G_OBJECT (ethdev), ethdev_rec->activation_done_id); - ethdev_rec->activation_done_id = 0; ethdev_rec->scanning = FALSE; @@ -371,6 +466,40 @@ cleanup_ethdev (NMDevice80211MeshOLPC *self) } static void +connect_to_device_signals (NMDevice80211MeshOLPC *self, NMDevice *dev) +{ + guint32 act_id, deact_id, act_fail_id; + + g_return_if_fail (self != NULL); + g_return_if_fail (dev != NULL); + + /* If there wasn't enough memory for the activated/deactivated signal + * hash tables, don't connect to the signals. + */ + if (!self->priv->mpp.activated_ids || !self->priv->mpp.deactivated_ids) + return; + + /* Attach to the activation success & deactivated signals of every + * device known about so far. + */ + act_id = g_signal_connect (G_OBJECT (dev), + "activation-success", + G_CALLBACK (mpp_device_activated_cb), + self); + g_hash_table_insert (self->priv->mpp.activated_ids, + dev, + GUINT_TO_POINTER (act_id)); + + deact_id = g_signal_connect (G_OBJECT (dev), + "deactivated", + G_CALLBACK (mpp_device_deactivated_cb), + self); + g_hash_table_insert (self->priv->mpp.activated_ids, + dev, + GUINT_TO_POINTER (deact_id)); +} + +static void real_start (NMDevice *dev) { NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); @@ -380,22 +509,27 @@ real_start (NMDevice *dev) g_assert (mesh_physdev); - /* Find the 802.11 non-mesh device if HAL knows about it already */ nm_lock_mutex (data->dev_list_mutex, __FUNCTION__); + /* Two things to do... Find the 802.11 non-mesh device if HAL knows about + * it already, and attach to the 'activation success' and 'deactivated' + * signals of every device to turn on/off the MPP functionality. + */ for (elt = data->dev_list; elt != NULL; elt = g_slist_next (elt)) { - NMDevice * ethdev = (NMDevice *)(elt->data); - const char * eth_physdev; - - if (!nm_device_is_802_11_wireless (ethdev)) - continue; - eth_physdev = nm_device_get_physical_device_udi (ethdev); - if (!eth_physdev) - continue; - if (strcmp (mesh_physdev, eth_physdev) == 0) { - setup_ethdev (self, NM_DEVICE_802_11_WIRELESS (ethdev)); - break; + NMDevice * otherdev = NM_DEVICE (elt->data); + + /* Find and attach to the companion wireless device */ + if (nm_device_is_802_11_wireless (otherdev)) { + const char * eth_physdev = nm_device_get_physical_device_udi (otherdev); + if (eth_physdev) { + if (strcmp (mesh_physdev, eth_physdev) == 0) + setup_ethdev (self, NM_DEVICE_802_11_WIRELESS (otherdev)); + } } + + /* Connect to the devices' activated and deactivated signals */ + if (otherdev != NM_DEVICE (self)) + connect_to_device_signals (self, otherdev); } nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); @@ -417,33 +551,31 @@ real_notify_device_added (NMDevice *dev, { NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); const char * mesh_physdev = nm_device_get_physical_device_udi (dev); - const char * eth_physdev = NULL; GSource * source; if (dev == added_dev) return; - if (self->priv->ethdev.dev || !nm_device_is_802_11_wireless (added_dev)) - return; - - eth_physdev = nm_device_get_physical_device_udi (added_dev); - if (!eth_physdev) - return; - - if (strcmp (mesh_physdev, eth_physdev) != 0) - return; - - setup_ethdev (self, NM_DEVICE_802_11_WIRELESS (added_dev)); - - /* schedule a link change for later since this function - * is called with the device list lock held. - */ - source = g_idle_source_new (); - if (source) { - g_source_set_callback (source, link_active_cb, self, NULL); - g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); - g_source_unref (source); + /* Find and attach to the companion wireless device */ + if (!self->priv->ethdev.dev && nm_device_is_802_11_wireless (added_dev)) { + const char * eth_physdev = nm_device_get_physical_device_udi (added_dev); + if (eth_physdev && !strcmp (mesh_physdev, eth_physdev)) { + setup_ethdev (self, NM_DEVICE_802_11_WIRELESS (added_dev)); + + /* schedule a link change for later since this function + * is called with the device list lock held. + */ + source = g_idle_source_new (); + if (source) { + g_source_set_callback (source, link_active_cb, self, NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); + } + } } + + /* Connect to the devices' activated and deactivated signals */ + connect_to_device_signals (self, added_dev); } static gboolean @@ -454,6 +586,13 @@ link_inactive_cb (gpointer user_data) } static void +dev_removed_disconnect_from_signal (gpointer key, gpointer value, gpointer user_data) +{ + if (NM_DEVICE (key) == NM_DEVICE (user_data)) + g_signal_handler_disconnect (G_OBJECT (key), GPOINTER_TO_UINT (value)); +} + +static void real_notify_device_removed (NMDevice *dev, NMDevice *removed_dev) { @@ -463,24 +602,38 @@ real_notify_device_removed (NMDevice *dev, if (dev == removed_dev) return; - if (!self->priv->ethdev.dev) - return; + if ( self->priv->ethdev.dev + && self->priv->ethdev.dev == NM_DEVICE_802_11_WIRELESS (removed_dev)) { + cleanup_ethdev (self); - if ( !nm_device_is_802_11_wireless (removed_dev) - || (self->priv->ethdev.dev != NM_DEVICE_802_11_WIRELESS (removed_dev))) - return; + /* schedule a link change for later since this function + * is called with the device list lock held. + */ + source = g_idle_source_new (); + if (source) { + g_source_set_callback (source, link_inactive_cb, self, NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); + } + } - cleanup_ethdev (self); + /* Disconnect from devices' activated/deactivated signals */ + if (self->priv->mpp.activated_ids) { + g_hash_table_foreach (self->priv->mpp.activated_ids, + dev_removed_disconnect_from_signal, + removed_dev); + } + if (self->priv->mpp.deactivated_ids) { + g_hash_table_foreach (self->priv->mpp.deactivated_ids, + dev_removed_disconnect_from_signal, + removed_dev); + } - /* schedule a link change for later since this function - * is called with the device list lock held. + /* If we are an MPP and the removed device was the one providing + * the primary connection, stop being an MPP. */ - source = g_idle_source_new (); - if (source) { - g_source_set_callback (source, link_inactive_cb, self, NULL); - g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); - g_source_unref (source); - } + if (removed_dev = self->priv->mpp.primary) + mpp_cleanup (self); } static void @@ -488,11 +641,9 @@ real_deactivate_quickly (NMDevice *dev) { NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); - mpp_discovery_cleanup (self); -#if USE_AUTOIP + mpp_cleanup (self); aipd_cleanup (self); -#endif - mesh_search_cleanup (self); + assoc_timeout_cleanup (self); } @@ -516,29 +667,30 @@ real_get_type_capabilities (NMDevice *dev) } static int -get_80211_mode (NMDevice80211MeshOLPC *self) +get_80211_mode (NMDevice80211Wireless * dev) { NMSock * sk; int mode = -1; struct iwreq wrq; int err; - g_return_val_if_fail (self != NULL, -1); + g_return_val_if_fail (dev != NULL, -1); /* Force the card into Managed/Infrastructure mode */ - sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __func__, NULL); + sk = nm_dev_sock_open (NM_DEVICE (dev), DEV_WIRELESS, __func__, NULL); if (!sk) { - nm_warning ("%s: failed to open device socket.", nm_device_get_iface (NM_DEVICE (self))); + nm_warning ("%s: failed to open device socket.", + nm_device_get_iface (NM_DEVICE (dev))); return -1; } err = iw_get_ext (nm_dev_sock_get_fd (sk), - nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (dev)), SIOCGIWMODE, &wrq); if (err) { nm_warning ("%s: failed to get device mode (errno: %d).", - nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (dev)), errno); goto out; } @@ -551,7 +703,7 @@ out: } static gboolean -set_80211_mode (NMDevice80211MeshOLPC *self, +set_80211_mode (NMDevice80211Wireless *dev, int mode) { NMSock * sk; @@ -559,26 +711,27 @@ set_80211_mode (NMDevice80211MeshOLPC *self, struct iwreq wrqu; int err; - g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (dev != NULL, FALSE); g_return_val_if_fail ((mode == IW_MODE_INFRA) || (mode == IW_MODE_ADHOC), FALSE); - if (get_80211_mode (self) == mode) + if (get_80211_mode (dev) == mode) return TRUE; - sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __func__, NULL); + sk = nm_dev_sock_open (NM_DEVICE (dev), DEV_WIRELESS, __func__, NULL); if (!sk) { - nm_warning ("%s: failed to open device socket.", nm_device_get_iface (NM_DEVICE (self))); + nm_warning ("%s: failed to open device socket.", + nm_device_get_iface (NM_DEVICE (dev))); return FALSE; } wrqu.u.mode = mode; err = iw_set_ext (nm_dev_sock_get_fd (sk), - nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (dev)), SIOCSIWMODE, &wrqu); if (err) { nm_warning ("%s: failed to set device mode to %d (errno: %d).", - nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (dev)), mode, errno); goto out; @@ -592,18 +745,19 @@ out: } static gboolean -clear_80211_keys (NMDevice80211MeshOLPC *self) +clear_80211_keys (NMDevice80211Wireless *dev) { NMSock * sk; struct iwreq wrqu; gboolean success = FALSE; int err; - g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (dev != NULL, FALSE); - sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __func__, NULL); + sk = nm_dev_sock_open (NM_DEVICE (dev), DEV_WIRELESS, __func__, NULL); if (!sk) { - nm_warning ("%s: failed to open device socket.", nm_device_get_iface (NM_DEVICE (self))); + nm_warning ("%s: failed to open device socket.", + nm_device_get_iface (NM_DEVICE (dev))); return FALSE; } @@ -612,12 +766,12 @@ clear_80211_keys (NMDevice80211MeshOLPC *self) wrqu.u.data.flags = IW_ENCODE_DISABLED | IW_ENCODE_NOKEY; err = iw_set_ext (nm_dev_sock_get_fd (sk), - nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (dev)), SIOCSIWENCODE, &wrqu); if (err) { nm_warning ("%s: failed to clear encryption keys (errno: %d).", - nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (dev)), errno); goto out; } @@ -630,7 +784,7 @@ out: } static gboolean -set_80211_ssid (NMDevice80211MeshOLPC *self, +set_80211_ssid (NMDevice80211Wireless *dev, const char *ssid, const guint32 ssid_len) { @@ -641,7 +795,7 @@ set_80211_ssid (NMDevice80211MeshOLPC *self, guint32 safe_len = (ssid_len > IW_ESSID_MAX_SIZE) ? IW_ESSID_MAX_SIZE : ssid_len; gboolean success = FALSE; - g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (dev != NULL, FALSE); /* Make sure the essid we get passed is a valid size */ if (!ssid || !ssid_len) { @@ -651,9 +805,10 @@ set_80211_ssid (NMDevice80211MeshOLPC *self, memcpy (safe_ssid, ssid, safe_len); } - sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __func__, NULL); + sk = nm_dev_sock_open (NM_DEVICE (dev), DEV_WIRELESS, __func__, NULL); if (!sk) { - nm_warning ("%s: failed to open device socket.", nm_device_get_iface (NM_DEVICE (self))); + nm_warning ("%s: failed to open device socket.", + nm_device_get_iface (NM_DEVICE (dev))); return FALSE; } @@ -662,12 +817,12 @@ set_80211_ssid (NMDevice80211MeshOLPC *self, wrqu.u.essid.flags = 1; /* Enable essid on card */ err = iw_set_ext (nm_dev_sock_get_fd (sk), - nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (dev)), SIOCSIWESSID, &wrqu); if (err) { nm_warning ("%s: failed to set SSID (errno: %d).", - nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_iface (NM_DEVICE (dev)), errno); goto out; } @@ -682,7 +837,7 @@ out: static int -get_80211_channel (NMDevice80211MeshOLPC *self) +get_80211_channel (NMDevice80211Wireless *dev, struct iw_range * range) { NMSock * sk; int err; @@ -691,10 +846,10 @@ get_80211_channel (NMDevice80211MeshOLPC *self) struct iwreq wrqu; const char * iface; - g_return_val_if_fail (self != NULL, -1); + g_return_val_if_fail (dev != NULL, -1); - iface = nm_device_get_iface (NM_DEVICE (self)); - sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __func__, NULL); + iface = nm_device_get_iface (NM_DEVICE (dev)); + sk = nm_dev_sock_open (NM_DEVICE (dev), DEV_WIRELESS, __func__, NULL); if (!sk) { nm_warning ("%s: failed to open device socket.", iface); return -1; @@ -709,7 +864,7 @@ get_80211_channel (NMDevice80211MeshOLPC *self) } freq = iw_freq2float (&wrqu.u.freq); - channel = iw_freq_to_channel (freq, &(self->priv->range)); + channel = iw_freq_to_channel (freq, range); if (channel == -1) { /* Already a channel # */ channel = (int) freq; @@ -721,8 +876,9 @@ out: } static gboolean -set_80211_channel (NMDevice80211MeshOLPC *self, - int channel) +set_80211_channel (NMDevice80211Wireless *dev, + int channel, + struct iw_range * range) { NMSock * sk; int err; @@ -731,14 +887,14 @@ set_80211_channel (NMDevice80211MeshOLPC *self, int skfd; const char * iface; - g_return_val_if_fail (self != NULL, FALSE); + g_return_val_if_fail (dev != NULL, FALSE); - if ((channel > 0) && (get_80211_channel (self) == channel)) + if ((channel > 0) && (get_80211_channel (dev, range) == channel)) return TRUE; - iface = nm_device_get_iface (NM_DEVICE (self)); + iface = nm_device_get_iface (NM_DEVICE (dev)); - sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __func__, NULL); + sk = nm_dev_sock_open (NM_DEVICE (dev), DEV_WIRELESS, __func__, NULL); if (!sk) { nm_warning ("%s: failed to open device socket.", iface); return FALSE; @@ -786,10 +942,124 @@ out: /*************************************************************/ -/* avahi-autoipd babysitting junk because it doesn't do DBus */ +/* Mesh Portal Pointer service stuff */ /*************************************************************/ -#if USE_AUTOIP +static gboolean +is_mpp_active (NMDevice80211MeshOLPC *self) +{ + g_return_val_if_fail (self != NULL, FALSE); + + return !!(self->priv->mpp.primary); +} + +static void +mpp_cleanup (NMDevice80211MeshOLPC *self) +{ + NMIP4Config * config; + + if (self->priv->mpp.primary) { + g_object_unref (self->priv->mpp.primary); + self->priv->mpp.primary = NULL; + } + + /* Remove any device nameservers and domains */ + if (nm_device_get_ip4_config (NM_DEVICE (self))) + nm_device_set_ip4_config (NM_DEVICE (self), NULL); + + nm_system_device_flush_routes (NM_DEVICE (self)); + nm_system_device_flush_addresses (NM_DEVICE (self)); + nm_device_update_ip4_address (NM_DEVICE (self)); +} + +static void +mpp_aipd_timeout (NMDevice80211MeshOLPC *self) +{ + g_return_if_fail (self != NULL); + + mpp_cleanup (self); +} + +static void +mpp_autoip_success (NMDevice80211MeshOLPC *self) +{ + NMIP4Config * config; + + g_return_if_fail (self != NULL); + g_return_if_fail (self->priv->mpp.primary != NULL); + + config = nm_ip4_config_new (); + nm_ip4_config_set_address (config, self->priv->aipd.ip4_addr); + nm_ip4_config_set_netmask (config, (guint32)(ntohl (IPV4LL_NETMASK))); + nm_ip4_config_set_broadcast (config, (guint32)(ntohl (IPV4LL_BROADCAST))); + nm_ip4_config_set_gateway (config, 0); + nm_device_set_ip4_config (NM_DEVICE (self), config); + + nm_system_device_set_from_ip4_config (NM_DEVICE (self), TRUE); + + +} + +static void +mpp_device_activated_cb (GObject * obj, + gpointer user_data) +{ + NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data); + NMDevice * primary_dev = NM_DEVICE (obj); + const char * iface; + + g_return_if_fail (self != NULL); + g_return_if_fail (primary_dev != NULL); + + if (self->priv->mpp.primary) + mpp_cleanup (self); + + self->priv->mpp.primary = primary_dev; + 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); + } + } else { + nm_warning ("%s: MPP couldn't start avahi-autoipd.", iface); + } + +out: + return; +} + +static void +mpp_device_deactivated_cb (GObject * obj, + gpointer user_data) +{ + NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data); + NMDevice * primary_dev = NM_DEVICE (obj); + + g_return_if_fail (self != NULL); + g_return_if_fail (primary_dev != NULL); + + 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)); + + mpp_cleanup (self); +} + + +/*************************************************************/ +/* avahi-autoipd babysitting junk because it doesn't do DBus */ +/*************************************************************/ static void aipd_remove_timeout (NMDevice80211MeshOLPC *self) @@ -809,7 +1079,12 @@ aipd_cleanup (NMDevice80211MeshOLPC *self) { g_return_if_fail (self != NULL); + nm_info ("%s: called", __func__); + if (self->priv->aipd.pid > 0) { + nm_info ("%s: Will kill avahi-autoipd pid %d", + __func__, + self->priv->aipd.pid); kill (self->priv->aipd.pid, SIGKILL); self->priv->aipd.pid = -1; } @@ -851,7 +1126,7 @@ aipd_watch_cb (GPid pid, } static void -supplicant_child_setup (gpointer user_data G_GNUC_UNUSED) +aipd_child_setup (gpointer user_data G_GNUC_UNUSED) { /* We are in the child process at this point. * Give child it's own program group for signal @@ -874,7 +1149,7 @@ aipd_exec (NMDevice80211MeshOLPC *self) argv[2] = NULL; success = g_spawn_async ("/", argv, NULL, 0, - &supplicant_child_setup, NULL, &pid, &error); + &aipd_child_setup, NULL, &pid, &error); if (!success) { if (error) { nm_warning ("Couldn't start avahi-autoipd. Error: (%d) %s", @@ -894,8 +1169,12 @@ aipd_exec (NMDevice80211MeshOLPC *self) } self->priv->aipd.watch = g_child_watch_source_new (pid); - if (!self->priv->aipd.watch) + if (!self->priv->aipd.watch) { + nm_info ("%s: returning failure pid %d", + __func__, + self->priv->aipd.pid); return FALSE; + } g_source_set_callback (self->priv->aipd.watch, (GSourceFunc) aipd_watch_cb, self, @@ -903,6 +1182,7 @@ aipd_exec (NMDevice80211MeshOLPC *self) g_source_attach (self->priv->aipd.watch, nm_device_get_main_context (NM_DEVICE (self))); g_source_unref (self->priv->aipd.watch); + nm_info ("%s: returning success pid %d", __func__, self->priv->aipd.pid); return TRUE; } @@ -918,8 +1198,12 @@ aipd_timeout_cb (gpointer user_data) return FALSE; nm_info ("%s: avahi-autoipd timed out.", nm_device_get_iface (dev)); - nm_policy_schedule_activation_failed (nm_device_get_act_request (dev)); - + if (nm_device_is_activating (NM_DEVICE (self))) { + channel_failure_handler (self, nm_device_get_act_request (dev)); + } else if (is_mpp_active (self)) { + /* Trying to get IP address for starting MPP */ + mpp_aipd_timeout (self); + } return FALSE; } @@ -959,290 +1243,166 @@ out: return success; } -#endif /* USE_AUTOIP */ /*************************************************************/ -/* Mesh Search stuff */ -/*************************************************************/ static void -mesh_search_cleanup (NMDevice80211MeshOLPC * self) +channel_failure_handler (NMDevice80211MeshOLPC *self, NMActRequest *req) { - if (self->priv->msearch.check) { - g_source_destroy (self->priv->msearch.check); - g_source_unref (self->priv->msearch.check); - self->priv->msearch.check = NULL; - } + gboolean fail = FALSE; - self->priv->msearch.check_tries = 0; + g_return_if_fail (self != NULL); + g_return_if_fail (req != NULL); - if (self->priv->msearch.fwt) { - g_hash_table_unref (self->priv->msearch.fwt); - self->priv->msearch.fwt = NULL; + switch (self->priv->step) { + case MESH_S1_SCHOOL_MPP: + if (self->priv->channel == 11) { + fail = TRUE; + break; + } + self->priv->channel += 5; + break; + case MESH_S3_XO_MPP: + if (self->priv->channel == 3) { + fail = TRUE; + break; + } + self->priv->channel++; + break; + default: + nm_info ("%s: %s/%d unhandled step %d\n", + nm_device_get_iface (NM_DEVICE (self)), + __func__, __LINE__, self->priv->step); + break; } -} -#define WLANIOCTL SIOCIWFIRSTPRIV -#define WLAN_SET128CHAR_GET128CHAR (WLANIOCTL + 25) -#define WLAN_SUBCMD_FWT_LIST 25 + if (fail) { + nm_policy_schedule_activation_failed (req); + } else { + nm_info ("Activation (%s/mesh) failed to find a mesh on channel %d.", + nm_device_get_iface (NM_DEVICE (self)), + self->priv->channel); + real_deactivate_quickly (NM_DEVICE (self)); + nm_device_activate_schedule_stage2_device_config (req); + } +} -static gboolean -mesh_search_get_fwt (NMDevice80211MeshOLPC * self, GSList ** list) +static NMActStageReturn +real_act_stage1_prepare (NMDevice *dev, NMActRequest *req) { - NMDevice * dev = NM_DEVICE (self); - NMSock * sk; - int num = 0; - const char * iface; - gboolean success = TRUE; - - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (list != NULL, FALSE); + NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); - iface = nm_device_get_iface (dev); + nm_device_set_active_link (dev, TRUE); - sk = nm_dev_sock_open (dev, DEV_WIRELESS, __func__, NULL); - if (!sk) - return FALSE; + /* Stop being an MPP if we currently are one */ + if (self->priv->mpp.primary) + mpp_cleanup (self); - while (num < 500) { - char buf[200]; - struct iwreq wrq; - int err, len, i = 0; - char * item; + /* Have to wait until ethdev is done scanning before continuing */ + if (self->priv->ethdev.scanning) + return NM_ACT_STAGE_RETURN_POSTPONE; - memset (buf, 0, sizeof (buf)); - memset (&wrq, 0, sizeof (wrq)); - strncpy (wrq.ifr_name, iface, IFNAMSIZ); - wrq.u.data.pointer = (caddr_t) &buf[0]; - wrq.u.data.length = sizeof (buf) - 1; - wrq.u.data.flags = WLAN_SUBCMD_FWT_LIST; - err = ioctl (nm_dev_sock_get_fd (sk), WLAN_SET128CHAR_GET128CHAR, &wrq); - if (err < 0) { - nm_warning ("%s: couldn't get FWT list. error %d", iface, err); - if (i == 0) - success = FALSE; - break; - } - len = wrq.u.data.length; + return NM_ACT_STAGE_RETURN_SUCCESS; +} - /* Check if we're done */ - if ((len == 0) || !strcmp (buf, " (null)") || !strlen (buf)) - break; - while ((i < len) && ((buf[i] == ' ') || (buf[i] == ':') || (buf[i] == '0'))) - i++; - if (i >= len) - break; /* All zeros, we're done too */ - - if (len < 35) { - nm_warning ("%s: FWT entry too short.", iface); - continue; - } - buf[sizeof (buf) - 1] = '\0'; - item = g_strdup (buf); - if (!item) { - nm_warning ("%s: not enough memory for FWT entry.", iface); - continue; - } - num++; - *list = g_slist_append (*list, item); - } +static void +assoc_timeout_cleanup (NMDevice80211MeshOLPC * self) +{ + if (!self->priv->assoc_timeout) + return; -out: - nm_dev_sock_close (sk); - return success; + g_source_destroy (self->priv->assoc_timeout); + self->priv->assoc_timeout = NULL; } static gboolean -mesh_search_check_cb (gpointer user_data) +assoc_timeout_cb (gpointer user_data) { - NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data); NMDevice * dev = NM_DEVICE (user_data); - GSList * list = NULL; - GSList * elt; - gboolean again = TRUE; + NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); NMActRequest * req; + NMActStage stage; - req = nm_device_get_act_request (dev); - if ( !req - || (nm_act_request_get_stage (req) != NM_ACT_STAGE_DEVICE_CONFIG) - || nm_device_activation_should_cancel (dev)) { - /* Must have been cancelled */ - return FALSE; - } - - self->priv->msearch.check_tries++; - if (self->priv->msearch.check_tries > 5) { - nm_info ("Activation (%s/mesh) Stage 2 of 6 (Device Configure) no mesh " - "found on channel %d.", - nm_device_get_iface (dev), - self->priv->channel); - mesh_search_cleanup (self); - nm_policy_schedule_activation_failed (req); - return FALSE; - } + g_return_val_if_fail (self != NULL, FALSE); - if (!mesh_search_get_fwt (self, &list)) { - nm_warning ("%s: could not get FWT list.", nm_device_get_iface (dev)); + if ( !self->priv->assoc_timeout + || !nm_device_is_activating (NM_DEVICE (self))) goto out; - } - /* If there's even one entry in the table, we have a mesh */ - if (list && list->data && strlen (list->data)) { - again = FALSE; - mesh_search_cleanup (self); - nm_device_activate_schedule_stage3_ip_config_start (req); - } + req = nm_device_get_act_request (NM_DEVICE (self)); + g_return_val_if_fail (req != NULL, FALSE); -#if 0 - /* Match all returned FWT entries with ones in the saved table. If there - * are any entries _not_ in the saved table, there's a mesh on this channel. - */ - for (elt = list; elt; elt = g_slist_next (elt)) { - if (!g_hash_table_lookup (self->priv->msearch.fwt, elt->data)) { - again = FALSE; - mesh_search_cleanup (self); - nm_device_activate_schedule_stage3_ip_config_start (req); - break; - } - } -#endif + 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); - g_slist_foreach (list, (GFunc) g_free, NULL); - g_slist_free (list); + channel_failure_handler (self, req); out: - return again; + return FALSE; } -#define WLAN_SETNONE_GETNONE (WLANIOCTL + 8) -#define WLAN_SUBCMD_FWT_RESET 14 - -static gboolean -mesh_search_fwt_reset (NMDevice80211MeshOLPC * self) +static void +assoc_timeout_done (gpointer user_data) { - NMSock * sk; - struct iwreq wrq; - int err; - const char * iface; - gboolean success = TRUE; - - g_return_val_if_fail (self != NULL, FALSE); - - iface = nm_device_get_iface (NM_DEVICE (self)); - - sk = nm_dev_sock_open (NM_DEVICE (self), DEV_WIRELESS, __func__, NULL); - if (!sk) - return FALSE; - - memset (&wrq, 0, sizeof (wrq)); - strncpy (wrq.ifr_name, iface, IFNAMSIZ); - wrq.u.data.flags = WLAN_SUBCMD_FWT_RESET; - err = ioctl (nm_dev_sock_get_fd (sk), WLAN_SETNONE_GETNONE, &wrq); - if (err < 0) { - nm_warning ("%s: couldn't reset FWT. error %d", iface, err); - goto out; - } - success = TRUE; + NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data); -out: - nm_dev_sock_close (sk); - return success; + self->priv->assoc_timeout = NULL; } static gboolean -mesh_search_begin (NMDevice80211MeshOLPC * self) +assoc_timeout_start (NMDevice80211MeshOLPC *self) { - GSList * list = NULL; - GSList * elt; gboolean success = FALSE; - GMainContext * context; g_return_val_if_fail (self != NULL, FALSE); - mesh_search_cleanup (self); - - if (!mesh_search_fwt_reset (self)) { - nm_warning ("%s: couldn't clear mesh FWT.", - nm_device_get_iface (NM_DEVICE (self))); - goto out; - } - -#if 0 - if (!mesh_search_get_fwt (self, &list)) - return FALSE; - - self->priv->msearch.fwt = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - if (!self->priv->msearch.fwt) { - nm_warning ("%s: not enough memory for mesh search table.", - nm_device_get_iface (NM_DEVICE (self))); - g_slist_foreach (list, (GFunc) g_free, NULL); + self->priv->assoc_timeout = g_timeout_source_new (3000); + if (!self->priv->assoc_timeout) goto out; - } - /* Walk the list and add items to the hash table */ - for (elt = list; elt; elt = g_slist_next (elt)) { - g_hash_table_insert (self->priv->msearch.fwt, - (gpointer) elt->data, - GINT_TO_POINTER (1)); - } -#endif - - self->priv->msearch.check = g_timeout_source_new (750); - if (!self->priv->msearch.check) - goto out; - context = nm_device_get_main_context (NM_DEVICE (self)); - g_source_set_callback (self->priv->msearch.check, - mesh_search_check_cb, + g_source_set_callback (self->priv->assoc_timeout, + assoc_timeout_cb, self, - NULL); - g_source_attach (self->priv->msearch.check, context); + assoc_timeout_done); + g_source_attach (self->priv->assoc_timeout, + nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (self->priv->assoc_timeout); success = TRUE; out: -#if 0 - g_slist_free (list); -#endif return success; } - -/*************************************************************/ - - -static NMActStageReturn -real_act_stage1_prepare (NMDevice *dev, NMActRequest *req) -{ - NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); - - nm_device_set_active_link (dev, TRUE); - - /* Have to wait until ethdev is done scanning before continuing */ - if (self->priv->ethdev.scanning) - return NM_ACT_STAGE_RETURN_POSTPONE; - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - static NMActStageReturn real_act_stage2_config (NMDevice *dev, NMActRequest *req) { NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + GSource * source; - if (!clear_80211_keys (self)) + if (!clear_80211_keys (self->priv->ethdev.dev)) goto out; - /* Mesh interface should be in adhoc mode */ - if (!set_80211_mode (self, IW_MODE_ADHOC)) + if (!set_80211_mode (self->priv->ethdev.dev, IW_MODE_ADHOC)) goto out; - if (!set_80211_channel (self, self->priv->channel)) + if (!set_80211_channel (self->priv->ethdev.dev, self->priv->channel, &self->priv->range)) { + /* Just fail this channel, not the entire activation */ + channel_failure_handler (self, req); + ret = NM_ACT_STAGE_RETURN_POSTPONE; goto out; + } #define MESH_SSID "olpc-mesh" - if (!set_80211_ssid (self, MESH_SSID, strlen (MESH_SSID))) + if (!set_80211_ssid (self->priv->ethdev.dev, MESH_SSID, strlen (MESH_SSID))) goto out; nm_info ("Activation (%s/mesh) Stage 2 of 6 (Device Configure) looking for " @@ -1250,57 +1410,110 @@ real_act_stage2_config (NMDevice *dev, nm_device_get_iface (NM_DEVICE (self)), self->priv->channel); - /* Start looking for a mesh */ - if (self->priv->attempt == 1) { - if (!mesh_search_begin (self)) - goto out; - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { - ret = NM_ACT_STAGE_RETURN_SUCCESS; - } + ret = NM_ACT_STAGE_RETURN_POSTPONE; out: return ret; } + +#define BUF_SIZE 100 +#define ETC_DHCLIENT_CONF_PATH "/etc/dhclient.conf" + static NMActStageReturn -real_act_stage3_ip_config_start (NMDevice *dev, - NMActRequest *req) +setup_for_mpp (NMDevice80211MeshOLPC * self, + NMActRequest * req, + const char * ip4, + const char * mac) { - NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - NMData * data = NULL; - const char * iface = nm_device_get_iface (dev); + NMDevice80211MeshOLPCClass * klass; + NMDeviceClass * parent_class; + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + const char * iface = nm_device_get_iface (NM_DEVICE (self)); + char buf[BUF_SIZE]; + int fd, written; - data = nm_act_request_get_data (req); - g_assert (data); +#if 0 + nm_system_device_add_route_via_device_with_iface (iface, ip4); -#if USE_AUTOIP - if (!aipd_exec (self)) { - nm_warning ("Activation (%s/mesh): couldn't start avahi-autoipd.", - iface); + 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 - if (!aipd_monitor_start (self)) { - nm_warning ("Activation (%s/mesh): couldn't monitor avahi-autoipd.", - iface); + snprintf (buf, BUF_SIZE, + "interface \"%s\" {\n" + " initial-interval 1;\n" + " anycast-mac ethernet %s\n" + "}\n", + iface, mac); + + fd = open (ETC_DHCLIENT_CONF_PATH, O_RDWR | O_CREAT | O_TRUNC); + if (fd < 0) { + nm_warning ("Couldn't open /etc/hosts: %s", strerror (errno)); goto out; } - ret = NM_ACT_STAGE_RETURN_POSTPONE; -#else - { - NMDevice80211MeshOLPCClass * klass; - NMDeviceClass * parent_class; - - /* Chain up to parent */ - nm_act_request_set_dhcp_timeout_wait (req, MESH_DHCP_TIMEOUT); - 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_stage3_ip_config_start (dev, req); + /* write it out */ + written = write (fd, buf, strlen (buf)); + if (written < 0) { + nm_warning ("Error writing dhclient.conf: %s", strerror (errno)); + goto close; + } else if (written != strlen (buf)) { + nm_warning ("Error writing dhclient.conf: output truncated."); + goto close; + } + + /* Chain up to parent */ + nm_act_request_set_dhcp_timeout_wait (req, MESH_DHCP_TIMEOUT); + 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_stage3_ip_config_start (NM_DEVICE (self), req); + +close: + close (fd); +out: + return ret; +} + +static NMActStageReturn +real_act_stage3_ip_config_start (NMDevice *dev, + NMActRequest *req) +{ + NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); + NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; + const char * iface = nm_device_get_iface (dev); + + switch (self->priv->step) { + case MESH_S1_SCHOOL_MPP: + ret = setup_for_mpp (self, req, SCHOOL_ANYCAST_IP4, SCHOOL_ANYCAST_MAC); + break; + case MESH_S3_XO_MPP: + ret = setup_for_mpp (self, req, XO_ANYCAST_IP4, XO_ANYCAST_MAC); + break; + case MESH_S4_P2P_MESH: + if (!aipd_exec (self)) { + nm_warning ("Activation (%s/mesh): couldn't start avahi-autoipd.", + iface); + goto out; + } + if (!aipd_monitor_start (self)) { + nm_warning ("Activation (%s/mesh): couldn't monitor avahi-autoipd.", + iface); + goto out; + } + 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); + break; } -#endif out: return ret; @@ -1316,9 +1529,9 @@ real_act_stage4_ip_config_timeout (NMDevice *self, g_assert (req); - /* No DHCP reply; fail association */ - nm_info ("No DHCP reply received."); - return NM_ACT_STAGE_RETURN_FAILURE; + /* No DHCP reply; next iteration */ + channel_failure_handler (NM_DEVICE_802_11_MESH_OLPC (self), req); + return NM_ACT_STAGE_RETURN_POSTPONE; } static NMActStageReturn @@ -1329,461 +1542,265 @@ real_act_stage4_get_ip4_config (NMDevice *dev, NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMIP4Config * real_config = NULL; + NMDevice80211MeshOLPCClass * klass; + NMDeviceClass * parent_class; + const char * iface = nm_device_get_iface (dev); -#if USE_AUTOIP g_return_val_if_fail (config != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (*config == NULL, NM_ACT_STAGE_RETURN_FAILURE); - real_config = nm_ip4_config_new (); - nm_ip4_config_set_address (real_config, self->priv->aipd.ip4_addr); - nm_ip4_config_set_netmask (real_config, (guint32)(ntohl (IPV4LL_NETMASK))); - nm_ip4_config_set_broadcast (real_config, (guint32)(ntohl (IPV4LL_BROADCAST))); - nm_ip4_config_set_gateway (real_config, 0); - - ret = NM_ACT_STAGE_RETURN_SUCCESS; -#else - { - NMDevice80211MeshOLPCClass * klass; - NMDeviceClass * parent_class; + switch (self->priv->step) { + case MESH_S1_SCHOOL_MPP: + 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); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + goto out; + break; + case MESH_S4_P2P_MESH: + real_config = nm_ip4_config_new (); + nm_ip4_config_set_address (real_config, self->priv->aipd.ip4_addr); + nm_ip4_config_set_netmask (real_config, (guint32)(ntohl (IPV4LL_NETMASK))); + nm_ip4_config_set_broadcast (real_config, (guint32)(ntohl (IPV4LL_BROADCAST))); + nm_ip4_config_set_gateway (real_config, 0); + break; + default: + nm_info ("%s: %s/%d unhandled step %d\n", + nm_device_get_iface (NM_DEVICE (self)), + __func__, __LINE__, self->priv->step); + break; + } - /* 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 (self->priv->step == MESH_S3_XO_MPP) { + /* Step 3 (XO_MPP) ignores the IP address provided in the DHCP response, + * so we still have to do autoip. + */ + if (!aipd_exec (self)) { + nm_warning ("Activation (%s/mesh): couldn't start avahi-autoipd.", + iface); + ret = NM_ACT_STAGE_RETURN_FAILURE; + goto out; + } + if (!aipd_monitor_start (self)) { + nm_warning ("Activation (%s/mesh): couldn't monitor avahi-autoipd.", + iface); + ret = NM_ACT_STAGE_RETURN_FAILURE; + goto out; + } + /* Save most of the request for later */ + nm_act_request_set_ip4_config (req, real_config); + ret = NM_ACT_STAGE_RETURN_POSTPONE; + } else { + *config = real_config; + ret = NM_ACT_STAGE_RETURN_SUCCESS; } -#endif - *config = real_config; +out: return ret; } - -/*************************************************************/ -/* MPP discovery stuff */ -/*************************************************************/ - static void -mpp_discovery_cleanup_timeout_source (NMDevice80211MeshOLPC *self) +real_activation_success_handler (NMDevice *dev, + NMActRequest *req) { - if (!self->priv->mpp.timeout_src) - return; - - g_source_destroy (self->priv->mpp.timeout_src); - g_source_unref (self->priv->mpp.timeout_src); - self->priv->mpp.timeout_src = NULL; + nm_device_set_active_link (dev, TRUE); } + static void -mpp_discovery_cleanup (NMDevice80211MeshOLPC *self) +real_activation_failure_handler (NMDevice *dev, + NMActRequest *req) { - g_return_if_fail (self != NULL); - - if (self->priv->mpp.chan) { - g_io_channel_shutdown (self->priv->mpp.chan, FALSE, NULL); - g_io_channel_unref (self->priv->mpp.chan); - self->priv->mpp.chan = NULL; - } - - if (self->priv->mpp.chan_src) { - g_source_destroy (self->priv->mpp.chan_src); - g_source_unref (self->priv->mpp.chan_src); - self->priv->mpp.chan_src = NULL; - } - - if (self->priv->mpp.sk >= 0) { - close (self->priv->mpp.sk ); - self->priv->mpp.sk = -1; - } + NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); - mpp_discovery_cleanup_timeout_source (self); + nm_device_set_active_link (dev, FALSE); - self->priv->mpp.tries = 0; + self->priv->step++; + self->priv->channel = 1; } + static gboolean -interpret_address (NMDevice * dev, - const char * line, - struct in_addr * addr, - const char * errmsg) +apply_autoip_address (NMDevice80211MeshOLPC *self, guint32 addr) { - const char * iface; - - g_return_val_if_fail (dev != NULL, FALSE); - g_return_val_if_fail (addr != NULL, FALSE); - g_return_val_if_fail (errmsg != NULL, FALSE); - - iface = nm_device_get_iface (dev); - - if (!line) { - nm_info ("Activation (%s/mesh): %s. Empty reply message line.", - iface, errmsg); - return FALSE; - } - - if (strlen (line) > 15) { - nm_info ("Activation (%s/mesh): %s. Invalid address; too long.", - iface, errmsg); - return FALSE; - } - - if (inet_aton (line, addr) == 0) { - nm_info ("Activation (%s/mesh): %s. Invalid address.", iface, errmsg); - return FALSE; - } - - return TRUE; -} - -#define MESSAGE_LEN 100 + NMIP4Config * ip4_config; + NMActRequest * req; -static gboolean -mpp_discovery_receive_cb (GIOChannel *source, - GIOCondition condition, - gpointer user_data) -{ - NMDevice * dev = NM_DEVICE (user_data); - NMDevice80211MeshOLPC *self = NM_DEVICE_802_11_MESH_OLPC (user_data); - NMActRequest * req; - char message[MESSAGE_LEN]; - gsize bytes_read = 0; - GError *error = NULL; - GIOStatus status; - gchar ** lines = NULL; - const char * iface = nm_device_get_iface (dev); - struct in_addr addr; - NMIP4Config * ip4_config; - NMData * app_data; - - /* Do nothing if we're supposed to be canceling activation. - * We'll get cleaned up by the cancellation handlers later. - */ - if (nm_device_activation_should_cancel (dev)) - return TRUE; + g_return_val_if_fail (self != NULL, FALSE); req = nm_device_get_act_request (NM_DEVICE (self)); - if (nm_act_request_get_stage (req) != NM_ACT_STAGE_POST_IP_START) - return TRUE; - - memset (message, 0, sizeof (message)); - status = g_io_channel_read_chars (self->priv->mpp.chan, - &message[0], - sizeof (message), - &bytes_read, - &error); - if (status != G_IO_STATUS_NORMAL) { - nm_info ("Activation (%s/mesh): error reading from MPP discovery " - "socket. status: %d, error: %d '%s'", - iface, status, - error ? error->code : -1, error ? error->message : "<none>"); - g_error_free (error); - goto out; - } - - nm_info ("Activation (%s/mesh): MPP discovery returned '%s'", iface, message); - - lines = g_strsplit (message, "\n", 5); - if (lines == NULL) { - nm_info ("Activation (%s/mesh): empty MPPREQ reply.", iface); - goto out; - } - - if (!lines[0] || strcmp (lines[0], "IPv4-0")) { - nm_info ("Activation (%s/mesh): invalid MPPREQ header.", iface); - goto out; - } - - ip4_config = nm_device_get_ip4_config (dev); - - if (!interpret_address (dev, lines[1], &addr, "invalid MPPREQ gateway")) - goto out; - nm_ip4_config_set_gateway (ip4_config, addr.s_addr); - - if (!interpret_address (dev, lines[2], &addr, "invalid MPPREQ nameserver #1")) - goto out; - nm_ip4_config_add_nameserver (ip4_config, addr.s_addr); + g_return_val_if_fail (req != NULL, FALSE); - if (lines[3]) { - /* Ignore whitespace */ - g_strstrip (lines[3]); - if (strlen (lines[3])) { - if (!interpret_address (dev, lines[3], &addr, "invalid MPPREQ nameserver #2")) - goto out; - nm_ip4_config_add_nameserver (ip4_config, addr.s_addr); - } - } - - /* Only cancel timeout now, so that errors above trigger retries */ - mpp_discovery_cleanup_timeout_source (self); - - app_data = nm_device_get_app_data (dev); - nm_named_manager_remove_ip4_config (app_data->named_manager, ip4_config); - if (!nm_system_device_set_from_ip4_config (dev)) { - nm_info ("Activation (%s/mesh): failed to set IP4 config.", iface); - nm_policy_schedule_activation_failed (req); - goto out; - } + ip4_config = nm_act_request_get_ip4_config (req); + g_return_val_if_fail (ip4_config != NULL, FALSE); - /* Clean up to ensure we never process more than one MPP response */ - mpp_discovery_cleanup (self); - nm_policy_schedule_activation_finish (req); + 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); -out: - g_strfreev (lines); return TRUE; } static void -mpp_discovery_receive_done (gpointer user_data) +handle_activation_autoip_event (NMDevice80211MeshOLPC *self, + NMActRequest *req, + const char *event, + const char *addr) { - NMDevice80211MeshOLPC *self = NM_DEVICE_802_11_MESH_OLPC (user_data); + const char * iface; + NMActStage stage; - self->priv->mpp.chan_src = NULL; -} + g_return_if_fail (self != NULL); + g_return_if_fail (req != NULL); -static gboolean -mpp_discovery_rreq_timeout_cb (gpointer user_data) -{ - NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (user_data); - NMActRequest * req; + iface = nm_device_get_iface (NM_DEVICE (self)); + stage = nm_act_request_get_stage (req); - self->priv->mpp.tries++; + if (strcmp (event, "BIND") == 0) { + struct in_addr ip; + int ret; - req = nm_device_get_act_request (NM_DEVICE (self)); - if (!req || (nm_act_request_get_stage (req) != NM_ACT_STAGE_POST_IP_START)) { - /* Must have been cancelled */ - mpp_discovery_cleanup (self); - return FALSE; - } + if (!((stage == NM_ACT_STAGE_IP_CONFIG_START) && (self->priv->step == MESH_S4_P2P_MESH)) + && !((stage == NM_ACT_STAGE_IP_CONFIG_GET) && (self->priv->step == MESH_S3_XO_MPP))) { + nm_warning ("%s: got avahi-autoip event %s for %s at wrong activation stage.", + iface, event, addr); + return; + } - if (self->priv->mpp.tries < 5) { - mpp_discovery_cleanup_timeout_source (self); - if (!mpp_discovery_send_rreq (self)) + ret = inet_aton (addr, &ip); + if (ret) { + if ((ntohl(ip.s_addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK) { + nm_warning ("%s: got invalid autoip address %s (0x%X).", + iface, addr, ip.s_addr); + nm_policy_schedule_activation_failed (req); + } else { + /* success */ + self->priv->aipd.ip4_addr = ip.s_addr; + aipd_remove_timeout (self); + + switch (self->priv->step) { + case MESH_S3_XO_MPP: + if (!apply_autoip_address (self, ip.s_addr)) + channel_failure_handler (self, req); + else + nm_device_activate_schedule_stage5_ip_config_commit (req); + 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_device_get_iface (NM_DEVICE (self)), + __func__, __LINE__, self->priv->step); + break; + } + } + } else { + nm_warning ("%s: got invalid autoip address %s.", iface, addr); nm_policy_schedule_activation_failed (req); + } } else { - NMActRequest * req = nm_device_get_act_request (NM_DEVICE (self)); - mpp_discovery_cleanup (self); - nm_policy_schedule_activation_failed (req); - } + nm_warning ("%s: autoip address %s no longer valid because '%s'.", + iface, addr, event); - return TRUE; + /* The LL address is gone. Terminate the connection or fail + * activation. + */ + if (nm_device_is_activating (NM_DEVICE (self))) { + nm_policy_schedule_activation_failed (req); + } else { + nm_device_set_active_link (NM_DEVICE (self), FALSE); + } + } } -#define MPPREQ_MSG "MPPREQ" -#define MPPREQ_PORT 16 -#define MPPREQ_IP4 "172.31.255.254" -#define MPPREQ_MAC "c027c027c027" - -static gboolean -mpp_discovery_send_rreq (NMDevice80211MeshOLPC *self) +static void +handle_mpp_autoip_event (NMDevice80211MeshOLPC *self, + const char *event, + const char *addr) { - const char * msg = MPPREQ_MSG; const char * iface; - struct sockaddr_in sin; - int ret; gboolean success = FALSE; - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (self->priv->mpp.sk >= 0, FALSE); + g_return_if_fail (self != NULL); iface = nm_device_get_iface (NM_DEVICE (self)); - memset (&sin, 0, sizeof (sin)); - sin.sin_family = AF_INET; - sin.sin_port = htons (MPPREQ_PORT); - if (!inet_aton (MPPREQ_IP4, &sin.sin_addr)) { - nm_info ("Error converting " MPPREQ_IP4 " to numeric address."); - goto done; - } + if (strcmp (event, "BIND") == 0) { + struct in_addr ip; + int ret; - ret = sendto (self->priv->mpp.sk, msg, strlen (msg), 0, - (struct sockaddr *) &sin, sizeof (sin)); - if (ret < 0) { - nm_info ("Activation (%s/mesh): could not send route request. errno: %d.", - iface, errno); - goto done; - } else if (ret < strlen (msg)) { - nm_info ("Activation (%s/mesh): couldn't send entire route request " - "message. Sent %d bytes.", - iface, ret); - goto done; + ret = inet_aton (addr, &ip); + if (ret && ((ntohl(ip.s_addr) & IPV4LL_NETMASK) == IPV4LL_NETWORK)) { + self->priv->aipd.ip4_addr = ip.s_addr; + aipd_remove_timeout (self); + success = TRUE; + } else { + nm_warning ("%s: got invalid autoip address %s.", iface, addr); + } + } else { + nm_warning ("%s: autoip address %s no longer valid because '%s'.", + iface, addr, event); } - nm_info ("Activation (%s/mesh): sent route request #%d.", - iface, - self->priv->mpp.tries + 1); - - mpp_discovery_cleanup_timeout_source (self); - self->priv->mpp.timeout_src = g_timeout_source_new (2000); - if (!self->priv->mpp.timeout_src) - goto done; - g_source_set_callback (self->priv->mpp.timeout_src, - mpp_discovery_rreq_timeout_cb, - self, - NULL); - g_source_attach (self->priv->mpp.timeout_src, - nm_device_get_main_context (NM_DEVICE (self))); - success = TRUE; - -done: - return success; + if (success) { + mpp_autoip_success (self); + } else { + mpp_cleanup (self); + } } static gboolean -mpp_discovery_start (NMDevice80211MeshOLPC *self) +handle_no_best_device (gpointer user_data) { - struct timeval tv = { 2, 0 }; - struct sockaddr_in sin; - int opt = 1; - NMIP4Config * ip4_config; - const char * iface; - - g_return_val_if_fail (self != NULL, FALSE); - - mpp_discovery_cleanup (self); - - ip4_config = nm_device_get_ip4_config (NM_DEVICE (self)); - g_return_val_if_fail (ip4_config != NULL, FALSE); + NMDevice * dev = NM_DEVICE (user_data); + NMDevice80211MeshOLPC * self; + gboolean reactivate = FALSE; - iface = nm_device_get_iface (NM_DEVICE (self)); - nm_info ("Activation (%s/mesh): starting MPP discovery...", iface); - - /* Open the MPP discovery socket */ - self->priv->mpp.sk = socket (AF_INET, SOCK_DGRAM, 0); - if (self->priv->mpp.sk < 0) { - nm_info ("Activation (%s/mesh): could not open socket for MPP " - "discovery. errno: %d.", - iface, - errno); - goto error; - } + g_return_val_if_fail (dev != NULL, FALSE); - if (setsockopt (self->priv->mpp.sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) { - nm_info ("Activation (%s/mesh): error setting socket options for MPP " - "discovery. errno: %d.", - iface, - errno); - goto error; - } + self = NM_DEVICE_802_11_MESH_OLPC (dev); - /* Set send & receive timeouts */ - if (setsockopt(self->priv->mpp.sk, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) < 0) { - nm_info ("Activation (%s/mesh): error setting socket send timeout for MPP " - "discovery. errno: %d.", - iface, - errno); - goto error; - } - if (setsockopt(self->priv->mpp.sk, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) { - nm_info ("Activation (%s/mesh): error setting socket receive for MPP " - "discovery. errno: %d.", - iface, - errno); - goto error; + /* If the next stage is step 3, then we set our link to TRUE and + * schedule another device change check so that we may continue with + * activation at step 3. + */ + if (self->priv->step == MESH_S2_AP) { + self->priv->step = MESH_S3_XO_MPP; + reactivate = TRUE; + } else if (self->priv->step == MESH_S4_P2P_MESH) { + self->priv->channel = 1; + reactivate = TRUE; } - memset (&sin, 0, sizeof (sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - if (bind(self->priv->mpp.sk, (struct sockaddr*)&sin, sizeof (sin)) < 0) { - nm_info ("Activation (%s/mesh): error binding socket for MPP " - "discovery. errno: %d.", - iface, - errno); - goto error; + if (reactivate) { + NMData * data = nm_device_get_app_data (dev); + if (data) { + nm_device_set_active_link (dev, TRUE); + nm_policy_schedule_device_change_check (data); + } } - /* Wait for an MPP reply */ - self->priv->mpp.chan = g_io_channel_unix_new (self->priv->mpp.sk); - g_io_channel_set_flags (self->priv->mpp.chan, G_IO_FLAG_NONBLOCK, NULL); - self->priv->mpp.chan_src = g_io_create_watch (self->priv->mpp.chan, G_IO_IN | G_IO_ERR); - if (!self->priv->mpp.chan_src) - goto error; - g_source_set_callback (self->priv->mpp.chan_src, - (GSourceFunc) mpp_discovery_receive_cb, - self, - mpp_discovery_receive_done); - g_source_attach (self->priv->mpp.chan_src, nm_device_get_main_context (NM_DEVICE (self))); - return TRUE; - -error: - mpp_discovery_cleanup (self); return FALSE; } - -static NMActStageReturn -real_act_stage6_post_ip_start (NMDevice *dev, - NMActRequest *req) -{ - NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); - - nm_system_device_add_route_via_device_with_iface (nm_device_get_iface (dev), - MPPREQ_IP4); - - if (nm_spawn_process ("/sbin/arp -s " MPPREQ_IP4 " " MPPREQ_MAC)) { - nm_warning ("Activation (%s/mesh): couldn't create anycast ARP" - " mapping for MPP discovery.", - nm_device_get_iface (dev)); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (!mpp_discovery_start (self)) - return NM_ACT_STAGE_RETURN_FAILURE; - - /* Send first packet */ - if (!mpp_discovery_send_rreq (self)) - return NM_ACT_STAGE_RETURN_FAILURE; - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -real_activation_success_handler (NMDevice *dev, - NMActRequest *req) -{ - NMData * app_data; - - app_data = nm_act_request_get_data (req); - g_assert (app_data); - - nm_device_set_active_link (dev, TRUE); -} - - static void -real_activation_failure_handler (NMDevice *dev, - NMActRequest *req) +real_notify_no_best_device (NMDevice *dev) { NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); - NMData * app_data; - - app_data = nm_act_request_get_data (req); - g_assert (app_data); - - self->priv->channel += 5; - if (self->priv->channel > 11) - self->priv->channel = 1; - - self->priv->num_channels_tried++; - if (self->priv->num_channels_tried > 2) { - /* After the third channel fails, jump to the next attempt */ - self->priv->num_channels_tried = 0; - self->priv->attempt++; - } + GSource * source; - if (self->priv->attempt > 2) { - /* Total failure to get a mesh after 2 passes */ - self->priv->num_channels_tried = 0; - self->priv->attempt = 1; - self->priv->channel = get_random_channel (); - nm_device_set_active_link (dev, FALSE); + g_return_if_fail (self != NULL); - /* Reset to managed mode to make scanning happy */ - set_80211_mode (self, IW_MODE_INFRA); - } + 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 USE_AUTOIP + static void real_handle_autoip_event (NMDevice *dev, const char *event, @@ -1791,62 +1808,47 @@ real_handle_autoip_event (NMDevice *dev, { NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (dev); NMActRequest * req = nm_device_get_act_request (dev); - struct in_addr ip; - int ret; - - if (!req) { - nm_warning ("%s: not active but got avahi-autoip event %s for %s.", - nm_device_get_iface (dev), - event, - addr); - return; - } - if (strcmp (event, "BIND") == 0) { - if (nm_act_request_get_stage (req) != NM_ACT_STAGE_IP_CONFIG_START) { - nm_warning ("%s: got avahi-autoip event %s for %s at wrong activation stage.", - nm_device_get_iface (dev), + if (nm_device_is_activating (NM_DEVICE (self))) { + if (req) { + handle_activation_autoip_event (self, req, event, addr); + } else { + nm_warning ("%s: not active but got avahi-autoip event %s for %s.", + nm_device_get_iface (NM_DEVICE (self)), event, addr); - return; - } + } + } else if (is_mpp_active (self)) { + handle_mpp_autoip_event (self, event, addr); + } +} - ret = inet_aton (addr, &ip); - if (ret) { - if ((ntohl(ip.s_addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK) { - nm_warning ("%s: got invalid autoip address %s (0x%X).", - nm_device_get_iface (dev), - addr, ip.s_addr); - nm_policy_schedule_activation_failed (req); - } else { - /* success */ - self->priv->aipd.ip4_addr = ip.s_addr; - aipd_remove_timeout (self); - nm_device_activate_schedule_stage4_ip_config_get (req); - } - } else { - nm_warning ("%s: got invalid autoip address %s.", - nm_device_get_iface (dev), - addr); - nm_policy_schedule_activation_failed (req); - } - } else { - nm_warning ("%s: autoip address %s no longer valid because '%s'.", - nm_device_get_iface (dev), - addr, - event); +static void +clear_hash_disconnect_from_signal (gpointer key, gpointer value, gpointer user_data) +{ + g_signal_handler_disconnect (G_OBJECT (key), GPOINTER_TO_UINT (value)); +} - /* The LL address is gone. Terminate the connection or fail - * activation. - */ - if (nm_device_is_activating (dev)) { - nm_policy_schedule_activation_failed (req); - } else { - nm_device_set_active_link (dev, FALSE); - } +static void +mpp_clear_hash_tables (NMDevice80211MeshOLPC *self) +{ + g_return_if_fail (self != NULL); + + if (self->priv->mpp.activated_ids) { + g_hash_table_foreach (self->priv->mpp.activated_ids, + clear_hash_disconnect_from_signal, + NULL); + g_hash_table_unref (self->priv->mpp.activated_ids); + self->priv->mpp.activated_ids = NULL; + } + if (self->priv->mpp.deactivated_ids) { + g_hash_table_foreach (self->priv->mpp.deactivated_ids, + clear_hash_disconnect_from_signal, + NULL); + g_hash_table_unref (self->priv->mpp.deactivated_ids); + self->priv->mpp.deactivated_ids = NULL; } } -#endif static void nm_device_802_11_mesh_olpc_dispose (GObject *object) @@ -1854,6 +1856,7 @@ nm_device_802_11_mesh_olpc_dispose (GObject *object) NMDevice80211MeshOLPC * self = NM_DEVICE_802_11_MESH_OLPC (object); NMDevice80211MeshOLPCClass * klass = NM_DEVICE_802_11_MESH_OLPC_GET_CLASS (object); NMDeviceClass * parent_class; + NMData * data = nm_device_get_app_data (NM_DEVICE (object)); /* Make sure dispose does not run twice. */ if (self->priv->dispose_has_run) @@ -1862,8 +1865,11 @@ nm_device_802_11_mesh_olpc_dispose (GObject *object) self->priv->dispose_has_run = TRUE; /* Only do this part of the cleanup if the object is initialized */ - if (self->priv->is_initialized) { - } + if (self->priv->is_initialized) + mpp_clear_hash_tables (self); + + g_signal_handler_disconnect (G_OBJECT (data->netlink_monitor), + self->priv->wireless_event_id); /* Chain up to the parent class */ parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); @@ -1905,13 +1911,11 @@ nm_device_802_11_mesh_olpc_class_init (NMDevice80211MeshOLPCClass *klass) parent_class->act_stage3_ip_config_start = real_act_stage3_ip_config_start; parent_class->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; parent_class->act_stage4_ip_config_timeout = real_act_stage4_ip_config_timeout; - parent_class->act_stage6_post_ip_start = real_act_stage6_post_ip_start; parent_class->activation_failure_handler = real_activation_failure_handler; parent_class->activation_success_handler = real_activation_success_handler; -#if USE_AUTOIP parent_class->handle_autoip_event = real_handle_autoip_event; -#endif + parent_class->notify_no_best_device = real_notify_no_best_device; g_type_class_add_private (object_class, sizeof (NMDevice80211MeshOLPCPrivate)); } diff --git a/src/nm-device-802-11-wireless.c b/src/nm-device-802-11-wireless.c index 2de2fe26e1..d98ceb8caf 100644 --- a/src/nm-device-802-11-wireless.c +++ b/src/nm-device-802-11-wireless.c @@ -2779,10 +2779,7 @@ supplicant_exec (NMDevice80211Wireless *self) argv[0] = WPA_SUPPLICANT_BIN; argv[1] = "-g"; argv[2] = WPA_SUPPLICANT_GLOBAL_SOCKET; - argv[3] = "-ddd"; - argv[4] = "-o"; - argv[5] = "local0"; - argv[6] = NULL; + argv[3] = NULL; success = g_spawn_async ("/", argv, NULL, 0, &supplicant_child_setup, NULL, &pid, &error); diff --git a/src/nm-device.c b/src/nm-device.c index 5e97cdf20e..68b15c6bfc 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -45,7 +45,9 @@ enum { ACTIVATION_STARTED = 0, - ACTIVATION_DONE, + ACTIVATION_SUCCESS, + ACTIVATION_FAILURE, + DEACTIVATED, NUMBER_OF_SIGNALS }; @@ -86,10 +88,6 @@ struct _NMDevicePrivate static gpointer nm_device_worker (gpointer user_data); -static void nm_device_activate_schedule_stage5_ip_config_commit (NMActRequest *req); - -static void nm_device_activate_schedule_stage6_post_ip_start (NMActRequest *req); - /* * nm_device_test_wireless_extensions * @@ -749,7 +747,7 @@ nm_device_activate_stage1_device_prepare (NMActRequest *req) g_assert (self); iface = nm_device_get_iface (self); - nm_info ("Activation (%s) Stage 1 of 6 (Device Prepare) started...", iface); + nm_info ("Activation (%s) Stage 1 of 5 (Device Prepare) started...", iface); ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, req); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) @@ -768,7 +766,7 @@ nm_device_activate_stage1_device_prepare (NMActRequest *req) out: nm_act_request_unref (req); - nm_info ("Activation (%s) Stage 1 of 6 (Device Prepare) complete.", iface); + nm_info ("Activation (%s) Stage 1 of 5 (Device Prepare) complete.", iface); return FALSE; } @@ -792,7 +790,7 @@ nm_device_activate_schedule_stage1_device_prepare (NMActRequest *req) nm_act_request_set_stage (req, NM_ACT_STAGE_DEVICE_PREPARE); nm_act_request_ref (req); - nm_info ("Activation (%s) Stage 1 of 6 (Device Prepare) scheduled...", nm_device_get_iface (self)); + nm_info ("Activation (%s) Stage 1 of 5 (Device Prepare) scheduled...", nm_device_get_iface (self)); source = g_idle_source_new (); g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage1_device_prepare, req, NULL); @@ -838,7 +836,7 @@ nm_device_activate_stage2_device_config (NMActRequest *req) g_assert (self); iface = nm_device_get_iface (self); - nm_info ("Activation (%s) Stage 2 of 6 (Device Configure) starting...", iface); + nm_info ("Activation (%s) Stage 2 of 5 (Device Configure) starting...", iface); /* Bring the device up */ if (!nm_device_is_up (self)) @@ -857,7 +855,7 @@ nm_device_activate_stage2_device_config (NMActRequest *req) } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - nm_info ("Activation (%s) Stage 2 of 6 (Device Configure) successful.", iface); + nm_info ("Activation (%s) Stage 2 of 5 (Device Configure) successful.", iface); if (nm_device_activation_should_cancel (self)) goto out; @@ -866,7 +864,7 @@ nm_device_activate_stage2_device_config (NMActRequest *req) out: nm_act_request_unref (req); - nm_info ("Activation (%s) Stage 2 of 6 (Device Configure) complete.", iface); + nm_info ("Activation (%s) Stage 2 of 5 (Device Configure) complete.", iface); return FALSE; } @@ -895,7 +893,7 @@ nm_device_activate_schedule_stage2_device_config (NMActRequest *req) g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage2_device_config, req, NULL); g_source_attach (source, self->priv->context); g_source_unref (source); - nm_info ("Activation (%s) Stage 2 of 6 (Device Configure) scheduled...", nm_device_get_iface (self)); + nm_info ("Activation (%s) Stage 2 of 5 (Device Configure) scheduled...", nm_device_get_iface (self)); } @@ -953,7 +951,7 @@ nm_device_activate_stage3_ip_config_start (NMActRequest *req) g_assert (self); iface = nm_device_get_iface (self); - nm_info ("Activation (%s) Stage 3 of 6 (IP Configure Start) started...", iface); + nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) started...", iface); if (nm_device_activation_should_cancel (self)) goto out; @@ -974,7 +972,7 @@ nm_device_activate_stage3_ip_config_start (NMActRequest *req) nm_device_activate_schedule_stage4_ip_config_get (req); out: - nm_info ("Activation (%s) Stage 3 of 6 (IP Configure Start) complete.", iface); + nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) complete.", iface); nm_act_request_unref (req); return FALSE; } @@ -1003,7 +1001,7 @@ nm_device_activate_schedule_stage3_ip_config_start (NMActRequest *req) g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage3_ip_config_start, req, NULL); g_source_attach (source, self->priv->context); g_source_unref (source); - nm_info ("Activation (%s) Stage 3 of 6 (IP Configure Start) scheduled.", nm_device_get_iface (self)); + nm_info ("Activation (%s) Stage 3 of 5 (IP Configure Start) scheduled.", nm_device_get_iface (self)); } @@ -1095,7 +1093,7 @@ nm_device_activate_stage4_ip_config_get (NMActRequest *req) self = nm_act_request_get_dev (req); g_assert (self); - nm_info ("Activation (%s) Stage 4 of 6 (IP Configure Get) started...", nm_device_get_iface (self)); + nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Get) started...", nm_device_get_iface (self)); if (nm_device_activation_should_cancel (self)) goto out; @@ -1123,7 +1121,7 @@ nm_device_activate_stage4_ip_config_get (NMActRequest *req) out: nm_act_request_unref (req); - nm_info ("Activation (%s) Stage 4 of 6 (IP Configure Get) complete.", nm_device_get_iface (self)); + nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Get) complete.", nm_device_get_iface (self)); return FALSE; } @@ -1147,7 +1145,7 @@ nm_device_activate_schedule_stage4_ip_config_get (NMActRequest *req) nm_act_request_set_stage (req, NM_ACT_STAGE_IP_CONFIG_GET); nm_act_request_ref (req); - nm_info ("Activation (%s) Stage 4 of 6 (IP Configure Get) scheduled...", + nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Get) scheduled...", nm_device_get_iface (self)); source = g_idle_source_new (); @@ -1199,7 +1197,7 @@ nm_device_activate_stage4_ip_config_timeout (NMActRequest *req) g_assert (self); iface = nm_device_get_iface (self); - nm_info ("Activation (%s) Stage 4 of 6 (IP Configure Timeout) started...", iface); + nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Timeout) started...", iface); if (nm_device_activation_should_cancel (self)) goto out; @@ -1220,7 +1218,7 @@ nm_device_activate_stage4_ip_config_timeout (NMActRequest *req) nm_device_activate_schedule_stage5_ip_config_commit (req); out: - nm_info ("Activation (%s) Stage 4 of 6 (IP Configure Timeout) complete.", iface); + nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Timeout) complete.", iface); return FALSE; } @@ -1248,7 +1246,7 @@ nm_device_activate_schedule_stage4_ip_config_timeout (NMActRequest *req) g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage4_ip_config_timeout, req, NULL); g_source_attach (source, self->priv->context); g_source_unref (source); - nm_info ("Activation (%s) Stage 4 of 6 (IP Configure Timeout) scheduled...", nm_device_get_iface (self)); + nm_info ("Activation (%s) Stage 4 of 5 (IP Configure Timeout) scheduled...", nm_device_get_iface (self)); } @@ -1276,14 +1274,14 @@ nm_device_activate_stage5_ip_config_commit (NMActRequest *req) ip4_config = nm_act_request_get_ip4_config (req); g_assert (ip4_config); - nm_info ("Activation (%s) Stage 5 of 6 (IP Configure Commit) started...", + nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) started...", nm_device_get_iface (self)); if (nm_device_activation_should_cancel (self)) goto out; nm_device_set_ip4_config (self, ip4_config); - if (nm_system_device_set_from_ip4_config (self)) + if (nm_system_device_set_from_ip4_config (self, FALSE)) { nm_device_update_ip4_address (self); nm_system_device_add_ip6_link_address (self); @@ -1293,14 +1291,14 @@ nm_device_activate_stage5_ip_config_commit (NMActRequest *req) nm_system_set_mtu (self); if (NM_DEVICE_GET_CLASS (self)->update_link) NM_DEVICE_GET_CLASS (self)->update_link (self); - nm_device_activate_schedule_stage6_post_ip_start (req); + nm_policy_schedule_activation_finish (req); } else nm_policy_schedule_activation_failed (req); out: nm_act_request_unref (req); - nm_info ("Activation (%s) Stage 5 of 6 (IP Configure Commit) complete.", + nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) complete.", nm_device_get_iface (self)); return FALSE; } @@ -1311,7 +1309,7 @@ out: * * Schedule commit of the IP config */ -static void +void nm_device_activate_schedule_stage5_ip_config_commit (NMActRequest *req) { GSource * source = NULL; @@ -1329,100 +1327,7 @@ nm_device_activate_schedule_stage5_ip_config_commit (NMActRequest *req) g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage5_ip_config_commit, req, NULL); g_source_attach (source, self->priv->context); g_source_unref (source); - nm_info ("Activation (%s) Stage 5 of 6 (IP Configure Commit) scheduled...", nm_device_get_iface (self)); -} - - -static NMActStageReturn -real_act_stage6_post_ip_start (NMDevice *self, - NMActRequest *req) -{ - return NM_ACT_STAGE_RETURN_SUCCESS; -} - - -/* - * nm_device_activate_stage6_post_ip_start - * - * Start post-IP configuration - * - */ -static gboolean -nm_device_activate_stage6_post_ip_start (NMActRequest *req) -{ - NMData * data = NULL; - NMDevice * self = NULL; - NMIP4Config * ip4_config = NULL; - int ret; - - g_return_val_if_fail (req != NULL, FALSE); - - data = nm_act_request_get_data (req); - g_assert (data); - - self = nm_act_request_get_dev (req); - g_assert (self); - - ip4_config = nm_act_request_get_ip4_config (req); - g_assert (ip4_config); - - nm_info ("Activation (%s) Stage 6 of 6 (Post-IP Start) started...", - nm_device_get_iface (self)); - - if (nm_device_activation_should_cancel (self)) - goto out; - - ret = NM_DEVICE_GET_CLASS (self)->act_stage6_post_ip_start (self, req); - - if (nm_device_activation_should_cancel (self)) - goto out; - - if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - goto out; - else if (ret == NM_ACT_STAGE_RETURN_FAILURE) - { - nm_policy_schedule_activation_failed (req); - goto out; - } - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); - - if (nm_device_activation_should_cancel (self)) - goto out; - - nm_policy_schedule_activation_finish (req); - -out: - nm_act_request_unref (req); - nm_info ("Activation (%s) Stage 6 of 6 (Post-IP Start) complete.", - nm_device_get_iface (self)); - return FALSE; -} - - -/* - * nm_device_activate_schedule_stage6_post_ip_start - * - * Schedule the start of post-IP configuration - */ -static void -nm_device_activate_schedule_stage6_post_ip_start (NMActRequest *req) -{ - GSource * source = NULL; - NMDevice * self = NULL; - - g_return_if_fail (req != NULL); - - self = nm_act_request_get_dev (req); - g_assert (self); - - nm_act_request_set_stage (req, NM_ACT_STAGE_POST_IP_START); - nm_act_request_ref (req); - - source = g_idle_source_new (); - g_source_set_callback (source, (GSourceFunc) nm_device_activate_stage6_post_ip_start, req, NULL); - g_source_attach (source, self->priv->context); - g_source_unref (source); - nm_info ("Activation (%s) Stage 6 of 6 (Post-IP Start) scheduled...", nm_device_get_iface (self)); + nm_info ("Activation (%s) Stage 5 of 5 (IP Configure Commit) scheduled...", nm_device_get_iface (self)); } @@ -1464,7 +1369,7 @@ activation_handle_cancel_helper (NMActRequest *req) nm_act_request_unref (req); } - g_signal_emit (G_OBJECT (self), nm_device_signals[ACTIVATION_DONE], 0); + g_signal_emit (G_OBJECT (self), nm_device_signals[ACTIVATION_FAILURE], 0); nm_schedule_state_change_signal_broadcast (self->priv->app_data); @@ -1601,6 +1506,8 @@ nm_device_deactivate_quickly (NMDevice *self) if (NM_DEVICE_GET_CLASS (self)->deactivate_quickly) NM_DEVICE_GET_CLASS (self)->deactivate_quickly (self); + g_signal_emit (G_OBJECT (self), nm_device_signals[DEACTIVATED], 0); + return TRUE; } @@ -1754,7 +1661,7 @@ nm_device_activation_failure_handler (NMDevice *self, if (NM_DEVICE_GET_CLASS (self)->activation_failure_handler) NM_DEVICE_GET_CLASS (self)->activation_failure_handler (self, req); - g_signal_emit (G_OBJECT (self), nm_device_signals[ACTIVATION_DONE], 0); + g_signal_emit (G_OBJECT (self), nm_device_signals[ACTIVATION_FAILURE], 0); } @@ -1767,7 +1674,7 @@ void nm_device_activation_success_handler (NMDevice *self, if (NM_DEVICE_GET_CLASS (self)->activation_success_handler) NM_DEVICE_GET_CLASS (self)->activation_success_handler (self, req); - g_signal_emit (G_OBJECT (self), nm_device_signals[ACTIVATION_DONE], 0); + g_signal_emit (G_OBJECT (self), nm_device_signals[ACTIVATION_SUCCESS], 0); } gboolean @@ -1935,6 +1842,16 @@ nm_device_handle_autoip_event (NMDevice * self, NM_DEVICE_GET_CLASS (self)->handle_autoip_event (self, event, addr); } +void +nm_device_notify_no_best_device (NMDevice * self) +{ + g_return_if_fail (self != NULL); + + if (NM_DEVICE_GET_CLASS (self)->notify_no_best_device) + NM_DEVICE_GET_CLASS (self)->notify_no_best_device (self); +} + + /* * nm_device_set_up_down * @@ -2190,7 +2107,6 @@ nm_device_class_init (NMDeviceClass *klass) klass->act_stage3_ip_config_start = real_act_stage3_ip_config_start; klass->act_stage4_get_ip4_config = real_act_stage4_get_ip4_config; klass->act_stage4_ip_config_timeout = real_act_stage4_ip_config_timeout; - klass->act_stage6_post_ip_start = real_act_stage6_post_ip_start; nm_device_signals[ACTIVATION_STARTED] = g_signal_new ("activation-started", @@ -2201,14 +2117,32 @@ nm_device_class_init (NMDeviceClass *klass) G_TYPE_NONE, 0); klass->activation_started = NULL; - nm_device_signals[ACTIVATION_DONE] = - g_signal_new ("activation-done", + nm_device_signals[ACTIVATION_SUCCESS] = + g_signal_new ("activation-success", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMDeviceClass, activation_success), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + klass->activation_success = NULL; + + nm_device_signals[ACTIVATION_FAILURE] = + g_signal_new ("activation-failure", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMDeviceClass, activation_failure), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + klass->activation_failure = NULL; + + nm_device_signals[DEACTIVATED] = + g_signal_new ("deactivated", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceClass, activation_done), + G_STRUCT_OFFSET (NMDeviceClass, sig_deactivated), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - klass->activation_done = NULL; + klass->sig_deactivated = NULL; g_type_class_add_private (object_class, sizeof (NMDevicePrivate)); } diff --git a/src/nm-device.h b/src/nm-device.h index b34da7064b..aa623623c9 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -101,8 +101,7 @@ struct _NMDeviceClass NMActStageReturn (* act_stage4_ip_config_timeout) (NMDevice *self, struct NMActRequest *req, NMIP4Config **config); - NMActStageReturn (* act_stage6_post_ip_start)(NMDevice *self, - struct NMActRequest *req); + void (* deactivate) (NMDevice *self); void (* deactivate_quickly) (NMDevice *self); @@ -120,9 +119,13 @@ struct _NMDeviceClass void (* handle_autoip_event) (NMDevice * self, const char * event, const char * addr); + void (* notify_no_best_device) (NMDevice * self); + /* Signals */ void (* activation_started) (NMDevice * dev); - void (* activation_done) (NMDevice * dev); + void (* activation_success) (NMDevice * dev); + void (* activation_failure) (NMDevice * dev); + void (* sig_deactivated) (NMDevice * dev); }; @@ -200,6 +203,7 @@ void nm_device_activate_schedule_stage1_device_prepare (struct NMActRequest * void nm_device_activate_schedule_stage2_device_config (struct NMActRequest *req); void nm_device_activate_schedule_stage4_ip_config_get (struct NMActRequest *req); void nm_device_activate_schedule_stage4_ip_config_timeout (struct NMActRequest *req); +void nm_device_activate_schedule_stage5_ip_config_commit (struct NMActRequest *req); void nm_device_deactivate (NMDevice *dev); gboolean nm_device_deactivate_quickly (NMDevice *dev); gboolean nm_device_is_activating (NMDevice *dev); @@ -218,6 +222,8 @@ const char * nm_device_get_physical_device_udi (NMDevice *dev); void nm_device_notify_device_added (NMDevice *self, NMDevice *added_dev); void nm_device_notify_device_removed (NMDevice *self, NMDevice *removed_dev); +void nm_device_notify_no_best_device (NMDevice * self); + G_END_DECLS #endif /* NM_DEVICE_H */ diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 644285a594..168c678a28 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -161,7 +161,7 @@ void nm_vpn_connection_deactivate (NMVPNConnection *connection) connection->vpn_iface, connection->ip4_config); /* Reset routes, nameservers, and domains of the currently active device */ - nm_system_device_set_from_ip4_config (connection->parent_dev); + nm_system_device_set_from_ip4_config (connection->parent_dev, FALSE); } nm_vpn_connection_set_ip4_config (connection, NULL); |