diff --git a/src/Makefile.am b/src/Makefile.am index 305a9a0dac..aeae2a0698 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,7 @@ nm_sources = \ devices/nm-device-bt.h \ devices/nm-device-ethernet.c \ devices/nm-device-ethernet.h \ + devices/nm-device-factory.c \ devices/nm-device-factory.h \ devices/nm-device-generic.c \ devices/nm-device-generic.h \ diff --git a/src/devices/nm-device-bt.c b/src/devices/nm-device-bt.c index 79371ee05a..ecb015b03c 100644 --- a/src/devices/nm-device-bt.c +++ b/src/devices/nm-device-bt.c @@ -588,22 +588,22 @@ modem_removed_cb (NMModem *modem, gpointer user_data) modem_cleanup (self); } -gboolean -nm_device_bt_modem_added (NMDeviceBt *self, - NMModem *modem, - const char *driver) +static gboolean +component_added (NMDevice *device, GObject *component) { - NMDeviceBtPrivate *priv; + NMDeviceBt *self = NM_DEVICE_BT (device); + NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); + NMModem *modem; const gchar *modem_data_port; const gchar *modem_control_port; char *base; NMDeviceState state; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - g_return_val_if_fail (NM_IS_DEVICE_BT (self), FALSE); - g_return_val_if_fail (NM_IS_MODEM (modem), FALSE); + if (!NM_IS_MODEM (component)) + return FALSE; + modem = NM_MODEM (component); - priv = NM_DEVICE_BT_GET_PRIVATE (self); modem_data_port = nm_modem_get_data_port (modem); modem_control_port = nm_modem_get_control_port (modem); g_return_val_if_fail (modem_data_port != NULL || modem_control_port != NULL, FALSE); @@ -1207,6 +1207,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; device_class->is_available = is_available; + device_class->component_added = component_added; device_class->state_changed = device_state_changed; diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c new file mode 100644 index 0000000000..423a26f6a7 --- /dev/null +++ b/src/devices/nm-device-factory.c @@ -0,0 +1,114 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2014 Red Hat, Inc. + */ + +#include "nm-device-factory.h" + +enum { + DEVICE_ADDED, + COMPONENT_ADDED, + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + +gboolean +nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component) +{ + gboolean consumed = FALSE; + + g_signal_emit (factory, signals[COMPONENT_ADDED], 0, component, &consumed); + return consumed; +} + +static void +interface_init (gpointer g_iface) +{ + GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); + static gboolean initialized = FALSE; + + if (G_LIKELY (initialized)) + return; + + g_object_interface_install_property + (g_iface, + g_param_spec_uint (NM_DEVICE_FACTORY_DEVICE_TYPE, + "Device type", + "Device type", + 0, G_MAXUINT32, NM_DEVICE_TYPE_UNKNOWN, + G_PARAM_READABLE)); + + /* Signals */ + signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDeviceFactory, device_added), + NULL, NULL, NULL, + G_TYPE_NONE, 1, NM_TYPE_DEVICE); + + signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, + iface_type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMDeviceFactory, component_added), + g_signal_accumulator_true_handled, NULL, NULL, + G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); + + initialized = TRUE; +} + +GType +nm_device_factory_get_type (void) +{ + static GType device_factory_type = 0; + + if (!device_factory_type) { + const GTypeInfo device_factory_info = { + sizeof (NMDeviceFactory), /* class_size */ + interface_init, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + device_factory_type = g_type_register_static (G_TYPE_INTERFACE, + "NMDeviceFactory", + &device_factory_info, + 0); + g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT); + } + + return device_factory_type; +} + +NMDevice * +nm_device_factory_new_link (NMDeviceFactory *factory, + NMPlatformLink *plink, + GError **error) +{ + g_return_if_fail (factory != NULL); + g_return_if_fail (plink != NULL); + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link) + return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link (factory, plink, error); + return NULL; +} + diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index 7b7efc8702..45ae77a9fb 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2007 - 2011 Red Hat, Inc. + * Copyright (C) 2007 - 2014 Red Hat, Inc. */ #ifndef NM_DEVICE_FACTORY_H @@ -26,6 +26,7 @@ #include "NetworkManager.h" #include "nm-platform.h" +#include "nm-device.h" /* WARNING: this file is private API between NetworkManager and its internal * device plugins. Its API can change at any time and is not guaranteed to be @@ -33,52 +34,106 @@ * not meant to enable third-party plugins. */ +typedef struct _NMDeviceFactory NMDeviceFactory; + /** - * nm_device_factory_create_device: - * @devpath: sysfs path of the device - * @ifname: interface name of the device - * @driver: driver of the device - * @error: error for failure information + * nm_device_factory_create: + * @error: an error if creation of the factory failed, or %NULL * - * Creates a #NMDevice subclass if the given information represents a device - * the factory is capable of creating. If the information does represent a - * device the factory is capable of creating, but the device could not be - * created, %NULL should be returned and @error should be set. If the - * factory is not capable of creating a device with the given information - * (ie, the factory creates Ethernet devices but the information represents - * a WiFi device) it should return %NULL and leave @error untouched. + * Creates a #GObject that implements the #NMDeviceFactory interface. This + * function must not emit any signals or perform any actions that would cause + * devices or components to be created immediately. Instead these should be + * deferred to an idle handler. * - * Returns: the device object (a subclass of #NMDevice) or %NULL + * Returns: the #GObject implementing #NMDeviceFactory or %NULL */ -GObject *nm_device_factory_create_device (NMPlatformLink *platform_device, +NMDeviceFactory *nm_device_factory_create (GError **error); + +/* Should match nm_device_factory_create() */ +typedef NMDeviceFactory * (*NMDeviceFactoryCreateFunc) (GError **error); + +/** + * nm_device_factory_get_device_type: + * + * Returns: the #NMDeviceType that this plugin creates + */ +NMDeviceType nm_device_factory_get_device_type (void); + +/* Should match nm_device_factory_get_device_type() */ +typedef NMDeviceType (*NMDeviceFactoryDeviceTypeFunc) (void); + +/********************************************************************/ + +#define NM_TYPE_DEVICE_FACTORY (nm_device_factory_get_type ()) +#define NM_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) +#define NM_IS_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_FACTORY)) +#define NM_DEVICE_FACTORY_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) + +/* properties */ +#define NM_DEVICE_FACTORY_DEVICE_TYPE "device-type" + +/* signals */ +#define NM_DEVICE_FACTORY_COMPONENT_ADDED "component-added" +#define NM_DEVICE_FACTORY_DEVICE_ADDED "device-added" + +struct _NMDeviceFactory { + GTypeInterface g_iface; + + /** + * new_link: + * @factory: the #NMDeviceFactory + * @link: the new link + * @error: error if the link could be claimed but an error occurred + * + * The NetworkManager core was notified of a new link which the plugin + * may want to claim and create a #NMDevice subclass for. If the link + * represents a device the factory is capable of claiming, but the device + * could not be created, %NULL should be returned and @error should be set. + * %NULL should always be returned and @error should never be set if the + * factory cannot create devices for the type which @link represents. + * + * Returns: the #NMDevice if the link was claimed and created, %NULL if not + */ + NMDevice * (*new_link) (NMDeviceFactory *factory, + NMPlatformLink *plink, + GError **error); + + /* Signals */ + + /** + * device_added: + * @factory: the #NMDeviceFactory + * @device: the new #NMDevice subclass + * + * The factory emits this signal if it finds a new device by itself. + */ + void (*device_added) (NMDeviceFactory *factory, NMDevice *device); + + /** + * component_added: + * @factory: the #NMDeviceFactory + * @component: a new component which existing devices may wish to claim + * + * The factory emits this signal when it finds a new component. For example, + * the WWAN factory may indicate that a new modem is available, which an + * existing Bluetooth device may wish to claim. If no device claims the + * component, the plugin is allowed to create a new #NMDevice instance for + * that component and emit the "device-added" signal. + * + * Returns: %TRUE if the component was claimed by a device, %FALSE if not + */ + gboolean (*component_added) (NMDeviceFactory *factory, GObject *component); +}; + +GType nm_device_factory_get_type (void); + +NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, + NMPlatformLink *plink, GError **error); -/* Should match nm_device_factory() */ -typedef GObject * (*NMDeviceFactoryCreateFunc) (NMPlatformLink *platform_device, - GError **error); - -/** - * nm_device_factory_get_priority: - * - * Returns the priority of this plugin. Higher numbers mean a higher priority. - * - * Returns: plugin priority - */ -guint32 nm_device_factory_get_priority (void); - -typedef guint32 (*NMDeviceFactoryPriorityFunc) (void); - -/** - * nm_device_factory_get_type: - * - * Returns the type of device this factory can create. Only one factory for - * each type of device is allowed. - * - * Returns: the %NMDeviceType - */ -NMDeviceType nm_device_factory_get_type (void); - -typedef NMDeviceType (*NMDeviceFactoryTypeFunc) (void); +/* For use by implementations */ +gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, + GObject *component); #endif /* NM_DEVICE_FACTORY_H */ diff --git a/src/devices/nm-device-modem.c b/src/devices/nm-device-modem.c index 5c10a8e05d..6a3656c4e9 100644 --- a/src/devices/nm-device-modem.c +++ b/src/devices/nm-device-modem.c @@ -212,6 +212,15 @@ nm_device_modem_get_modem (NMDeviceModem *self) return NM_DEVICE_MODEM_GET_PRIVATE (self)->modem; } +static gboolean +owns_iface (NMDevice *device, const char *iface) +{ + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); + + g_assert (priv->modem); + return nm_modem_owns_port (priv->modem, iface); +} + /*****************************************************************************/ static void @@ -492,6 +501,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) device_class->ip4_config_pre_commit = ip4_config_pre_commit; device_class->get_enabled = get_enabled; device_class->set_enabled = set_enabled; + device_class->owns_iface = owns_iface; device_class->state_changed = device_state_changed; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index e43df20d07..d4f16a62e7 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -1193,6 +1193,48 @@ link_changed (NMDevice *device, NMPlatformLink *info) nm_device_set_carrier (device, info->connected); } +/** + * nm_device_notify_component_added(): + * @device: the #NMDevice + * @component: the component being added by a plugin + * + * Called by the manager to notify the device that a new component has + * been found. The device implementation should return %TRUE if it + * wishes to claim the component, or %FALSE if it cannot. + * + * Returns: %TRUE to claim the component, %FALSE if the component cannot be + * claimed. + */ +gboolean +nm_device_notify_component_added (NMDevice *device, GObject *component) +{ + if (NM_DEVICE_GET_CLASS (device)->component_added) + return NM_DEVICE_GET_CLASS (device)->component_added (device, component); + return FALSE; +} + +/** + * nm_device_owns_iface(): + * @device: the #NMDevice + * @iface: an interface name + * + * Called by the manager to ask if the device or any of its components owns + * @iface. For example, a WWAN implementation would return %TRUE for an + * ethernet interface name that was owned by the WWAN device's modem component, + * because that ethernet interface is controlled by the WWAN device and cannot + * be used independently of the WWAN device. + * + * Returns: %TRUE if @device or it's components owns the interface name, + * %FALSE if not + */ +gboolean +nm_device_owns_iface (NMDevice *device, const char *iface) +{ + if (NM_DEVICE_GET_CLASS (device)->owns_iface) + return NM_DEVICE_GET_CLASS (device)->owns_iface (device, iface); + return FALSE; +} + static void check_carrier (NMDevice *device) { diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 807cf6873e..03e3b87ed0 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -196,6 +196,10 @@ typedef struct { gboolean (* have_any_ready_slaves) (NMDevice *self, const GSList *slaves); + + gboolean (* component_added) (NMDevice *self, GObject *component); + + gboolean (* owns_iface) (NMDevice *self, const char *iface); } NMDeviceClass; @@ -332,6 +336,10 @@ guint32 nm_device_get_mtu (NMDevice *device); gboolean nm_device_connection_is_available (NMDevice *device, NMConnection *connection); +gboolean nm_device_notify_component_added (NMDevice *device, GObject *component); + +gboolean nm_device_owns_iface (NMDevice *device, const char *iface); + G_END_DECLS /* For testing only */ diff --git a/src/devices/wimax/nm-wimax-factory.c b/src/devices/wimax/nm-wimax-factory.c index 738c12eb31..d5bf57f602 100644 --- a/src/devices/wimax/nm-wimax-factory.c +++ b/src/devices/wimax/nm-wimax-factory.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright (C) 2011 Red Hat, Inc. + * Copyright (C) 2011 - 2014 Red Hat, Inc. */ #include @@ -23,28 +23,92 @@ #include "nm-device-factory.h" #include "nm-device-wimax.h" -G_MODULE_EXPORT GObject * -nm_device_factory_create_device (NMPlatformLink *platform_device, - GError **error) +#define NM_TYPE_WIMAX_FACTORY (nm_wimax_factory_get_type ()) +#define NM_WIMAX_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_WIMAX_FACTORY, NMWimaxFactory)) + +typedef struct { + GObject parent; +} NMWimaxFactory; + +typedef struct { + GObjectClass parent; +} NMWimaxFactoryClass; + +static GType nm_wimax_factory_get_type (void); + +static void device_factory_interface_init (NMDeviceFactory *factory_iface); + +G_DEFINE_TYPE_EXTENDED (NMWimaxFactory, nm_wimax_factory, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) + +/**************************************************************************/ + +#define PLUGIN_TYPE NM_DEVICE_TYPE_WIMAX + +G_MODULE_EXPORT NMDeviceFactory * +nm_device_factory_create (GError **error) +{ + return (NMDeviceFactory *) g_object_new (NM_TYPE_WIMAX_FACTORY, NULL); +} + +G_MODULE_EXPORT NMDeviceType +nm_device_factory_get_device_type (void) +{ + return PLUGIN_TYPE; +} + +/**************************************************************************/ + +static NMDevice * +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { /* FIXME: check udev 'DEVTYPE' instead; but since we only support Intel * WiMAX devices for now this is appropriate. */ - if (g_strcmp0 (platform_device->driver, "i2400m_usb") != 0) + if (g_strcmp0 (plink->driver, "i2400m_usb") != 0) return NULL; /* unsupported */ - return (GObject *) nm_device_wimax_new (platform_device); + return (NMDevice *) nm_device_wimax_new (plink); } -G_MODULE_EXPORT guint32 -nm_device_factory_get_priority (void) +enum { + PROP_0 = 0x1000, + PROP_DEVICE_TYPE, +}; + +static void +get_property (GObject *object, guint prop, GValue *value, GParamSpec *pspec) { - return 0; + switch (prop) { + case PROP_DEVICE_TYPE: + g_value_set_uint (value, PLUGIN_TYPE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop, pspec); + break; + } } -G_MODULE_EXPORT NMDeviceType -nm_device_factory_get_type (void) +static void +device_factory_interface_init (NMDeviceFactory *factory_iface) { - return NM_DEVICE_TYPE_WIMAX; + factory_iface->new_link = new_link; +} + +static void +nm_wimax_factory_init (NMWimaxFactory *factory) +{ +} + +static void +nm_wimax_factory_class_init (NMWimaxFactoryClass *wf_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (wf_class); + + object_class->get_property = get_property; + + g_object_class_override_property (object_class, + PROP_DEVICE_TYPE, + NM_DEVICE_FACTORY_DEVICE_TYPE); } diff --git a/src/nm-manager.c b/src/nm-manager.c index fc439f0921..22e8a32f57 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -551,27 +551,12 @@ modem_added (NMModemManager *modem_manager, NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDevice *device = NULL; const char *modem_iface; - GSList *iter, *remove = NULL; - - /* Remove ethernet devices that are actually owned by the modem, since - * they cannot be used as normal ethernet. - */ - for (iter = priv->devices; iter; iter = iter->next) { - if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_ETHERNET) { - if (nm_modem_owns_port (modem, nm_device_get_ip_iface (iter->data))) - remove = g_slist_prepend (remove, iter->data); - } - } - for (iter = remove; iter; iter = iter->next) - remove_device (self, NM_DEVICE (iter->data), FALSE); - g_slist_free (remove); + GSList *iter; /* Give Bluetooth DUN devices first chance to claim the modem */ - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - if (nm_device_get_device_type (iter->data) == NM_DEVICE_TYPE_BT) { - if (nm_device_bt_modem_added (NM_DEVICE_BT (iter->data), modem, driver)) - return; - } + for (iter = priv->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added (device, G_OBJECT (modem))) + return; } /* If it was a Bluetooth modem and no bluetooth device claimed it, ignore @@ -589,8 +574,10 @@ modem_added (NMModemManager *modem_manager, /* Make the new modem device */ device = nm_device_modem_new (modem, driver); - if (device) + if (device) { add_device (self, device, FALSE); + g_object_unref (device); + } } static void @@ -1182,6 +1169,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) if (device) { nm_device_set_is_nm_owned (device, TRUE); add_device (self, device, FALSE); + g_object_unref (device); } g_signal_handlers_unblock_by_func (nm_platform_get (), G_CALLBACK (platform_link_added_cb), self); @@ -1792,6 +1780,15 @@ get_existing_connection (NMManager *manager, NMDevice *device) return added ? NM_CONNECTION (added) : NULL; } +/** + * add_device: + * @self: the #NMManager + * @device: the #NMDevice to add + * @generate_con: %TRUE if existing connection (if any) should be assumed + * + * If successful, this function will increase the references count of @device. + * Callers should decrease the reference count. + */ static void add_device (NMManager *self, NMDevice *device, gboolean generate_con) { @@ -1804,26 +1801,31 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) gboolean enabled = FALSE; RfKillType rtype; NMDeviceType devtype; - - iface = nm_device_get_ip_iface (device); - g_assert (iface); + GSList *iter, *remove = NULL; devtype = nm_device_get_device_type (device); - /* Ignore the device if we already know about it. But some modems will - * provide pseudo-ethernet devices that NM has already claimed while - * ModemManager is still detecting the modem's serial ports, so when the - * MM modem object finally shows up it may have the same IP interface as the - * ethernet interface we've already detected. In this case we skip the - * check for an existing device with the same IP interface name and kill - * the ethernet device later in favor of the modem device. - */ - if ((devtype != NM_DEVICE_TYPE_MODEM) && find_device_by_ip_iface (self, iface)) { - g_object_unref (device); + /* No duplicates */ + if (nm_manager_get_device_by_udi (self, nm_device_get_udi (device))) return; - } - priv->devices = g_slist_append (priv->devices, device); + /* Remove existing devices owned by the new device; eg remove ethernet + * ports that are owned by a WWAN modem, since udev may announce them + * before the modem is fully discovered. + * + * FIXME: use parent/child device relationships instead of removing + * the child NMDevice entirely + */ + for (iter = priv->devices; iter; iter = iter->next) { + iface = nm_device_get_ip_iface (iter->data); + if (nm_device_owns_iface (device, iface)) + remove = g_slist_prepend (remove, iter->data); + } + for (iter = remove; iter; iter = iter->next) + remove_device (self, NM_DEVICE (iter->data), FALSE); + g_slist_free (remove); + + priv->devices = g_slist_append (priv->devices, g_object_ref (device)); g_signal_connect (device, "state-changed", G_CALLBACK (manager_device_state_changed), @@ -1874,6 +1876,9 @@ add_device (NMManager *self, NMDevice *device, gboolean generate_con) nm_device_set_enabled (device, enabled); } + iface = nm_device_get_iface (device); + g_assert (iface); + type_desc = nm_device_get_type_desc (device); g_assert (type_desc); driver = nm_device_get_driver (device); @@ -1983,6 +1988,7 @@ bluez_manager_bdaddr_added_cb (NMBluezManager *bluez_mgr, has_nap ? "NAP" : ""); add_device (manager, device, FALSE); + g_object_unref (device); } } @@ -2050,25 +2056,31 @@ find_device_by_ifindex (NMManager *self, guint32 ifindex) return NULL; } -#define PLUGIN_PREFIX "libnm-device-plugin-" - -typedef struct { - NMDeviceType t; - guint priority; - NMDeviceFactoryCreateFunc create_func; -} PluginInfo; - -static gint -plugin_sort (PluginInfo *a, PluginInfo *b) +static void +factory_device_added_cb (NMDeviceFactory *factory, + NMDevice *device, + gpointer user_data) { - /* Higher priority means sort earlier in the list (ie, return -1) */ - if (a->priority > b->priority) - return -1; - else if (a->priority < b->priority) - return 1; - return 0; + add_device (NM_MANAGER (user_data), device, FALSE); } +static gboolean +factory_component_added_cb (NMDeviceFactory *factory, + GObject *component, + gpointer user_data) +{ + NMManager *self = NM_MANAGER (user_data); + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) + return TRUE; + } + return FALSE; +} + +#define PLUGIN_PREFIX "libnm-device-plugin-" + static void load_device_factories (NMManager *self) { @@ -2077,7 +2089,7 @@ load_device_factories (NMManager *self) GError *error = NULL; const char *item; char *path; - GSList *list = NULL, *iter; + GSList *iter; dir = g_dir_open (NMPLUGINDIR, 0, &error); if (!dir) { @@ -2090,11 +2102,11 @@ load_device_factories (NMManager *self) while ((item = g_dir_read_name (dir))) { GModule *plugin; + NMDeviceFactory *factory; NMDeviceFactoryCreateFunc create_func; - NMDeviceFactoryPriorityFunc priority_func; - NMDeviceFactoryTypeFunc type_func; - PluginInfo *info = NULL; - NMDeviceType plugin_type; + NMDeviceFactoryDeviceTypeFunc type_func; + NMDeviceType dev_type; + gboolean found = FALSE; if (!g_str_has_prefix (item, PLUGIN_PREFIX)) continue; @@ -2109,60 +2121,63 @@ load_device_factories (NMManager *self) continue; } - if (!g_module_symbol (plugin, "nm_device_factory_get_type", (gpointer) (&type_func))) { - nm_log_warn (LOGD_HW, "(%s): failed to find device factory: %s", item, g_module_error ()); + if (!g_module_symbol (plugin, "nm_device_factory_get_device_type", (gpointer) &type_func)) { + nm_log_warn (LOGD_HW, "(%s): failed to find device factory type: %s", item, g_module_error ()); g_module_close (plugin); continue; } /* Make sure we don't double-load plugins */ - plugin_type = type_func (); - for (iter = list; iter; iter = g_slist_next (iter)) { - PluginInfo *candidate = iter->data; + dev_type = type_func (); + for (iter = priv->factories; iter; iter = iter->next) { + NMDeviceType t = NM_DEVICE_TYPE_UNKNOWN; - if (plugin_type == candidate->t) { - info = candidate; + g_object_get (G_OBJECT (iter->data), + NM_DEVICE_FACTORY_DEVICE_TYPE, &t, + NULL); + if (dev_type == t) { + found = TRUE; break; } } - if (info) { + if (found) { g_module_close (plugin); continue; } - if (!g_module_symbol (plugin, "nm_device_factory_create_device", (gpointer) (&create_func))) { - nm_log_warn (LOGD_HW, "(%s): failed to find device creator: %s", item, g_module_error ()); + if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) { + nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ()); g_module_close (plugin); continue; } - info = g_malloc0 (sizeof (*info)); - info->create_func = create_func; - info->t = plugin_type; - - /* Grab priority; higher number equals higher priority */ - if (g_module_symbol (plugin, "nm_device_factory_get_priority", (gpointer) (&priority_func))) - info->priority = priority_func (); - else { - nm_log_dbg (LOGD_HW, "(%s): failed to find device factory priority func: %s", - item, g_module_error ()); + factory = create_func (&error); + if (!factory) { + nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s", + item, error ? error->message : "unknown"); + g_clear_error (&error); + g_module_close (plugin); + continue; } + g_clear_error (&error); g_module_make_resident (plugin); - list = g_slist_insert_sorted (list, info, (GCompareFunc) plugin_sort); + priv->factories = g_slist_prepend (priv->factories, factory); - nm_log_info (LOGD_HW, "Loaded device factory: %s", g_module_name (plugin)); + g_signal_connect (factory, + NM_DEVICE_FACTORY_DEVICE_ADDED, + G_CALLBACK (factory_device_added_cb), + self); + g_signal_connect (factory, + NM_DEVICE_FACTORY_COMPONENT_ADDED, + G_CALLBACK (factory_component_added_cb), + self); + + nm_log_info (LOGD_HW, "Loaded device plugin: %s", g_module_name (plugin)); }; g_dir_close (dir); - /* Ditch the priority info and copy the factory functions to our private data */ - for (iter = list; iter; iter = g_slist_next (iter)) { - PluginInfo *info = iter->data; - - priv->factories = g_slist_append (priv->factories, info->create_func); - g_free (info); - } - g_slist_free (list); + priv->factories = g_slist_reverse (priv->factories); } static void @@ -2184,11 +2199,10 @@ platform_link_added_cb (NMPlatform *platform, return; /* Try registered device factories */ - for (iter = priv->factories; iter; iter = g_slist_next (iter)) { - NMDeviceFactoryCreateFunc create_func = iter->data; + for (iter = priv->factories; iter; iter = iter->next) { + NMDeviceFactory *factory = NM_DEVICE_FACTORY (iter->data); - g_clear_error (&error); - device = (NMDevice *) create_func (plink, &error); + device = nm_device_factory_new_link (factory, plink, &error); if (device && NM_IS_DEVICE (device)) { g_assert_no_error (error); break; /* success! */ @@ -2281,8 +2295,10 @@ platform_link_added_cb (NMPlatform *platform, } } - if (device) + if (device) { add_device (self, device, plink->type != NM_LINK_TYPE_LOOPBACK); + g_object_unref (device); + } } static void @@ -4807,6 +4823,8 @@ nm_manager_new (NMSettings *settings, */ rfkill_change_wifi (priv->radio_states[RFKILL_TYPE_WLAN].desc, initial_wifi_enabled); + load_device_factories (singleton); + return singleton; } @@ -4917,8 +4935,6 @@ nm_manager_init (NMManager *manager) KERNEL_FIRMWARE_DIR); } - load_device_factories (manager); - /* Update timestamps in active connections */ priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, manager); } @@ -5046,6 +5062,7 @@ dispose (GObject *object) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); DBusGConnection *bus; DBusConnection *dbus_connection; + GSList *iter; g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; @@ -5116,6 +5133,12 @@ dispose (GObject *object) g_clear_object (&priv->fw_monitor); } + for (iter = priv->factories; iter; iter = iter->next) { + NMDeviceFactory *factory = iter->data; + + g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager); + g_object_unref (factory); + } g_clear_pointer (&priv->factories, g_slist_free); if (priv->timestamp_update_id) {