From a5919b696cfa82b3e5d08850c7f8b2ca585444f2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 6 Mar 2006 01:10:58 +0000 Subject: [PATCH] 2006-03-05 Dan Williams Process netlink messages in device subclasses rather than in NetworkManager.c. Also add support for recognizing Wireless Events. * configure.in - Find GLIB_GENMARSHAL * src/Makefile.am - Since we're marshalling custom types for wireless event signals, we get to create our own marshallers using GLIB_GENMARSHAL * src/NetworkManager.c - (nm_monitor_wired_link_state): renamed to nm_monitor_setup - (nm_monitor_setup): renamed from nm_monitor_wired_link_state, and cut down somewhat. We no longer process signals here. - (nm_data_new): create the netlink monitor here, and remove a useless call to nm_policy_schedule_device_change_check() - (nm_data_free): get rid of the netlink monitor here - (nm_device_link_activated, nm_device_link_deactivated): removed - (main): don't create the netlink monitor here, let nm_data_new do that. Call nm_policy_schedule_device_change_check() right before we jump to the mainloop to figure out which device to use first * src/NetworkManagerSystem.[ch] - (nm_system_get_rtnl_index_from_iface, nm_system_get_iface_from_rtnl_index): convert back and forth from interface names to interface indexes * src/nm-device-802-11-wireless.c - (real_init): connect to wireless-event signals from the netlink monitor object - (nm_device_802_11_wireless_event): new function, schedule handler for wireless event signals from the netlink monitor object. We want the handler to run in the device's context - (wireless_event_helper): handle wireless-event signals from netlink - (nm_device_802_11_wireless_dispose): disconnect wireless-event signal handler * src/nm-device-802-11-wireless.h - remove unused prototype for nm_device_802_11_wireless_new * src/nm-device-802-3-ethernet.c - (real_init): new function; set up signal handlers for link events - (nm_device_802_3_ethernet_link_activated): new function, schedule handler for netlink link activated events on device's main loop - (link_activated_helper): when we get a link activated event, set the device's link to be active - (nm_device_802_3_ethernet_link_deactivated): new function; schedule handler for netlink link deactivated events on device's main loop - (link_deactivated_helper): when we get a link deactivated event, set the device's link to be inactive - (nm_device_802_3_ethernet_dispose): disconnect signal handler on dispose * src/nm-device-802-3-ethernet.h - remove unused prototype for nm_device_802_3_ethernet_new * src/nm-device.[ch] - (nm_get_device_by_iface_locked): variant of nm_get_device_by_iface but locks the device list - (nm_device_set_active_link): a little bit of cleanup and de-indenting * src/nm-netlink-monitor.[ch] - (nm_netlink_monitor_class_install_signals): New signal "wireless-event" - (nm_netlink_monitor_new): keep reference to NMData so we can get at the device list - (nm_netlink_monitor_event_handler): expand for wireless events too * src/nm-marshal-main.c - Include generated nm-marshal.c and nm-marshal.h * src/nm-marshal.list - List of custom marshal functions git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@1555 4912f4e0-d625-0410-9fb7-b9a5a253dbdc --- ChangeLog | 77 +++++++++++++++ configure.in | 3 + src/.cvsignore | 2 + src/Makefile.am | 38 ++++++-- src/NetworkManager.c | 164 ++++++++++++-------------------- src/NetworkManagerSystem.c | 42 ++++++++ src/NetworkManagerSystem.h | 3 + src/nm-device-802-11-wireless.c | 128 +++++++++++++++++++++++++ src/nm-device-802-11-wireless.h | 2 - src/nm-device-802-3-ethernet.c | 88 +++++++++++++++++ src/nm-device-802-3-ethernet.h | 2 - src/nm-device.c | 99 +++++++++++++------ src/nm-device.h | 2 + src/nm-marshal-main.c | 2 + src/nm-marshal.list | 3 + src/nm-netlink-monitor.c | 111 ++++++++++++++------- src/nm-netlink-monitor.h | 19 ++-- 17 files changed, 596 insertions(+), 189 deletions(-) create mode 100644 src/nm-marshal-main.c create mode 100644 src/nm-marshal.list diff --git a/ChangeLog b/ChangeLog index 3844756c87..c900469845 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,80 @@ +2006-03-05 Dan Williams + + Process netlink messages in device subclasses rather than in + NetworkManager.c. Also add support for recognizing Wireless Events. + + * configure.in + - Find GLIB_GENMARSHAL + + * src/Makefile.am + - Since we're marshalling custom types for wireless event signals, + we get to create our own marshallers using GLIB_GENMARSHAL + + * src/NetworkManager.c + - (nm_monitor_wired_link_state): renamed to nm_monitor_setup + - (nm_monitor_setup): renamed from nm_monitor_wired_link_state, and + cut down somewhat. We no longer process signals here. + - (nm_data_new): create the netlink monitor here, and remove a + useless call to nm_policy_schedule_device_change_check() + - (nm_data_free): get rid of the netlink monitor here + - (nm_device_link_activated, nm_device_link_deactivated): removed + - (main): don't create the netlink monitor here, let nm_data_new + do that. Call nm_policy_schedule_device_change_check() right + before we jump to the mainloop to figure out which device + to use first + + * src/NetworkManagerSystem.[ch] + - (nm_system_get_rtnl_index_from_iface, nm_system_get_iface_from_rtnl_index): + convert back and forth from interface names to interface + indexes + + * src/nm-device-802-11-wireless.c + - (real_init): connect to wireless-event signals from the netlink + monitor object + - (nm_device_802_11_wireless_event): new function, schedule handler + for wireless event signals from the netlink monitor object. We + want the handler to run in the device's context + - (wireless_event_helper): handle wireless-event signals from netlink + - (nm_device_802_11_wireless_dispose): disconnect wireless-event + signal handler + + * src/nm-device-802-11-wireless.h + - remove unused prototype for nm_device_802_11_wireless_new + + * src/nm-device-802-3-ethernet.c + - (real_init): new function; set up signal handlers for link events + - (nm_device_802_3_ethernet_link_activated): new function, schedule + handler for netlink link activated events on device's main loop + - (link_activated_helper): when we get a link activated event, set + the device's link to be active + - (nm_device_802_3_ethernet_link_deactivated): new function; schedule + handler for netlink link deactivated events on device's main loop + - (link_deactivated_helper): when we get a link deactivated event, set + the device's link to be inactive + - (nm_device_802_3_ethernet_dispose): disconnect signal handler on + dispose + + * src/nm-device-802-3-ethernet.h + - remove unused prototype for nm_device_802_3_ethernet_new + + * src/nm-device.[ch] + - (nm_get_device_by_iface_locked): variant of nm_get_device_by_iface + but locks the device list + - (nm_device_set_active_link): a little bit of cleanup and de-indenting + + * src/nm-netlink-monitor.[ch] + - (nm_netlink_monitor_class_install_signals): New signal + "wireless-event" + - (nm_netlink_monitor_new): keep reference to NMData so we can get + at the device list + - (nm_netlink_monitor_event_handler): expand for wireless events too + + * src/nm-marshal-main.c + - Include generated nm-marshal.c and nm-marshal.h + + * src/nm-marshal.list + - List of custom marshal functions + 2006-03-05 Dan Williams * gnome/applet/applet-notifications.h diff --git a/configure.in b/configure.in index 89cd7849b2..335cc8ddc6 100644 --- a/configure.in +++ b/configure.in @@ -201,6 +201,9 @@ PKG_CHECK_MODULES(LIBGNOMEUI, libgnomeui-2.0) AC_SUBST(LIBGNOMEUI_CFLAGS) # is this even needed? it was typed incorrectly before AC_SUBST(LIBGNOMEUI_LIBS) +GLIB_GENMARSHAL=`pkg-config --variable=glib_genmarshal glib-2.0` +AC_SUBST(GLIB_GENMARSHAL) + AC_ARG_WITH(dbus-sys, AC_HELP_STRING([--with-dbus-sys=DIR], [where D-BUS system.d directory is])) if ! test -z "$with_dbus_sys" ; then diff --git a/src/.cvsignore b/src/.cvsignore index 49fc5a3d67..903005b2f4 100644 --- a/src/.cvsignore +++ b/src/.cvsignore @@ -2,3 +2,5 @@ Makefile Makefile.in NetworkManager nm-crash-logger +nm-marshal.c +nm-marshal.h diff --git a/src/Makefile.am b/src/Makefile.am index 88323fd6e6..342c9acb95 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,17 +62,31 @@ NetworkManager_SOURCES = \ nm-ap-security-wpa-eap.h \ nm-ap-security-wpa-psk.c \ nm-ap-security-wpa-psk.h \ + nm-marshal-main.c \ kernel-types.h \ wpa.c \ wpa.h \ wpa_ctrl.c \ wpa_ctrl.h -rundir=$(localstatedir)/run/NetworkManager -dispatcherdir=$(sysconfdir)/NetworkManager/dispatcher.d -install-data-hook: - $(mkinstalldirs) -m 0700 $(DESTDIR)$(rundir) - $(mkinstalldirs) -m 0755 $(DESTDIR)$(dispatcherdir) +nm-marshal.h: Makefile.am nm-marshal.list + $(GLIB_GENMARSHAL) --prefix=nm_marshal nm-marshal.list --header > xgen-gmh \ + && (cmp -s xgen-gmh nm-marshal.h || cp xgen-gmh nm-marshal.h) \ + && rm -f xgen-gmh xgen-gmh~ + +nm-marshal.c: Makefile.am nm-marshal.list + $(GLIB_GENMARSHAL) --prefix=nm_marshal nm-marshal.list --body > xgen-gmc \ + && cp xgen-gmc nm-marshal.c \ + && rm -f xgen-gmc xgen-gmc~ + +nm-marshal-main.c: nm-marshal.c nm-marshal.h + +built_sources = \ + nm-marshal.h \ + nm-marshal.c \ + $(NULL) + +$(NetworkManager_OBJECTS): $(built_sources) NetworkManager_CPPFLAGS = \ $(DBUS_CFLAGS) \ @@ -127,4 +141,16 @@ NetworkManager_DATA = gdb-cmd dbusservicedir = $(DBUS_SYS_DIR) dbusservice_DATA = NetworkManager.conf -EXTRA_DIST = $(dbusservice_DATA) $(NetworkManager_DATA) +EXTRA_DIST = \ + $(dbusservice_DATA) \ + $(NetworkManager_DATA) \ + nm-marshal.list + +rundir=$(localstatedir)/run/NetworkManager +dispatcherdir=$(sysconfdir)/NetworkManager/dispatcher.d +install-data-hook: + $(mkinstalldirs) -m 0700 $(DESTDIR)$(rundir) + $(mkinstalldirs) -m 0755 $(DESTDIR)$(dispatcherdir) + +CLEANFILES = $(built_sources) + diff --git a/src/NetworkManager.c b/src/NetworkManager.c index 4e0e63ac33..33ea3b9d10 100644 --- a/src/NetworkManager.c +++ b/src/NetworkManager.c @@ -370,6 +370,45 @@ void nm_schedule_state_change_signal_broadcast (NMData *data) } +static void +nm_error_monitoring_device_link_state (NmNetlinkMonitor *monitor, + GError *error, + NMData *data) +{ + /* FIXME: Try to handle the error instead of just printing it. */ + nm_warning ("error monitoring wired ethernet link state: %s\n", + error->message); +} + +static NmNetlinkMonitor * +nm_monitor_setup (NMData *data) +{ + GError *error = NULL; + NmNetlinkMonitor *monitor; + + monitor = nm_netlink_monitor_new (data); + nm_netlink_monitor_open_connection (monitor, &error); + if (error != NULL) + { + nm_warning ("could not monitor wired ethernet devices: %s", + error->message); + g_error_free (error); + g_object_unref (monitor); + return NULL; + } + + g_signal_connect (G_OBJECT (monitor), "error", + G_CALLBACK (nm_error_monitoring_device_link_state), + data); + + nm_netlink_monitor_attach (monitor, data->main_context); + + /* Request initial status of cards */ + nm_netlink_monitor_request_status (monitor, NULL); + return monitor; +} + + /* * nm_data_new * @@ -408,7 +447,7 @@ static NMData *nm_data_new (gboolean enable_test_devices) { nm_data_free (data); nm_warning ("could not initialize data structure locks."); - return (NULL); + return NULL; } nm_register_mutex_desc (data->dev_list_mutex, "Device List Mutex"); nm_register_mutex_desc (data->dialup_list_mutex, "DialUp List Mutex"); @@ -420,15 +459,20 @@ static NMData *nm_data_new (gboolean enable_test_devices) { nm_data_free (data); nm_warning ("could not create access point lists."); - return (NULL); + return NULL; + } + + /* Create watch functions that monitor cards for link status. */ + if (!(data->netlink_monitor = nm_monitor_setup (data))) + { + nm_data_free (data); + nm_warning ("could not create netlink monitor."); + return NULL; } data->enable_test_devices = enable_test_devices; data->wireless_enabled = TRUE; - - nm_policy_schedule_device_change_check (data); - - return (data); + return data; } @@ -458,6 +502,12 @@ static void nm_data_free (NMData *data) if ((req = nm_vpn_manager_get_vpn_act_request (data->vpn_manager))) nm_vpn_manager_deactivate_vpn_connection (data->vpn_manager, nm_vpn_act_request_get_parent_dev (req)); + if (data->netlink_monitor) + { + g_object_unref (G_OBJECT (data->netlink_monitor)); + data->netlink_monitor = NULL; + } + /* Stop and destroy all devices */ nm_lock_mutex (data->dev_list_mutex, __FUNCTION__); g_slist_foreach (data->dev_list, (GFunc) device_stop_and_free, NULL); @@ -497,99 +547,6 @@ static gboolean sigterm_pipe_handler (GIOChannel *src, GIOCondition condition, g return FALSE; } -static void nm_device_link_activated (NmNetlinkMonitor *monitor, const gchar *interface_name, NMData *data) -{ - NMDevice *dev = NULL; - - if (nm_try_acquire_mutex (data->dev_list_mutex, __func__)) - { - if ((dev = nm_get_device_by_iface (data, interface_name))) - g_object_ref (G_OBJECT (dev)); - nm_unlock_mutex (data->dev_list_mutex, __func__); - } - - /* Don't do anything if we already have a link */ - if (dev) - { - if (nm_device_is_802_3_ethernet (dev) && !nm_device_has_active_link (dev)) - { - nm_device_set_active_link (dev, TRUE); - nm_policy_schedule_device_change_check (data); - } - g_object_unref (G_OBJECT (dev)); - } -} - -static void nm_device_link_deactivated (NmNetlinkMonitor *monitor, const gchar *interface_name, NMData *data) -{ - NMDevice *dev = NULL; - - if (nm_try_acquire_mutex (data->dev_list_mutex, __func__)) - { - if ((dev = nm_get_device_by_iface (data, interface_name))) - g_object_ref (G_OBJECT (dev)); - nm_unlock_mutex (data->dev_list_mutex, __func__); - } - - if (dev) - { - if (nm_device_is_802_3_ethernet (dev)) - nm_device_set_active_link (dev, FALSE); - g_object_unref (G_OBJECT (dev)); - } -} - -static void -nm_error_monitoring_device_link_state (NmNetlinkMonitor *monitor, - GError *error, - NMData *data) -{ - /* FIXME: Try to handle the error instead of just printing it. - */ - nm_warning ("error monitoring wired ethernet link state: %s\n", - error->message); -} - -static void -nm_monitor_wired_link_state (NMData *data) -{ - GError *error; - NmNetlinkMonitor *monitor; - - monitor = nm_netlink_monitor_new (); - - error = NULL; - nm_netlink_monitor_open_connection (monitor, &error); - - if (error != NULL) - { - nm_warning ("could not monitor wired ethernet devices: %s", - error->message); - g_error_free (error); - g_object_unref (monitor); - return; - } - - g_signal_connect (G_OBJECT (monitor), "interface-connected", - G_CALLBACK (nm_device_link_activated), data); - - g_signal_connect (G_OBJECT (monitor), "interface-disconnected", - G_CALLBACK (nm_device_link_deactivated), data); - - g_signal_connect (G_OBJECT (monitor), "error", - G_CALLBACK (nm_error_monitoring_device_link_state), - data); - - nm_netlink_monitor_attach (monitor, data->main_context); - - /* Request initial status of cards - */ - nm_netlink_monitor_request_status (monitor, NULL); - - data->netlink_monitor = monitor; -} - - static LibHalContext *nm_get_hal_ctx (NMData *data) { LibHalContext * ctx = NULL; @@ -802,7 +759,7 @@ int main( int argc, char *argv[] ) { nm_error ("nm_data_new() failed... Not enough memory?"); exit (EXIT_FAILURE); - } + } /* Create our dbus service */ nm_data->dbus_connection = nm_dbus_init (nm_data); @@ -846,15 +803,12 @@ int main( int argc, char *argv[] ) /* Bring up the loopback interface. */ nm_system_enable_loopback (); - /* Create watch functions that monitor cards for link status. */ - nm_monitor_wired_link_state (nm_data); - /* Get modems, ISDN, and so on's configuration from the system */ nm_data->dialup_list = nm_system_get_dialup_config (); + /* Run the main loop */ + nm_policy_schedule_device_change_check (nm_data); nm_schedule_state_change_signal_broadcast (nm_data); - - /* Wheeee!!! */ g_main_loop_run (nm_data->main_loop); nm_print_open_socks (); diff --git a/src/NetworkManagerSystem.c b/src/NetworkManagerSystem.c index fc93a9d22f..dab3b97586 100644 --- a/src/NetworkManagerSystem.c +++ b/src/NetworkManagerSystem.c @@ -127,6 +127,48 @@ static struct nl_handle * new_nl_handle (void) } +int +nm_system_get_rtnl_index_from_iface (const char *iface) +{ + struct nl_handle * nlh = NULL; + struct nl_cache * cache = NULL; + int i = RTNL_LINK_NOT_FOUND; + + nlh = new_nl_handle (); + if (nlh && (cache = get_link_cache (nlh))) + i = rtnl_link_name2i (cache, iface); + nl_close (nlh); + nl_handle_destroy (nlh); + + return i; +} + + +#define MAX_IFACE_LEN 32 +char * +nm_system_get_iface_from_rtnl_index (int rtnl_index) +{ + struct nl_handle * nlh = NULL; + struct nl_cache * cache = NULL; + char * buf = NULL; + + nlh = new_nl_handle (); + if (nlh && (cache = get_link_cache (nlh))) + { + buf = g_malloc0 (MAX_IFACE_LEN); + if (!rtnl_link_i2name (cache, rtnl_index, buf, MAX_IFACE_LEN - 1)) + { + g_free (buf); + buf = NULL; + } + } + nl_close (nlh); + nl_handle_destroy (nlh); + + return buf; +} + + /* * nm_system_device_set_from_ip4_config * diff --git a/src/NetworkManagerSystem.h b/src/NetworkManagerSystem.h index e6f3f80ddd..82c83c4d2b 100644 --- a/src/NetworkManagerSystem.h +++ b/src/NetworkManagerSystem.h @@ -35,6 +35,9 @@ void nm_system_init (void); gboolean nm_system_device_has_active_routes (NMDevice *dev); +int nm_system_get_rtnl_index_from_iface (const char *iface); +char * nm_system_get_iface_from_rtnl_index (int rtnl_index); + void nm_system_device_flush_routes (NMDevice *dev); void nm_system_device_flush_routes_with_iface (const char *iface); diff --git a/src/nm-device-802-11-wireless.c b/src/nm-device-802-11-wireless.c index 79f0dbc085..6411ac1c32 100644 --- a/src/nm-device-802-11-wireless.c +++ b/src/nm-device-802-11-wireless.c @@ -82,6 +82,7 @@ struct _NMDevice80211WirelessPrivate guint32 failed_link_count; GSource * link_timeout; + gulong wireless_event_id; /* Static options from driver */ guint8 we_version; @@ -134,6 +135,12 @@ static void nm_device_802_11_wireless_set_wep_enc_key (NMDevice80211Wireless *s const char *key, int auth_method); +static void nm_device_802_11_wireless_event (NmNetlinkMonitor *monitor, + GObject *obj, + char *data, + int data_len, + NMDevice80211Wireless *self); + static guint nm_wireless_scan_interval_to_seconds (NMWirelessScanInterval interval) { guint seconds; @@ -254,6 +261,7 @@ real_init (NMDevice *dev) NMData * app_data; guint32 caps; NMSock * sk; + NmNetlinkMonitor * monitor; self->priv->scan_mutex = g_mutex_new (); nm_register_mutex_desc (self->priv->scan_mutex, "Scan Mutex"); @@ -308,6 +316,122 @@ real_init (NMDevice *dev) } nm_dev_sock_close (sk); } + + monitor = app_data->netlink_monitor; + self->priv->wireless_event_id = + g_signal_connect (G_OBJECT (monitor), "wireless-event", + G_CALLBACK (nm_device_802_11_wireless_event), self); +} + + +typedef struct WirelessEventCBData +{ + NMDevice80211Wireless * dev; + char * data; + int len; +} WirelessEventCBData; + +static gboolean +wireless_event_helper (gpointer user_data) +{ + NMDevice80211Wireless * self; + WirelessEventCBData * cb_data; + struct iw_event iwe_buf, *iwe = &iwe_buf; + char *pos, *end, *custom; + + cb_data = (WirelessEventCBData *) user_data; + g_return_val_if_fail (cb_data != NULL, FALSE); + + self = NM_DEVICE_802_11_WIRELESS (cb_data->dev); + g_return_val_if_fail (self != NULL, FALSE); + + g_return_val_if_fail (cb_data->data != NULL, FALSE); + g_return_val_if_fail (cb_data->len >= 0, FALSE); + + 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; + if (self->priv->we_version > 18 && + (iwe->cmd == IWEVMICHAELMICFAILURE || + iwe->cmd == IWEVCUSTOM || + iwe->cmd == IWEVASSOCREQIE || + iwe->cmd == IWEVASSOCRESPIE || + iwe->cmd == IWEVPMKIDCAND)) + { + /* WE-19 removed the pointer from struct iw_point */ + char *dpos = (char *) &iwe_buf.u.data.length; + int dlen = dpos - (char *) &iwe_buf; + memcpy (dpos, pos + IW_EV_LCP_LEN, + sizeof (struct iw_event) - dlen); + } + else + { + memcpy (&iwe_buf, pos, sizeof (struct iw_event)); + custom += IW_EV_POINT_OFF; + } + + switch (iwe->cmd) + { + case SIOCGIWAP: + if ( memcmp(iwe->u.ap_addr.sa_data, + "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 + || memcmp(iwe->u.ap_addr.sa_data, + "\x44\x44\x44\x44\x44\x44", ETH_ALEN) == 0 + || memcmp(iwe->u.ap_addr.sa_data, + "\xFF\xFF\xFF\xFF\xFF\xFF", ETH_ALEN) == 0) + { + /* disassociated */ + } else { + /* associated */ + } + break; + case SIOCGIWSCAN: + /* Got some scan results */ + break; + } + pos += iwe->len; + } + g_object_unref (G_OBJECT (self)); + g_free (cb_data->data); + g_free (cb_data); + return FALSE; +} + +static void +nm_device_802_11_wireless_event (NmNetlinkMonitor *monitor, + GObject *obj, + char *data, + int data_len, + NMDevice80211Wireless *self) +{ + GSource * source; + WirelessEventCBData * cb_data; + + /* Make sure signal is for us */ + if (NM_DEVICE (self) != NM_DEVICE (obj)) + return; + + cb_data = g_malloc0 (sizeof (WirelessEventCBData)); + cb_data->dev = self; + g_object_ref (G_OBJECT (self)); + 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, NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); } @@ -2887,6 +3011,7 @@ nm_device_802_11_wireless_dispose (GObject *object) NMDevice80211Wireless * self = NM_DEVICE_802_11_WIRELESS (object); NMDevice80211WirelessClass * klass = NM_DEVICE_802_11_WIRELESS_GET_CLASS (object); NMDeviceClass * parent_class; + NMData * data = nm_device_get_app_data (NM_DEVICE (self)); if (self->priv->dispose_has_run) /* If dispose did already run, return. */ @@ -2907,6 +3032,9 @@ nm_device_802_11_wireless_dispose (GObject *object) nm_ap_list_unref (self->priv->ap_list); g_mutex_free (self->priv->scan_mutex); + 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)); G_OBJECT_CLASS (parent_class)->dispose (object); diff --git a/src/nm-device-802-11-wireless.h b/src/nm-device-802-11-wireless.h index d5d32f5f18..1397889055 100644 --- a/src/nm-device-802-11-wireless.h +++ b/src/nm-device-802-11-wireless.h @@ -65,8 +65,6 @@ struct _NMDevice80211WirelessClass GType nm_device_802_11_wireless_get_type (void); -NMDevice80211Wireless * nm_device_802_11_wireless_new (void); - static inline gboolean nm_device_is_802_11_wireless (NMDevice *dev); static inline gboolean nm_device_is_802_11_wireless (NMDevice *dev) diff --git a/src/nm-device-802-3-ethernet.c b/src/nm-device-802-3-ethernet.c index e57c481a04..adc54fe4d3 100644 --- a/src/nm-device-802-3-ethernet.c +++ b/src/nm-device-802-3-ethernet.c @@ -32,6 +32,7 @@ #include "NetworkManagerMain.h" #include "nm-activation-request.h" #include "NetworkManagerUtils.h" +#include "NetworkManagerPolicy.h" #include "nm-utils.h" #include "kernel-types.h" @@ -43,11 +44,20 @@ struct _NMDevice8023EthernetPrivate struct ether_addr hw_addr; char * carrier_file_path; + gulong link_connected_id; + gulong link_disconnected_id; }; static gboolean supports_mii_carrier_detect (NMDevice8023Ethernet *dev); static gboolean supports_ethtool_carrier_detect (NMDevice8023Ethernet *dev); +static void nm_device_802_3_ethernet_link_activated (NmNetlinkMonitor *monitor, + GObject *obj, + NMDevice8023Ethernet *self); +static void nm_device_802_3_ethernet_link_deactivated (NmNetlinkMonitor *monitor, + GObject *obj, + NMDevice8023Ethernet *self); + static void nm_device_802_3_ethernet_init (NMDevice8023Ethernet * self) @@ -58,6 +68,77 @@ nm_device_802_3_ethernet_init (NMDevice8023Ethernet * self) memset (&(self->priv->hw_addr), 0, sizeof (struct ether_addr)); } +static void +real_init (NMDevice *dev) +{ + NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (dev); + NMData * app_data; + NmNetlinkMonitor * monitor; + + app_data = nm_device_get_app_data (NM_DEVICE (self)); + monitor = app_data->netlink_monitor; + + self->priv->link_connected_id = + g_signal_connect (G_OBJECT (monitor), "interface-connected", + G_CALLBACK (nm_device_802_3_ethernet_link_activated), self); + + self->priv->link_disconnected_id = + g_signal_connect (G_OBJECT (monitor), "interface-disconnected", + G_CALLBACK (nm_device_802_3_ethernet_link_deactivated), self); +} + +static gboolean +link_activated_helper (NMDevice8023Ethernet *self) +{ + nm_device_set_active_link (NM_DEVICE (self), TRUE); + return FALSE; +} + +static void +nm_device_802_3_ethernet_link_activated (NmNetlinkMonitor *monitor, + GObject *obj, + NMDevice8023Ethernet *self) +{ + /* Make sure signal is for us */ + if (NM_DEVICE (self) != NM_DEVICE (obj)) + return; + + if (!nm_device_has_active_link (NM_DEVICE (self))) + { + GSource * source = g_idle_source_new (); + + g_source_set_callback (source, (GSourceFunc) link_activated_helper, self, NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); + } +} + + +static gboolean +link_deactivated_helper (NMDevice8023Ethernet *self) +{ + nm_device_set_active_link (NM_DEVICE (self), FALSE); + return FALSE; +} + +static void +nm_device_802_3_ethernet_link_deactivated (NmNetlinkMonitor *monitor, + GObject *obj, + NMDevice8023Ethernet *self) +{ + /* Make sure signal is for us */ + if (NM_DEVICE (self) != NM_DEVICE (obj)) + return; + + if (nm_device_has_active_link (NM_DEVICE (self))) + { + GSource * source = g_idle_source_new (); + + g_source_set_callback (source, (GSourceFunc) link_deactivated_helper, self, NULL); + g_source_attach (source, nm_device_get_main_context (NM_DEVICE (self))); + g_source_unref (source); + } +} static gboolean probe_link (NMDevice8023Ethernet *self) @@ -219,6 +300,7 @@ nm_device_802_3_ethernet_dispose (GObject *object) NMDevice8023Ethernet * self = NM_DEVICE_802_3_ETHERNET (object); NMDevice8023EthernetClass * klass = NM_DEVICE_802_3_ETHERNET_GET_CLASS (object); NMDeviceClass * parent_class; + NMData * data = nm_device_get_app_data (NM_DEVICE (self)); if (self->priv->dispose_has_run) /* If dispose did already run, return. */ @@ -234,6 +316,11 @@ nm_device_802_3_ethernet_dispose (GObject *object) * reference. */ + g_signal_handler_disconnect (G_OBJECT (data->netlink_monitor), + self->priv->link_connected_id); + g_signal_handler_disconnect (G_OBJECT (data->netlink_monitor), + self->priv->link_disconnected_id); + /* Chain up to the parent class */ parent_class = NM_DEVICE_CLASS (g_type_class_peek_parent (klass)); G_OBJECT_CLASS (parent_class)->dispose (object); @@ -264,6 +351,7 @@ nm_device_802_3_ethernet_class_init (NMDevice8023EthernetClass *klass) object_class->finalize = nm_device_802_3_ethernet_finalize; parent_class->get_generic_capabilities = real_get_generic_capabilities; + parent_class->init = real_init; parent_class->start = real_start; parent_class->update_link = real_update_link; diff --git a/src/nm-device-802-3-ethernet.h b/src/nm-device-802-3-ethernet.h index f976ab4cc1..5d5a70b08e 100644 --- a/src/nm-device-802-3-ethernet.h +++ b/src/nm-device-802-3-ethernet.h @@ -57,8 +57,6 @@ struct _NMDevice8023EthernetClass GType nm_device_802_3_ethernet_get_type (void); -NMDevice8023Ethernet * nm_device_802_3_ethernet_new (void); - static inline gboolean nm_device_is_802_3_ethernet (NMDevice *dev); static inline gboolean nm_device_is_802_3_ethernet (NMDevice *dev) diff --git a/src/nm-device.c b/src/nm-device.c index 77eeb2db43..3fac32eea2 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -393,6 +393,43 @@ nm_get_device_by_iface (NMData *data, } +/* + * nm_get_device_by_iface_locked + * + * Search through the device list for a device with a given iface. + * NOTE: refs the device, caller must unref when done. + * + */ +NMDevice * +nm_get_device_by_iface_locked (NMData *data, + const char *iface) +{ + GSList * elt; + NMDevice *dev = NULL; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (iface != NULL, NULL); + + nm_lock_mutex (data->dev_list_mutex, __func__); + for (elt = data->dev_list; elt; elt = g_slist_next (elt)) + { + NMDevice *tmp_dev = NULL; + if ((tmp_dev = NM_DEVICE (elt->data))) + { + if (nm_null_safe_strcmp (nm_device_get_iface (tmp_dev), iface) == 0) + { + g_object_ref (G_OBJECT (tmp_dev)); + dev = tmp_dev; + break; + } + } + } + nm_unlock_mutex (data->dev_list_mutex, __FUNCTION__); + + return dev; +} + + /* * Get/set functions for UDI */ @@ -556,45 +593,45 @@ nm_device_set_active_link (NMDevice *self, app_data = self->priv->app_data; req = nm_device_get_act_request (self); - if (self->priv->link_active != link_active) + if (self->priv->link_active == link_active) + return; + + self->priv->link_active = link_active; + + /* Deactivate a currently active device */ + if (!link_active && req) + nm_policy_schedule_device_change_check (app_data); + else if (link_active && !req) { - self->priv->link_active = link_active; + NMDevice * act_dev = nm_get_active_device (app_data); + NMActRequest * act_dev_req = act_dev ? nm_device_get_act_request (act_dev) : NULL; - /* Deactivate a currently active device */ - if (!link_active && req) - nm_policy_schedule_device_change_check (app_data); - else if (link_active && !req) + /* Should we switch to this device now that it has a link? + * + * Only auto-switch for wired devices, AND... + * + * only switch to fully-supported devices, since ones that don't have carrier detection + * capability usually report the carrier as "always on" even if its not really on. User + * must manually choose semi-supported devices. + * + */ + if (nm_device_is_802_3_ethernet (self) && (nm_device_get_capabilities (self) & NM_DEVICE_CAP_CARRIER_DETECT)) { - NMDevice * act_dev = nm_get_active_device (app_data); - NMActRequest * act_dev_req = act_dev ? nm_device_get_act_request (act_dev) : NULL; + gboolean do_switch = act_dev ? FALSE : TRUE; /* If no currently active device, switch to this one */ + NMActRequest * act_req; - /* Should we switch to this device now that it has a link? - * - * Only auto-switch for wired devices, AND... - * - * only switch to fully-supported devices, since ones that don't have carrier detection - * capability usually report the carrier as "always on" even if its not really on. User - * must manually choose semi-supported devices. - * - */ - if (nm_device_is_802_3_ethernet (self) && (nm_device_get_capabilities (self) & NM_DEVICE_CAP_CARRIER_DETECT)) + /* If active device is wireless, switch to this one */ + if (act_dev && nm_device_is_802_11_wireless (act_dev) && act_dev_req && !nm_act_request_get_user_requested (act_dev_req)) + do_switch = TRUE; + + if (do_switch && (act_req = nm_act_request_new (app_data, self, NULL, TRUE))) { - gboolean do_switch = act_dev ? FALSE : TRUE; /* If no currently active device, switch to this one */ - NMActRequest * act_req; - - /* If active device is wireless, switch to this one */ - if (act_dev && nm_device_is_802_11_wireless (act_dev) && act_dev_req && !nm_act_request_get_user_requested (act_dev_req)) - do_switch = TRUE; - - if (do_switch && (act_req = nm_act_request_new (app_data, self, NULL, TRUE))) - { - nm_info ("Will activate wired connection '%s' because it now has a link.", nm_device_get_iface (self)); - nm_policy_schedule_device_change_check (app_data); - } + nm_info ("Will activate wired connection '%s' because it now has a link.", nm_device_get_iface (self)); + nm_policy_schedule_device_change_check (app_data); } } - nm_dbus_schedule_device_status_change_signal (app_data, self, NULL, link_active ? DEVICE_CARRIER_ON : DEVICE_CARRIER_OFF); } + nm_dbus_schedule_device_status_change_signal (app_data, self, NULL, link_active ? DEVICE_CARRIER_ON : DEVICE_CARRIER_OFF); } diff --git a/src/nm-device.h b/src/nm-device.h index f413c8800c..59f68f8db5 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -173,6 +173,8 @@ NMDevice * nm_get_device_by_udi (struct NMData *data, const char *udi); NMDevice * nm_get_device_by_iface (struct NMData *data, const char *iface); +NMDevice * nm_get_device_by_iface_locked (struct NMData *data, + const char *iface); gboolean nm_device_is_test_device (NMDevice *dev); diff --git a/src/nm-marshal-main.c b/src/nm-marshal-main.c new file mode 100644 index 0000000000..7c20913962 --- /dev/null +++ b/src/nm-marshal-main.c @@ -0,0 +1,2 @@ +#include "nm-marshal.h" +#include "nm-marshal.c" diff --git a/src/nm-marshal.list b/src/nm-marshal.list new file mode 100644 index 0000000000..a88a93ef80 --- /dev/null +++ b/src/nm-marshal.list @@ -0,0 +1,3 @@ +VOID:OBJECT +VOID:OBJECT,POINTER,INT +VOID:POINTER diff --git a/src/nm-netlink-monitor.c b/src/nm-netlink-monitor.c index 98e9c17967..8d9297e5f2 100644 --- a/src/nm-netlink-monitor.c +++ b/src/nm-netlink-monitor.c @@ -33,12 +33,16 @@ #include #include #include +#include #include #include +#include "NetworkManager.h" +#include "NetworkManagerSystem.h" #include "nm-netlink-monitor.h" #include "nm-utils.h" +#include "nm-marshal.h" #define NM_NETLINK_MONITOR_EVENT_CONDITIONS \ ((GIOCondition) (G_IO_IN | G_IO_PRI)) @@ -49,11 +53,13 @@ #define NM_NETLINK_MONITOR_DISCONNECT_CONDITIONS \ ((GIOCondition) (G_IO_HUP)) +struct NMData; struct _NmNetlinkMonitorPrivate { - GMainContext *context; - GIOChannel *io_channel; - GSource *event_source; + GMainContext * context; + GIOChannel * io_channel; + GSource * event_source; + struct NMData *app_data; }; static void nm_netlink_monitor_finalize (GObject *object); @@ -75,6 +81,7 @@ enum { INTERFACE_CONNECTED = 0, INTERFACE_DISCONNECTED, + WIRELESS_EVENT, ERROR, NUMBER_OF_SIGNALS }; @@ -109,8 +116,8 @@ nm_netlink_monitor_class_install_signals (NmNetlinkMonitorClass *monitor_class) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NmNetlinkMonitorClass, interface_connected), - NULL, NULL, g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); + NULL, NULL, nm_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); monitor_class->interface_connected = NULL; nm_netlink_monitor_signals[INTERFACE_DISCONNECTED] = @@ -118,16 +125,25 @@ nm_netlink_monitor_class_install_signals (NmNetlinkMonitorClass *monitor_class) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NmNetlinkMonitorClass, interface_disconnected), - NULL, NULL, g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); + NULL, NULL, nm_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); monitor_class->interface_disconnected = NULL; + nm_netlink_monitor_signals[WIRELESS_EVENT] = + g_signal_new ("wireless-event", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NmNetlinkMonitorClass, wireless_event), + NULL, NULL, nm_marshal_VOID__OBJECT_POINTER_INT, + G_TYPE_NONE, 3, G_TYPE_OBJECT, G_TYPE_POINTER, G_TYPE_INT); + monitor_class->wireless_event = NULL; + nm_netlink_monitor_signals[ERROR] = g_signal_new ("error", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NmNetlinkMonitorClass, error), - NULL, NULL, g_cclosure_marshal_VOID__POINTER, + NULL, NULL, nm_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); monitor_class->error = NULL; } @@ -259,13 +275,17 @@ nm_netlink_monitor_error_quark (void) } NmNetlinkMonitor * -nm_netlink_monitor_new (void) +nm_netlink_monitor_new (struct NMData *data) { - GObject *instance; + NmNetlinkMonitor *instance; - instance = g_object_new (NM_TYPE_NETLINK_MONITOR, NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); - return NM_NETLINK_MONITOR (instance); + instance = NM_NETLINK_MONITOR (g_object_new (NM_TYPE_NETLINK_MONITOR, + NULL, NULL)); + instance->priv->app_data = data; + + return instance; } static void @@ -625,8 +645,6 @@ nm_netlink_monitor_event_handler (GIOChannel *channel, struct ifinfomsg *interface_info; struct rtattr *attribute; int num_attribute_bytes_to_process; - gboolean is_connected; - gchar *interface_name; g_assert (num_bytes_to_process <= num_received_bytes); @@ -680,38 +698,59 @@ nm_netlink_monitor_event_handler (GIOChannel *channel, break; } - interface_name = NULL; interface_info = (struct ifinfomsg *) NLMSG_DATA (header); - /* The !! weirdness is to cannonicalize the value to 0 or 1. - */ - is_connected = !!((gboolean) (interface_info->ifi_flags & IFF_RUNNING)); - num_attribute_bytes_to_process = IFLA_PAYLOAD (header); + /* Dispatch the event */ for (attribute = IFLA_RTA (interface_info); - RTA_OK (attribute, num_attribute_bytes_to_process); + RTA_OK (attribute, num_attribute_bytes_to_process); attribute = RTA_NEXT (attribute, num_attribute_bytes_to_process)) { + int data_len = RTA_PAYLOAD (attribute); + if (attribute->rta_type == IFLA_IFNAME) { - interface_name = - (gchar *) g_strdup (RTA_DATA (attribute)); + char * iface = g_malloc0 (data_len + 1); + memcpy (iface, RTA_DATA (attribute), data_len); + if (strlen (iface)) + { + /* The !! weirdness is to cannonicalize the value to 0 or 1. */ + gboolean is_connected = !!((gboolean) (interface_info->ifi_flags & IFF_RUNNING)); + NMDevice * dev; + + if ((dev = nm_get_device_by_iface_locked (monitor->priv->app_data, iface))) + { + if (is_connected) { + g_signal_emit (G_OBJECT (monitor), + nm_netlink_monitor_signals[INTERFACE_CONNECTED], + 0, dev); + } else { + g_signal_emit (G_OBJECT (monitor), + nm_netlink_monitor_signals[INTERFACE_DISCONNECTED], + 0, dev); + } + g_object_unref (G_OBJECT (dev)); + } + } + g_free (iface); + } else if (attribute->rta_type == IFLA_WIRELESS) { + char * iface = nm_system_get_iface_from_rtnl_index (interface_info->ifi_index); + if (iface != NULL) { + NMDevice *dev; + if ((dev = nm_get_device_by_iface_locked (monitor->priv->app_data, iface))) + { + char * data = g_malloc0 (data_len); + memcpy (data, RTA_DATA (attribute), data_len); + g_signal_emit (G_OBJECT (monitor), + nm_netlink_monitor_signals[WIRELESS_EVENT], + 0, dev, data, data_len); + g_free (data); + g_object_unref (G_OBJECT (dev)); + } + } + g_free (iface); } } - - if (interface_name != NULL) - { - if (is_connected) - g_signal_emit (G_OBJECT (monitor), - nm_netlink_monitor_signals[INTERFACE_CONNECTED], - 0, interface_name); - else - g_signal_emit (G_OBJECT (monitor), - nm_netlink_monitor_signals[INTERFACE_DISCONNECTED], - 0, interface_name); - - g_free (interface_name); - } } g_free (received_bytes); diff --git a/src/nm-netlink-monitor.h b/src/nm-netlink-monitor.h index c6fccfe05a..b1ca09c6e0 100644 --- a/src/nm-netlink-monitor.h +++ b/src/nm-netlink-monitor.h @@ -53,12 +53,16 @@ struct _NmNetlinkMonitorClass GObjectClass parent_class; /* Signals */ - void (* interface_connected) (NmNetlinkMonitor *monitor, - const gchar *interface); - void (* interface_disconnected) (NmNetlinkMonitor *monitor, - const gchar *interface); - void (* error) (NmNetlinkMonitor *monitor, - GError *error); + void (* interface_connected) (NmNetlinkMonitor * monitor, + GObject *dev); + void (* interface_disconnected) (NmNetlinkMonitor * monitor, + GObject *dev); + void (* wireless_event) (NmNetlinkMonitor * monitor, + GObject *dev, + const gchar * data, + int data_len); + void (* error) (NmNetlinkMonitor * monitor, + GError * error); }; enum _NmNetlinkMonitorError @@ -76,7 +80,8 @@ enum _NmNetlinkMonitorError GType nm_netlink_monitor_get_type (void) G_GNUC_CONST; GQuark nm_netlink_monitor_error_quark (void) G_GNUC_CONST; -NmNetlinkMonitor *nm_netlink_monitor_new (void); +struct NMData; +NmNetlinkMonitor *nm_netlink_monitor_new (struct NMData *data); gboolean nm_netlink_monitor_open_connection (NmNetlinkMonitor *monitor,