diff --git a/include/NetworkManager.h b/include/NetworkManager.h index 3b5106d23..6ccd2886e 100644 --- a/include/NetworkManager.h +++ b/include/NetworkManager.h @@ -101,20 +101,22 @@ typedef enum { * @NM_DEVICE_TYPE_WIMAX: an 802.16e Mobile WiMAX broadband device * @NM_DEVICE_TYPE_MODEM: a modem supporting analog telephone, CDMA/EVDO, * GSM/UMTS, or LTE network access protocols + * @NM_DEVICE_TYPE_INFINIBAND: an IP-over-Infiniband device * * #NMDeviceType values indicate the type of hardware represented by * an #NMDevice. **/ typedef enum { - NM_DEVICE_TYPE_UNKNOWN = 0, - NM_DEVICE_TYPE_ETHERNET = 1, - NM_DEVICE_TYPE_WIFI = 2, - NM_DEVICE_TYPE_UNUSED1 = 3, - NM_DEVICE_TYPE_UNUSED2 = 4, - NM_DEVICE_TYPE_BT = 5, /* Bluetooth */ - NM_DEVICE_TYPE_OLPC_MESH = 6, - NM_DEVICE_TYPE_WIMAX = 7, - NM_DEVICE_TYPE_MODEM = 8, + NM_DEVICE_TYPE_UNKNOWN = 0, + NM_DEVICE_TYPE_ETHERNET = 1, + NM_DEVICE_TYPE_WIFI = 2, + NM_DEVICE_TYPE_UNUSED1 = 3, + NM_DEVICE_TYPE_UNUSED2 = 4, + NM_DEVICE_TYPE_BT = 5, /* Bluetooth */ + NM_DEVICE_TYPE_OLPC_MESH = 6, + NM_DEVICE_TYPE_WIMAX = 7, + NM_DEVICE_TYPE_MODEM = 8, + NM_DEVICE_TYPE_INFINIBAND = 9, } NMDeviceType; /** diff --git a/introspection/nm-device-infiniband.xml b/introspection/nm-device-infiniband.xml new file mode 100644 index 000000000..097714c69 --- /dev/null +++ b/introspection/nm-device-infiniband.xml @@ -0,0 +1,27 @@ + + + + + + + + Hardware address of the device. + + + + + + Indicates whether the physical carrier is found (e.g. whether a cable is plugged in or not). + + + + + + + A dictionary mapping property names to variant boxed values + + + + + + diff --git a/src/Makefile.am b/src/Makefile.am index c46e5e8e5..9685cc0e6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -130,12 +130,16 @@ NetworkManager_SOURCES = \ wifi-utils-nl80211.h \ nm-device-wifi.c \ nm-device-wifi.h \ + nm-device-wired.c \ + nm-device-wired.h \ nm-device-olpc-mesh.c \ nm-device-olpc-mesh.h \ nm-device-bt.c \ nm-device-bt.h \ nm-device-modem.h \ nm-device-modem.c \ + nm-device-infiniband.c \ + nm-device-infiniband.h \ nm-wifi-ap.c \ nm-wifi-ap.h \ nm-wifi-ap-utils.c \ @@ -201,6 +205,9 @@ nm-device-interface-glue.h: $(top_srcdir)/introspection/nm-device.xml nm-device-ethernet-glue.h: $(top_srcdir)/introspection/nm-device-ethernet.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_device_ethernet --mode=glib-server --output=$@ $< +nm-device-infiniband-glue.h: $(top_srcdir)/introspection/nm-device-infiniband.xml + $(AM_V_GEN) dbus-binding-tool --prefix=nm_device_infiniband --mode=glib-server --output=$@ $< + nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml $(AM_V_GEN) dbus-binding-tool --prefix=nm_device_wifi --mode=glib-server --output=$@ $< @@ -233,6 +240,7 @@ BUILT_SOURCES = \ nm-manager-glue.h \ nm-device-interface-glue.h \ nm-device-ethernet-glue.h \ + nm-device-infiniband-glue.h \ nm-device-wifi-glue.h \ nm-device-olpc-mesh-glue.h \ nm-device-bt-glue.h \ diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c index 078f15272..bc587b206 100644 --- a/src/logging/nm-logging.c +++ b/src/logging/nm-logging.c @@ -47,7 +47,7 @@ static guint32 log_domains = \ LOGD_DHCP4 | LOGD_DHCP6 | LOGD_PPP | LOGD_IP4 | LOGD_IP6 | LOGD_AUTOIP4 | \ LOGD_DNS | LOGD_VPN | LOGD_SHARING | LOGD_SUPPLICANT | LOGD_AGENTS | \ LOGD_SETTINGS | LOGD_SUSPEND | LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | \ - LOGD_WIMAX; + LOGD_WIMAX | LOGD_INFINIBAND; typedef struct { guint32 num; @@ -88,6 +88,7 @@ static const LogDesc domain_descs[] = { { LOGD_DEVICE, "DEVICE" }, { LOGD_OLPC_MESH, "OLPC" }, { LOGD_WIMAX, "WIMAX" }, + { LOGD_INFINIBAND,"INFINIBAND" }, { 0, NULL } }; diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h index e3e05f59b..586f61c7f 100644 --- a/src/logging/nm-logging.h +++ b/src/logging/nm-logging.h @@ -52,6 +52,7 @@ enum { LOGD_DEVICE = 0x00200000, /* Device state and activation */ LOGD_OLPC_MESH = 0x00400000, LOGD_WIMAX = 0x00800000, + LOGD_INFINIBAND = 0x01000000, }; #define LOGD_DHCP (LOGD_DHCP4 | LOGD_DHCP6) diff --git a/src/nm-device-ethernet.c b/src/nm-device-ethernet.c index 33d33c907..f33204524 100644 --- a/src/nm-device-ethernet.c +++ b/src/nm-device-ethernet.c @@ -38,8 +38,6 @@ #include -#include - #include "nm-glib-compat.h" #include "nm-device-ethernet.h" #include "nm-device-interface.h" @@ -49,7 +47,6 @@ #include "nm-supplicant-manager.h" #include "nm-supplicant-interface.h" #include "nm-supplicant-config.h" -#include "nm-netlink-monitor.h" #include "nm-system.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h" @@ -59,14 +56,12 @@ #include "ppp-manager/nm-ppp-manager.h" #include "nm-logging.h" #include "nm-properties-changed-signal.h" -#include "nm-dhcp-manager.h" -#include "nm-netlink-utils.h" #include "nm-utils.h" #include "nm-device-ethernet-glue.h" -G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE) +G_DEFINE_TYPE (NMDeviceEthernet, nm_device_ethernet, NM_TYPE_DEVICE_WIRED) #define NM_DEVICE_ETHERNET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_ETHERNET, NMDeviceEthernetPrivate)) @@ -96,17 +91,8 @@ typedef struct Supplicant { } Supplicant; typedef struct { - gboolean disposed; - - guint8 hw_addr[ETH_ALEN]; /* Currently set MAC address */ guint8 perm_hw_addr[ETH_ALEN]; /* Permanent MAC address */ guint8 initial_hw_addr[ETH_ALEN]; /* Initial MAC address (as seen when NM starts) */ - gboolean carrier; - - NMNetlinkMonitor * monitor; - gulong link_connected_id; - gulong link_disconnected_id; - guint carrier_action_defer_id; Supplicant supplicant; guint supplicant_timeout_id; @@ -176,122 +162,6 @@ nm_ethernet_error_get_type (void) return etype; } -static void -carrier_action_defer_clear (NMDeviceEthernet *self) -{ - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - - if (priv->carrier_action_defer_id) { - g_source_remove (priv->carrier_action_defer_id); - priv->carrier_action_defer_id = 0; - } -} - -static gboolean -carrier_action_defer_cb (gpointer user_data) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - NMDeviceState state; - - priv->carrier_action_defer_id = 0; - - state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); - if (state == NM_DEVICE_STATE_UNAVAILABLE) { - if (priv->carrier) - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); - } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { - if (!priv->carrier) - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); - } - - return FALSE; -} - -static void -set_carrier (NMDeviceEthernet *self, - const gboolean carrier, - const gboolean defer_action) -{ - NMDeviceEthernetPrivate *priv; - NMDeviceState state; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - if (priv->carrier == carrier) - return; - - /* Clear any previous deferred action */ - carrier_action_defer_clear (self); - - priv->carrier = carrier; - g_object_notify (G_OBJECT (self), NM_DEVICE_ETHERNET_CARRIER); - - state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); - nm_log_info (LOGD_HW | LOGD_ETHER, "(%s): carrier now %s (device state %d%s)", - nm_device_get_iface (NM_DEVICE (self)), - carrier ? "ON" : "OFF", - state, - defer_action ? ", deferring action for 4 seconds" : ""); - - if (defer_action) - priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self); - else - carrier_action_defer_cb (self); -} - -static void -carrier_on (NMNetlinkMonitor *monitor, - int idx, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); - guint32 caps; - - /* Make sure signal is for us */ - if (idx == nm_device_get_ifindex (device)) { - /* Ignore spurious netlink messages */ - caps = nm_device_get_capabilities (device); - if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT)) - return; - - set_carrier (self, TRUE, FALSE); - } -} - -static void -carrier_off (NMNetlinkMonitor *monitor, - int idx, - gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); - guint32 caps; - - /* Make sure signal is for us */ - if (idx == nm_device_get_ifindex (device)) { - NMDeviceState state; - gboolean defer = FALSE; - - /* Ignore spurious netlink messages */ - caps = nm_device_get_capabilities (device); - if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT)) - return; - - /* Defer carrier-off event actions while connected by a few seconds - * so that tripping over a cable, power-cycling a switch, or breaking - * off the RJ45 locking tab isn't so catastrophic. - */ - state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); - if (state > NM_DEVICE_STATE_DISCONNECTED) - defer = TRUE; - - set_carrier (self, FALSE, defer); - } -} - static void _update_s390_subchannels (NMDeviceEthernet *self) { @@ -403,7 +273,6 @@ constructor (GType type, GObject *object; NMDeviceEthernetPrivate *priv; NMDevice *self; - guint32 caps; object = G_OBJECT_CLASS (nm_device_ethernet_parent_class)->constructor (type, n_construct_params, @@ -421,59 +290,6 @@ constructor (GType type, /* s390 stuff */ _update_s390_subchannels (NM_DEVICE_ETHERNET (self)); - caps = nm_device_get_capabilities (self); - if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { - GError *error = NULL; - guint32 ifflags = 0; - - /* Only listen to netlink for cards that support carrier detect */ - priv->monitor = nm_netlink_monitor_get (); - - priv->link_connected_id = g_signal_connect (priv->monitor, "carrier-on", - G_CALLBACK (carrier_on), - self); - priv->link_disconnected_id = g_signal_connect (priv->monitor, "carrier-off", - G_CALLBACK (carrier_off), - self); - - /* Get initial link state */ - if (!nm_netlink_monitor_get_flags_sync (priv->monitor, - nm_device_get_ifindex (NM_DEVICE (self)), - &ifflags, - &error)) { - nm_log_warn (LOGD_HW | LOGD_ETHER, - "(%s): couldn't get initial carrier state: (%d) %s", - nm_device_get_iface (NM_DEVICE (self)), - error ? error->code : -1, - (error && error->message) ? error->message : "unknown"); - g_clear_error (&error); - } else - priv->carrier = !!(ifflags & IFF_LOWER_UP); - - nm_log_info (LOGD_HW | LOGD_ETHER, - "(%s): carrier is %s", - nm_device_get_iface (NM_DEVICE (self)), - priv->carrier ? "ON" : "OFF"); - - /* Request link state again just in case an error occurred getting the - * initial link state. - */ - if (!nm_netlink_monitor_request_status (priv->monitor, &error)) { - nm_log_warn (LOGD_HW | LOGD_ETHER, - "(%s): couldn't request carrier state: (%d) %s", - nm_device_get_iface (NM_DEVICE (self)), - error ? error->code : -1, - (error && error->message) ? error->message : "unknown"); - g_clear_error (&error); - } - } else { - nm_log_info (LOGD_HW | LOGD_ETHER, - "(%s): driver '%s' does not support carrier detection.", - nm_device_get_iface (self), - nm_device_get_driver (self)); - priv->carrier = TRUE; - } - return object; } @@ -546,24 +362,6 @@ real_take_down (NMDevice *dev) } } -static gboolean -real_hw_is_up (NMDevice *device) -{ - return nm_system_iface_is_up (nm_device_get_ip_ifindex (device)); -} - -static gboolean -real_hw_bring_up (NMDevice *dev, gboolean *no_firmware) -{ - return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware); -} - -static void -real_hw_take_down (NMDevice *dev) -{ - nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL); -} - NMDevice * nm_device_ethernet_new (const char *udi, const char *iface, @@ -583,24 +381,6 @@ nm_device_ethernet_new (const char *udi, } -/* - * nm_device_ethernet_get_address - * - * Get a device's hardware address - * - */ -void -nm_device_ethernet_get_address (NMDeviceEthernet *self, struct ether_addr *addr) -{ - NMDeviceEthernetPrivate *priv; - - g_return_if_fail (self != NULL); - g_return_if_fail (addr != NULL); - - priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - memcpy (addr, &priv->hw_addr, sizeof (priv->hw_addr)); -} - gboolean nm_device_bond_connection_matches (NMDevice *device, NMConnection *connection) { @@ -660,12 +440,14 @@ out: static void _update_hw_addr (NMDeviceEthernet *self, const guint8 *addr) { - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + guint8 *current_addr; g_return_if_fail (addr != NULL); - if (memcmp (&priv->hw_addr, addr, ETH_ALEN)) { - memcpy (&priv->hw_addr, addr, ETH_ALEN); + current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self)); + + if (memcmp (current_addr, addr, ETH_ALEN)) { + memcpy (current_addr, addr, ETH_ALEN); g_object_notify (G_OBJECT (self), NM_DEVICE_ETHERNET_HW_ADDRESS); } } @@ -674,7 +456,7 @@ static gboolean _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail) { NMDevice *dev = NM_DEVICE (self); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + guint8 *current_addr; const char *iface; char *mac_str = NULL; gboolean success = FALSE; @@ -683,18 +465,18 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail) iface = nm_device_get_iface (dev); - mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); - /* Do nothing if current MAC is same */ - if (!memcmp (&priv->hw_addr, addr, ETH_ALEN)) { + current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self)); + if (!memcmp (current_addr, addr, ETH_ALEN)) { nm_log_dbg (LOGD_DEVICE | LOGD_ETHER, "(%s): no MAC address change needed", iface); - g_free (mac_str); return TRUE; } + mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); + /* Can't change MAC address while device is up */ - real_hw_take_down (dev); + nm_device_hw_take_down (dev, FALSE); success = nm_system_iface_set_mac (nm_device_get_ip_ifindex (dev), (struct ether_addr *) addr); if (success) { @@ -706,7 +488,7 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail) nm_log_warn (LOGD_DEVICE | LOGD_ETHER, "(%s): failed to %s MAC address to %s", iface, detail, mac_str); } - real_hw_bring_up (dev, NULL); + nm_device_hw_bring_up (dev, FALSE, NULL); g_free (mac_str); return success; @@ -715,28 +497,16 @@ _set_hw_addr (NMDeviceEthernet *self, const guint8 *addr, const char *detail) static void real_update_hw_address (NMDevice *dev) { - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - struct ifreq req; - int fd; + guint8 *hw_addr, old_addr[ETH_ALEN]; - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - nm_log_warn (LOGD_HW, "couldn't open control socket."); - return; - } + hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev)); + memcpy (old_addr, hw_addr, ETH_ALEN); - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ); + NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->update_hw_address (dev); - errno = 0; - if (ioctl (fd, SIOCGIFHWADDR, &req) < 0) { - nm_log_err (LOGD_HW | LOGD_ETHER, - "(%s) failed to read hardware address (error %d)", - nm_device_get_iface (dev), errno); - } else - _update_hw_addr (self, (const guint8 *) &req.ifr_hwaddr.sa_data); - - close (fd); + hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev)); + if (memcmp (old_addr, hw_addr, ETH_ALEN)) + g_object_notify (G_OBJECT (dev), NM_DEVICE_ETHERNET_HW_ADDRESS); } static void @@ -766,10 +536,13 @@ real_update_permanent_hw_address (NMDevice *dev) errno = 0; ret = ioctl (fd, SIOCETHTOOL, &req); if ((ret < 0) || !nm_ethernet_address_is_valid ((struct ether_addr *) epaddr->data)) { + guint8 *current_addr; + nm_log_err (LOGD_HW | LOGD_ETHER, "(%s): unable to read permanent MAC address (error %d)", nm_device_get_iface (dev), errno); /* Fall back to current address */ - memcpy (epaddr->data, &priv->hw_addr, ETH_ALEN); + current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self)); + memcpy (epaddr->data, current_addr, ETH_ALEN); } if (memcmp (&priv->perm_hw_addr, epaddr->data, ETH_ALEN)) { @@ -785,6 +558,7 @@ real_update_initial_hw_address (NMDevice *dev) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + guint8 *current_addr; char *mac_str = NULL; guint8 *addr = priv->initial_hw_addr; guint8 zero[ETH_ALEN] = {0,0,0,0,0,0}; @@ -792,11 +566,12 @@ real_update_initial_hw_address (NMDevice *dev) /* This sets initial MAC address from current MAC address. It should only * be called from NMDevice constructor() to really get the initial address. */ - if (!memcmp (&priv->hw_addr, &zero, ETH_ALEN)) + current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self)); + if (!memcmp (current_addr, &zero, ETH_ALEN)) real_update_hw_address (dev); - if (memcmp (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN)) - memcpy (&priv->initial_hw_addr, &priv->hw_addr, ETH_ALEN); + if (memcmp (&priv->initial_hw_addr, current_addr, ETH_ALEN)) + memcpy (&priv->initial_hw_addr, current_addr, ETH_ALEN); mac_str = g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); @@ -825,34 +600,6 @@ real_get_generic_capabilities (NMDevice *dev) return caps; } -static gboolean -real_can_interrupt_activation (NMDevice *dev) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - gboolean interrupt = FALSE; - - /* Devices that support carrier detect can interrupt activation - * if the link becomes inactive. - */ - if (nm_device_get_capabilities (dev) & NM_DEVICE_CAP_CARRIER_DETECT) { - if (NM_DEVICE_ETHERNET_GET_PRIVATE (self)->carrier == FALSE) - interrupt = TRUE; - } - return interrupt; -} - -static gboolean -real_is_available (NMDevice *dev) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - - /* Can't do anything if there isn't a carrier */ - if (!NM_DEVICE_ETHERNET_GET_PRIVATE (self)->carrier) - return FALSE; - - return TRUE; -} - static gboolean match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_mac) { @@ -1795,87 +1542,19 @@ wired_match_config (NMDevice *self, NMConnection *connection) return TRUE; } -static gboolean -ip4_match_config (NMDevice *self, NMConnection *connection) -{ - NMSettingIP4Config *s_ip4; - int i, num; - GSList *leases, *iter; - NMDHCPManager *dhcp_mgr; - const char *method; - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (!s_ip4) - return FALSE; - - /* Get any saved leases that apply to this connection */ - dhcp_mgr = nm_dhcp_manager_get (); - leases = nm_dhcp_manager_get_lease_config (dhcp_mgr, - nm_device_get_iface (self), - nm_connection_get_uuid (connection)); - g_object_unref (dhcp_mgr); - - method = nm_setting_ip4_config_get_method (s_ip4); - if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - gboolean found = FALSE; - - /* Find at least one lease's address on the device */ - for (iter = leases; iter; iter = g_slist_next (iter)) { - NMIP4Config *ip4_config = iter->data; - NMIP4Address *addr = nm_ip4_config_get_address (ip4_config, 0); - struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) }; - - if (addr && nm_netlink_find_address (nm_device_get_ip_ifindex (self), - AF_INET, - &tmp, - nm_ip4_address_get_prefix (addr))) { - found = TRUE; /* Yay, device has same address as a lease */ - break; - } - } - g_slist_foreach (leases, (GFunc) g_object_unref, NULL); - g_slist_free (leases); - return found; - } else { - /* Maybe the connection used to be DHCP and there are stale leases; ignore them */ - g_slist_foreach (leases, (GFunc) g_object_unref, NULL); - g_slist_free (leases); - } - - /* 'shared' and 'link-local' aren't supported methods because 'shared' - * requires too much iptables and dnsmasq state to be reclaimed, and - * avahi-autoipd isn't smart enough to allow the link-local address to be - * determined at any point other than when it was first assigned. - */ - if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) - return FALSE; - - /* Everything below for static addressing */ - - /* Find all IP4 addresses of this connection on the device */ - num = nm_setting_ip4_config_get_num_addresses (s_ip4); - for (i = 0; i < num; i++) { - NMIP4Address *addr = nm_setting_ip4_config_get_address (s_ip4, i); - struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) }; - - if (!nm_netlink_find_address (nm_device_get_ip_ifindex (self), - AF_INET, - &tmp, - nm_ip4_address_get_prefix (addr))) - return FALSE; - } - - /* Success; all the connection's static IP addresses are assigned to the device */ - return TRUE; -} - static NMConnection * connection_match_config (NMDevice *self, const GSList *connections) { - GSList *iter; + const GSList *iter; + GSList *wired_matches; NMSettingConnection *s_con; + NMConnection *match; - for (iter = (GSList *) connections; iter; iter = g_slist_next (iter)) { + /* First narrow @connections down to those that match in their + * NMSettingWired configuration. + */ + wired_matches = NULL; + for (iter = connections; iter; iter = iter->next) { NMConnection *candidate = NM_CONNECTION (iter->data); s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION); @@ -1893,13 +1572,15 @@ connection_match_config (NMDevice *self, const GSList *connections) if (!wired_match_config (self, candidate)) continue; - if (!ip4_match_config (self, candidate)) - continue; - - return candidate; + wired_matches = g_slist_prepend (wired_matches, candidate); } - return NULL; + /* Now pass those to the super method, which will check IP config */ + wired_matches = g_slist_reverse (wired_matches); + match = NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->connection_match_config (self, wired_matches); + g_slist_free (wired_matches); + + return match; } static void @@ -1908,29 +1589,6 @@ dispose (GObject *object) NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - if (priv->disposed) { - G_OBJECT_CLASS (nm_device_ethernet_parent_class)->dispose (object); - return; - } - - priv->disposed = TRUE; - - if (priv->link_connected_id) { - g_signal_handler_disconnect (priv->monitor, priv->link_connected_id); - priv->link_connected_id = 0; - } - if (priv->link_disconnected_id) { - g_signal_handler_disconnect (priv->monitor, priv->link_disconnected_id); - priv->link_disconnected_id = 0; - } - - carrier_action_defer_clear (self); - - if (priv->monitor) { - g_object_unref (priv->monitor); - priv->monitor = NULL; - } - g_free (priv->subchan1); g_free (priv->subchan2); g_free (priv->subchan3); @@ -1945,10 +1603,12 @@ get_property (GObject *object, guint prop_id, { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + guint8 *current_addr; switch (prop_id) { case PROP_HW_ADDRESS: - g_value_take_string (value, nm_utils_hwaddr_ntoa (&priv->hw_addr, ARPHRD_ETHER)); + current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self)); + g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_ETHER)); break; case PROP_PERM_HW_ADDRESS: g_value_take_string (value, nm_utils_hwaddr_ntoa (&priv->perm_hw_addr, ARPHRD_ETHER)); @@ -1957,7 +1617,7 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, nm_device_ethernet_get_speed (self)); break; case PROP_CARRIER: - g_value_set_boolean (value, priv->carrier); + g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (self))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1991,18 +1651,13 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = real_get_generic_capabilities; - parent_class->hw_is_up = real_hw_is_up; - parent_class->hw_bring_up = real_hw_bring_up; - parent_class->hw_take_down = real_hw_take_down; parent_class->is_up = real_is_up; parent_class->bring_up = real_bring_up; parent_class->take_down = real_take_down; - parent_class->can_interrupt_activation = real_can_interrupt_activation; parent_class->update_hw_address = real_update_hw_address; parent_class->update_permanent_hw_address = real_update_permanent_hw_address; parent_class->update_initial_hw_address = real_update_initial_hw_address; parent_class->get_best_auto_connection = real_get_best_auto_connection; - parent_class->is_available = real_is_available; parent_class->check_connection_compatible = real_check_connection_compatible; parent_class->complete_connection = real_complete_connection; diff --git a/src/nm-device-ethernet.h b/src/nm-device-ethernet.h index c7adbf8f8..51993db55 100644 --- a/src/nm-device-ethernet.h +++ b/src/nm-device-ethernet.h @@ -23,9 +23,8 @@ #define NM_DEVICE_ETHERNET_H #include -#include -#include "nm-device.h" +#include "nm-device-wired.h" G_BEGIN_DECLS @@ -42,11 +41,11 @@ G_BEGIN_DECLS #define NM_DEVICE_ETHERNET_CARRIER "carrier" typedef struct { - NMDevice parent; + NMDeviceWired parent; } NMDeviceEthernet; typedef struct { - NMDeviceClass parent; + NMDeviceWiredClass parent; /* Signals */ void (*properties_changed) (NMDeviceEthernet *device, GHashTable *properties); @@ -60,9 +59,6 @@ NMDevice *nm_device_ethernet_new (const char *udi, const char *iface, const char *driver); -void nm_device_ethernet_get_address (NMDeviceEthernet *dev, - struct ether_addr *addr); - gboolean nm_device_bond_connection_matches (NMDevice *device, NMConnection *connection); G_END_DECLS diff --git a/src/nm-device-infiniband.c b/src/nm-device-infiniband.c new file mode 100644 index 000000000..2e4a5e776 --- /dev/null +++ b/src/nm-device-infiniband.c @@ -0,0 +1,468 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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 2011 Red Hat, Inc. + */ + +#include "config.h" + +#include +#include + +#include +#include + +#include "nm-device-infiniband.h" +#include "nm-device-interface.h" +#include "nm-logging.h" +#include "nm-properties-changed-signal.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" +#if 0 +#include "nm-device-private.h" +#include "nm-activation-request.h" +#include "nm-setting-connection.h" +#include "nm-setting-wired.h" +#include "nm-dhcp-manager.h" +#include "nm-netlink-utils.h" +#endif + +#include "nm-device-infiniband-glue.h" + + +G_DEFINE_TYPE (NMDeviceInfiniband, nm_device_infiniband, NM_TYPE_DEVICE_WIRED) + +#define NM_DEVICE_INFINIBAND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandPrivate)) + +typedef enum +{ + NM_INFINIBAND_ERROR_CONNECTION_NOT_INFINIBAND = 0, + NM_INFINIBAND_ERROR_CONNECTION_INVALID, + NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE, +} NMInfinibandError; + +#define NM_INFINIBAND_ERROR (nm_infiniband_error_quark ()) +#define NM_TYPE_INFINIBAND_ERROR (nm_infiniband_error_get_type ()) + +typedef struct { + int dummy; +} NMDeviceInfinibandPrivate; + +enum { + PROPERTIES_CHANGED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +enum { + PROP_0, + PROP_HW_ADDRESS, + PROP_CARRIER, + + LAST_PROP +}; + +static GQuark +nm_infiniband_error_quark (void) +{ + static GQuark quark = 0; + if (!quark) + quark = g_quark_from_static_string ("nm-infiniband-error"); + return quark; +} + +/* This should really be standard. */ +#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } + +static GType +nm_infiniband_error_get_type (void) +{ + static GType etype = 0; + + if (etype == 0) { + static const GEnumValue values[] = { + /* Connection was not a wired connection. */ + ENUM_ENTRY (NM_INFINIBAND_ERROR_CONNECTION_NOT_INFINIBAND, "ConnectionNotInfiniband"), + /* Connection was not a valid wired connection. */ + ENUM_ENTRY (NM_INFINIBAND_ERROR_CONNECTION_INVALID, "ConnectionInvalid"), + /* Connection does not apply to this device. */ + ENUM_ENTRY (NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE, "ConnectionIncompatible"), + { 0, 0, 0 } + }; + etype = g_enum_register_static ("NMInfinibandError", values); + } + return etype; +} + +static GObject* +constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) +{ + GObject *object; + NMDeviceInfinibandPrivate *priv; + NMDevice *self; + + object = G_OBJECT_CLASS (nm_device_infiniband_parent_class)->constructor (type, + n_construct_params, + construct_params); + if (!object) + return NULL; + + self = NM_DEVICE (object); + priv = NM_DEVICE_INFINIBAND_GET_PRIVATE (self); + + nm_log_dbg (LOGD_HW | LOGD_INFINIBAND, "(%s): kernel ifindex %d", + nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_ifindex (NM_DEVICE (self))); + + return object; +} + +static void +nm_device_infiniband_init (NMDeviceInfiniband * self) +{ +} + +NMDevice * +nm_device_infiniband_new (const char *udi, + const char *iface, + const char *driver) +{ + g_return_val_if_fail (udi != NULL, NULL); + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (driver != NULL, NULL); + + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, + NM_DEVICE_INTERFACE_UDI, udi, + NM_DEVICE_INTERFACE_IFACE, iface, + NM_DEVICE_INTERFACE_DRIVER, driver, + NM_DEVICE_INTERFACE_TYPE_DESC, "Infiniband", + NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, + NULL); +} + + +static void +real_update_hw_address (NMDevice *dev) +{ + guint8 *hw_addr, old_addr[INFINIBAND_ALEN]; + + hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev)); + memcpy (old_addr, hw_addr, INFINIBAND_ALEN); + + NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->update_hw_address (dev); + + hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev)); + if (memcmp (old_addr, hw_addr, INFINIBAND_ALEN)) + g_object_notify (G_OBJECT (dev), NM_DEVICE_INFINIBAND_HW_ADDRESS); +} + +static guint32 +real_get_generic_capabilities (NMDevice *dev) +{ + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_NM_SUPPORTED; +} + +static NMConnection * +real_get_best_auto_connection (NMDevice *dev, + GSList *connections, + char **specific_object) +{ + GSList *iter; + + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMConnection *connection = NM_CONNECTION (iter->data); + NMSettingConnection *s_con; + NMSettingInfiniband *s_infiniband; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) + continue; + if (!nm_setting_connection_get_autoconnect (s_con)) + continue; + + s_infiniband = nm_connection_get_setting_infiniband (connection); + if (!s_infiniband) + continue; + + if (s_infiniband) { + guint8 *hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev)); + const GByteArray *mac; + + mac = nm_setting_infiniband_get_mac_address (s_infiniband); + if (mac && memcmp (mac->data, hwaddr, INFINIBAND_ALEN)) + continue; + } + + return connection; + } + return NULL; +} + +static void +real_ip4_config_pre_commit (NMDevice *self, NMIP4Config *config) +{ + NMConnection *connection; + NMSettingInfiniband *s_infiniband; + guint32 mtu; + + connection = nm_act_request_get_connection (nm_device_get_act_request (self)); + g_assert (connection); + s_infiniband = nm_connection_get_setting_infiniband (connection); + g_assert (s_infiniband); + + /* MTU override */ + mtu = nm_setting_infiniband_get_mtu (s_infiniband); + if (mtu) + nm_ip4_config_set_mtu (config, mtu); +} + +static gboolean +real_check_connection_compatible (NMDevice *device, + NMConnection *connection, + GError **error) +{ + NMSettingInfiniband *s_infiniband; + const GByteArray *mac; + + if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) { + g_set_error (error, + NM_INFINIBAND_ERROR, + NM_INFINIBAND_ERROR_CONNECTION_NOT_INFINIBAND, + "The connection was not an Infiniband connection."); + return FALSE; + } + + s_infiniband = nm_connection_get_setting_infiniband (connection); + if (!s_infiniband) { + g_set_error (error, + NM_INFINIBAND_ERROR, NM_INFINIBAND_ERROR_CONNECTION_INVALID, + "The connection was not a valid infiniband connection."); + return FALSE; + } + + if (s_infiniband) { + guint8 *hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)); + + mac = nm_setting_infiniband_get_mac_address (s_infiniband); + if (mac && memcmp (mac->data, hwaddr, INFINIBAND_ALEN)) { + g_set_error (error, + NM_INFINIBAND_ERROR, + NM_INFINIBAND_ERROR_CONNECTION_INCOMPATIBLE, + "The connection's MAC address did not match this device."); + return FALSE; + } + } + + return TRUE; +} + +static gboolean +real_complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingInfiniband *s_infiniband; + const GByteArray *setting_mac; + guint8 *hwaddr; + + nm_utils_complete_generic (connection, + NM_SETTING_INFINIBAND_SETTING_NAME, + existing_connections, + _("Infiniband connection %d"), + NULL, + TRUE); + + s_infiniband = nm_connection_get_setting_infiniband (connection); + if (!s_infiniband) { + s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new (); + nm_connection_add_setting (connection, NM_SETTING (s_infiniband)); + } + + hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)); + setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's MAC */ + if (memcmp (setting_mac->data, hwaddr, INFINIBAND_ALEN)) { + g_set_error_literal (error, + NM_SETTING_INFINIBAND_ERROR, + NM_SETTING_INFINIBAND_ERROR_INVALID_PROPERTY, + NM_SETTING_INFINIBAND_MAC_ADDRESS); + return FALSE; + } + } else { + GByteArray *mac; + + /* Lock the connection to this device by default */ + mac = g_byte_array_sized_new (INFINIBAND_ALEN); + g_byte_array_append (mac, hwaddr, INFINIBAND_ALEN); + g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL); + g_byte_array_free (mac, TRUE); + } + + return TRUE; +} + +static gboolean +spec_match_list (NMDevice *device, const GSList *specs) +{ + char *hwaddr; + gboolean matched; + + hwaddr = nm_utils_hwaddr_ntoa (nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)), ARPHRD_INFINIBAND); + matched = nm_match_spec_hwaddr (specs, hwaddr); + g_free (hwaddr); + + return matched; +} + +static gboolean +infiniband_match_config (NMDevice *self, NMConnection *connection) +{ + NMSettingInfiniband *s_infiniband; + const GByteArray *s_mac; + + s_infiniband = nm_connection_get_setting_infiniband (connection); + if (!s_infiniband) + return FALSE; + + /* MAC address check */ + s_mac = nm_setting_infiniband_get_mac_address (s_infiniband); + if (s_mac && memcmp (s_mac->data, nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (self)), INFINIBAND_ALEN)) + return FALSE; + + return TRUE; +} + +static NMConnection * +connection_match_config (NMDevice *self, const GSList *connections) +{ + const GSList *iter; + GSList *infiniband_matches; + NMConnection *match; + + /* First narrow @connections down to those that match in their + * NMSettingInfiniband configuration. + */ + infiniband_matches = NULL; + for (iter = connections; iter; iter = iter->next) { + NMConnection *candidate = NM_CONNECTION (iter->data); + + if (!nm_connection_is_type (candidate, NM_SETTING_INFINIBAND_SETTING_NAME)) + continue; + if (!infiniband_match_config (self, candidate)) + continue; + + infiniband_matches = g_slist_prepend (infiniband_matches, candidate); + } + + /* Now pass those to the super method, which will check IP config */ + infiniband_matches = g_slist_reverse (infiniband_matches); + match = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->connection_match_config (self, infiniband_matches); + g_slist_free (infiniband_matches); + + return match; +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + guint8 *current_addr; + + switch (prop_id) { + case PROP_HW_ADDRESS: + current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (object)); + g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_INFINIBAND)); + break; + case PROP_CARRIER: + g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMDeviceInfinibandPrivate)); + + /* virtual methods */ + object_class->constructor = constructor; + object_class->get_property = get_property; + object_class->set_property = set_property; + + parent_class->get_generic_capabilities = real_get_generic_capabilities; + parent_class->update_hw_address = real_update_hw_address; + parent_class->get_best_auto_connection = real_get_best_auto_connection; + parent_class->check_connection_compatible = real_check_connection_compatible; + parent_class->complete_connection = real_complete_connection; + + parent_class->ip4_config_pre_commit = real_ip4_config_pre_commit; + parent_class->spec_match_list = spec_match_list; + parent_class->connection_match_config = connection_match_config; + + /* properties */ + g_object_class_install_property + (object_class, PROP_HW_ADDRESS, + g_param_spec_string (NM_DEVICE_INFINIBAND_HW_ADDRESS, + "Active MAC Address", + "Currently set hardware MAC address", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property + (object_class, PROP_CARRIER, + g_param_spec_boolean (NM_DEVICE_INFINIBAND_CARRIER, + "Carrier", + "Carrier", + FALSE, + G_PARAM_READABLE)); + + /* Signals */ + signals[PROPERTIES_CHANGED] = + nm_properties_changed_signal_new (object_class, + G_STRUCT_OFFSET (NMDeviceInfinibandClass, properties_changed)); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), + &dbus_glib_nm_device_infiniband_object_info); + + dbus_g_error_domain_register (NM_INFINIBAND_ERROR, NULL, NM_TYPE_INFINIBAND_ERROR); +} diff --git a/src/nm-device-infiniband.h b/src/nm-device-infiniband.h new file mode 100644 index 000000000..d70abd9d0 --- /dev/null +++ b/src/nm-device-infiniband.h @@ -0,0 +1,60 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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 2011 Red Hat, Inc. + */ + +#ifndef NM_DEVICE_INFINIBAND_H +#define NM_DEVICE_INFINIBAND_H + +#include + +#include "nm-device-wired.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_INFINIBAND (nm_device_infiniband_get_type ()) +#define NM_DEVICE_INFINIBAND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfiniband)) +#define NM_DEVICE_INFINIBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandClass)) +#define NM_IS_DEVICE_INFINIBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_INFINIBAND)) +#define NM_IS_DEVICE_INFINIBAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_INFINIBAND)) +#define NM_DEVICE_INFINIBAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_INFINIBAND, NMDeviceInfinibandClass)) + +#define NM_DEVICE_INFINIBAND_HW_ADDRESS "hw-address" +#define NM_DEVICE_INFINIBAND_CARRIER "carrier" + +typedef struct { + NMDeviceWired parent; +} NMDeviceInfiniband; + +typedef struct { + NMDeviceWiredClass parent; + + /* Signals */ + void (*properties_changed) (NMDeviceInfiniband *device, GHashTable *properties); +} NMDeviceInfinibandClass; + + +GType nm_device_infiniband_get_type (void); + +NMDevice *nm_device_infiniband_new (const char *udi, + const char *iface, + const char *driver); + +G_END_DECLS + +#endif /* NM_DEVICE_INFINIBAND_H */ diff --git a/src/nm-device-wired.c b/src/nm-device-wired.c new file mode 100644 index 000000000..6adbf6a5d --- /dev/null +++ b/src/nm-device-wired.c @@ -0,0 +1,547 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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) 2005 - 2011 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#include "config.h" +#include +#include +#include +#include +#include + +#include "nm-device-wired.h" +#include "nm-device-interface.h" +#include "nm-device-private.h" +#include "nm-dhcp-manager.h" +#include "nm-logging.h" +#include "nm-netlink-monitor.h" +#include "nm-netlink-utils.h" +#include "nm-system.h" +#include "nm-utils.h" +#include "NetworkManagerUtils.h" + + +G_DEFINE_TYPE (NMDeviceWired, nm_device_wired, NM_TYPE_DEVICE) + +#define NM_DEVICE_WIRED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_WIRED, NMDeviceWiredPrivate)) + +#define NM_DEVICE_WIRED_LOG_LEVEL(dev) ((nm_device_get_device_type (dev) == NM_DEVICE_TYPE_INFINIBAND) ? LOGD_INFINIBAND : LOGD_ETHER) + +typedef struct { + guint8 hw_addr[NM_UTILS_HWADDR_LEN_MAX]; /* Currently set MAC address */ + guint hw_addr_type; + guint hw_addr_len; + gboolean carrier; + + NMNetlinkMonitor * monitor; + gulong link_connected_id; + gulong link_disconnected_id; + guint carrier_action_defer_id; + +} NMDeviceWiredPrivate; + +static void +carrier_action_defer_clear (NMDeviceWired *self) +{ + NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); + + if (priv->carrier_action_defer_id) { + g_source_remove (priv->carrier_action_defer_id); + priv->carrier_action_defer_id = 0; + } +} + +static gboolean +carrier_action_defer_cb (gpointer user_data) +{ + NMDeviceWired *self = NM_DEVICE_WIRED (user_data); + NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); + NMDeviceState state; + + priv->carrier_action_defer_id = 0; + + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); + if (state == NM_DEVICE_STATE_UNAVAILABLE) { + if (priv->carrier) + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); + } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { + if (!priv->carrier) + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); + } + + return FALSE; +} + +static void +set_carrier (NMDeviceWired *self, + const gboolean carrier, + const gboolean defer_action) +{ + NMDeviceWiredPrivate *priv; + NMDeviceState state; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_WIRED_GET_PRIVATE (self); + if (priv->carrier == carrier) + return; + + /* Clear any previous deferred action */ + carrier_action_defer_clear (self); + + priv->carrier = carrier; + g_object_notify (G_OBJECT (self), "carrier"); + + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); + nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), + "(%s): carrier now %s (device state %d%s)", + nm_device_get_iface (NM_DEVICE (self)), + carrier ? "ON" : "OFF", + state, + defer_action ? ", deferring action for 4 seconds" : ""); + + if (defer_action) + priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self); + else + carrier_action_defer_cb (self); +} + +static void +carrier_on (NMNetlinkMonitor *monitor, + int idx, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceWired *self = NM_DEVICE_WIRED (device); + guint32 caps; + + /* Make sure signal is for us */ + if (idx == nm_device_get_ifindex (device)) { + /* Ignore spurious netlink messages */ + caps = nm_device_get_capabilities (device); + if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT)) + return; + + set_carrier (self, TRUE, FALSE); + } +} + +static void +carrier_off (NMNetlinkMonitor *monitor, + int idx, + gpointer user_data) +{ + NMDevice *device = NM_DEVICE (user_data); + NMDeviceWired *self = NM_DEVICE_WIRED (device); + guint32 caps; + + /* Make sure signal is for us */ + if (idx == nm_device_get_ifindex (device)) { + NMDeviceState state; + gboolean defer = FALSE; + + /* Ignore spurious netlink messages */ + caps = nm_device_get_capabilities (device); + if (!(caps & NM_DEVICE_CAP_CARRIER_DETECT)) + return; + + /* Defer carrier-off event actions while connected by a few seconds + * so that tripping over a cable, power-cycling a switch, or breaking + * off the RJ45 locking tab isn't so catastrophic. + */ + state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self)); + if (state > NM_DEVICE_STATE_DISCONNECTED) + defer = TRUE; + + set_carrier (self, FALSE, defer); + } +} + +static GObject* +constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) +{ + GObject *object; + NMDeviceWiredPrivate *priv; + NMDevice *self; + guint32 caps; + + object = G_OBJECT_CLASS (nm_device_wired_parent_class)->constructor (type, + n_construct_params, + construct_params); + if (!object) + return NULL; + + self = NM_DEVICE (object); + priv = NM_DEVICE_WIRED_GET_PRIVATE (self); + + nm_log_dbg (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), + "(%s): kernel ifindex %d", + nm_device_get_iface (NM_DEVICE (self)), + nm_device_get_ifindex (NM_DEVICE (self))); + + if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_ETHERNET) { + priv->hw_addr_type = ARPHRD_ETHER; + priv->hw_addr_len = ETH_ALEN; + } else if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_INFINIBAND) { + priv->hw_addr_type = ARPHRD_INFINIBAND; + priv->hw_addr_len = INFINIBAND_ALEN; + } else + g_assert_not_reached (); + + caps = nm_device_get_capabilities (self); + if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { + GError *error = NULL; + guint32 ifflags = 0; + + /* Only listen to netlink for cards that support carrier detect */ + priv->monitor = nm_netlink_monitor_get (); + + priv->link_connected_id = g_signal_connect (priv->monitor, "carrier-on", + G_CALLBACK (carrier_on), + self); + priv->link_disconnected_id = g_signal_connect (priv->monitor, "carrier-off", + G_CALLBACK (carrier_off), + self); + + /* Get initial link state */ + if (!nm_netlink_monitor_get_flags_sync (priv->monitor, + nm_device_get_ifindex (NM_DEVICE (self)), + &ifflags, + &error)) { + nm_log_warn (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), + "(%s): couldn't get initial carrier state: (%d) %s", + nm_device_get_iface (NM_DEVICE (self)), + error ? error->code : -1, + (error && error->message) ? error->message : "unknown"); + g_clear_error (&error); + } else + priv->carrier = !!(ifflags & IFF_LOWER_UP); + + nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), + "(%s): carrier is %s", + nm_device_get_iface (NM_DEVICE (self)), + priv->carrier ? "ON" : "OFF"); + + /* Request link state again just in case an error occurred getting the + * initial link state. + */ + if (!nm_netlink_monitor_request_status (priv->monitor, &error)) { + nm_log_warn (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), + "(%s): couldn't request carrier state: (%d) %s", + nm_device_get_iface (NM_DEVICE (self)), + error ? error->code : -1, + (error && error->message) ? error->message : "unknown"); + g_clear_error (&error); + } + } else { + nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (NM_DEVICE (self)), + "(%s): driver '%s' does not support carrier detection.", + nm_device_get_iface (self), + nm_device_get_driver (self)); + priv->carrier = TRUE; + } + + return object; +} + +static void +nm_device_wired_init (NMDeviceWired * self) +{ +} + +static gboolean +real_hw_is_up (NMDevice *device) +{ + return nm_system_iface_is_up (nm_device_get_ip_ifindex (device)); +} + +static gboolean +real_hw_bring_up (NMDevice *dev, gboolean *no_firmware) +{ + return nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware); +} + +static void +real_hw_take_down (NMDevice *dev) +{ + nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), FALSE, NULL); +} + +static void +real_update_hw_address (NMDevice *dev) +{ + NMDeviceWired *self = NM_DEVICE_WIRED (dev); + NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); + struct rtnl_link *rtnl; + struct nl_addr *addr; + + rtnl = nm_netlink_index_to_rtnl_link (nm_device_get_ip_ifindex (dev)); + if (!rtnl) { + nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), + "(%s) failed to read hardware address (error %d)", + nm_device_get_iface (dev), errno); + return; + } + + addr = rtnl_link_get_addr (rtnl); + if (!addr) { + nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), + "(%s) no hardware address?", + nm_device_get_iface (dev)); + rtnl_link_put (rtnl); + return; + } + + if (nl_addr_get_len (addr) != priv->hw_addr_len) { + nm_log_err (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (dev), + "(%s) hardware address is wrong length (expected %d got %d)", + nm_device_get_iface (dev), + priv->hw_addr_len, nl_addr_get_len (addr)); + } else { + memcpy (&priv->hw_addr, nl_addr_get_binary_addr (addr), + priv->hw_addr_len); + } + + rtnl_link_put (rtnl); +} + +static gboolean +real_can_interrupt_activation (NMDevice *dev) +{ + NMDeviceWired *self = NM_DEVICE_WIRED (dev); + gboolean interrupt = FALSE; + + /* Devices that support carrier detect can interrupt activation + * if the link becomes inactive. + */ + if (nm_device_get_capabilities (dev) & NM_DEVICE_CAP_CARRIER_DETECT) { + if (NM_DEVICE_WIRED_GET_PRIVATE (self)->carrier == FALSE) + interrupt = TRUE; + } + return interrupt; +} + +static gboolean +real_is_available (NMDevice *dev) +{ + NMDeviceWired *self = NM_DEVICE_WIRED (dev); + + /* Can't do anything if there isn't a carrier */ + if (!NM_DEVICE_WIRED_GET_PRIVATE (self)->carrier) + return FALSE; + + return TRUE; +} + +static gboolean +ip4_match_config (NMDevice *self, NMConnection *connection) +{ + NMSettingIP4Config *s_ip4; + int i, num; + GSList *leases, *iter; + NMDHCPManager *dhcp_mgr; + const char *method; + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + if (!s_ip4) + return FALSE; + + /* Get any saved leases that apply to this connection */ + dhcp_mgr = nm_dhcp_manager_get (); + leases = nm_dhcp_manager_get_lease_config (dhcp_mgr, + nm_device_get_iface (self), + nm_connection_get_uuid (connection)); + g_object_unref (dhcp_mgr); + + method = nm_setting_ip4_config_get_method (s_ip4); + if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { + gboolean found = FALSE; + + /* Find at least one lease's address on the device */ + for (iter = leases; iter; iter = g_slist_next (iter)) { + NMIP4Config *ip4_config = iter->data; + NMIP4Address *addr = nm_ip4_config_get_address (ip4_config, 0); + struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) }; + + if (addr && nm_netlink_find_address (nm_device_get_ip_ifindex (self), + AF_INET, + &tmp, + nm_ip4_address_get_prefix (addr))) { + found = TRUE; /* Yay, device has same address as a lease */ + break; + } + } + g_slist_foreach (leases, (GFunc) g_object_unref, NULL); + g_slist_free (leases); + return found; + } else { + /* Maybe the connection used to be DHCP and there are stale leases; ignore them */ + g_slist_foreach (leases, (GFunc) g_object_unref, NULL); + g_slist_free (leases); + } + + /* 'shared' and 'link-local' aren't supported methods because 'shared' + * requires too much iptables and dnsmasq state to be reclaimed, and + * avahi-autoipd isn't smart enough to allow the link-local address to be + * determined at any point other than when it was first assigned. + */ + if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) + return FALSE; + + /* Everything below for static addressing */ + + /* Find all IP4 addresses of this connection on the device */ + num = nm_setting_ip4_config_get_num_addresses (s_ip4); + for (i = 0; i < num; i++) { + NMIP4Address *addr = nm_setting_ip4_config_get_address (s_ip4, i); + struct in_addr tmp = { .s_addr = nm_ip4_address_get_address (addr) }; + + if (!nm_netlink_find_address (nm_device_get_ip_ifindex (self), + AF_INET, + &tmp, + nm_ip4_address_get_prefix (addr))) + return FALSE; + } + + /* Success; all the connection's static IP addresses are assigned to the device */ + return TRUE; +} + +static NMConnection * +connection_match_config (NMDevice *self, const GSList *connections) +{ + const GSList *iter; + + for (iter = connections; iter; iter = iter->next) { + NMConnection *candidate = NM_CONNECTION (iter->data); + + if (!ip4_match_config (self, candidate)) + continue; + + return candidate; + } + + return NULL; +} + +static void +dispose (GObject *object) +{ + NMDeviceWired *self = NM_DEVICE_WIRED (object); + NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); + + if (priv->link_connected_id) { + g_signal_handler_disconnect (priv->monitor, priv->link_connected_id); + priv->link_connected_id = 0; + } + if (priv->link_disconnected_id) { + g_signal_handler_disconnect (priv->monitor, priv->link_disconnected_id); + priv->link_disconnected_id = 0; + } + + carrier_action_defer_clear (self); + + if (priv->monitor) { + g_object_unref (priv->monitor); + priv->monitor = NULL; + } + + G_OBJECT_CLASS (nm_device_wired_parent_class)->dispose (object); +} + +static void +nm_device_wired_class_init (NMDeviceWiredClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMDeviceWiredPrivate)); + + /* virtual methods */ + object_class->constructor = constructor; + object_class->dispose = dispose; + + parent_class->hw_is_up = real_hw_is_up; + parent_class->hw_bring_up = real_hw_bring_up; + parent_class->hw_take_down = real_hw_take_down; + parent_class->can_interrupt_activation = real_can_interrupt_activation; + parent_class->update_hw_address = real_update_hw_address; + parent_class->is_available = real_is_available; + parent_class->connection_match_config = connection_match_config; +} + +/** + * nm_device_wired_get_hwaddr: + * @dev: an #NMDeviceWired + * + * Get a device's hardware address + * + * Return value: (transfer none): @dev's hardware address + */ +guint8 * +nm_device_wired_get_hwaddr (NMDeviceWired *dev) +{ + NMDeviceWiredPrivate *priv; + + g_return_val_if_fail (dev != NULL, NULL); + + priv = NM_DEVICE_WIRED_GET_PRIVATE (dev); + return priv->hw_addr; +} + +/** + * nm_device_wired_get_hwaddr_type: + * @dev: an #NMDeviceWired + * + * Get the type of a device's hardware address + * + * Return value: the type of @dev's hardware address + */ +int +nm_device_wired_get_hwaddr_type (NMDeviceWired *dev) +{ + NMDeviceWiredPrivate *priv; + + g_return_val_if_fail (dev != NULL, -1); + + priv = NM_DEVICE_WIRED_GET_PRIVATE (dev); + return priv->hw_addr_type; +} + +/** + * nm_device_wired_get_carrier: + * @dev: an #NMDeviceWired + * + * Get @dev's carrier status + * + * Return value: @dev's carrier + */ +gboolean +nm_device_wired_get_carrier (NMDeviceWired *dev) +{ + NMDeviceWiredPrivate *priv; + + g_return_val_if_fail (dev != NULL, -1); + + priv = NM_DEVICE_WIRED_GET_PRIVATE (dev); + return priv->carrier; +} diff --git a/src/nm-device-wired.h b/src/nm-device-wired.h new file mode 100644 index 000000000..b2f6ee43f --- /dev/null +++ b/src/nm-device-wired.h @@ -0,0 +1,55 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager -- Network link manager + * + * 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) 2005 - 2010 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#ifndef NM_DEVICE_WIRED_H +#define NM_DEVICE_WIRED_H + +#include + +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_WIRED (nm_device_wired_get_type ()) +#define NM_DEVICE_WIRED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_WIRED, NMDeviceWired)) +#define NM_DEVICE_WIRED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_WIRED, NMDeviceWiredClass)) +#define NM_IS_DEVICE_WIRED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_WIRED)) +#define NM_IS_DEVICE_WIRED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_WIRED)) +#define NM_DEVICE_WIRED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_WIRED, NMDeviceWiredClass)) + +typedef struct { + NMDevice parent; +} NMDeviceWired; + +typedef struct { + NMDeviceClass parent; + +} NMDeviceWiredClass; + +GType nm_device_wired_get_type (void); + +guint8 *nm_device_wired_get_hwaddr (NMDeviceWired *dev); +int nm_device_wired_get_hwaddr_type (NMDeviceWired *dev); +gboolean nm_device_wired_get_carrier (NMDeviceWired *dev); + +G_END_DECLS + +#endif /* NM_DEVICE_WIRED_H */ diff --git a/src/nm-device.c b/src/nm-device.c index 117ad490b..9a12c7b06 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -296,15 +296,6 @@ constructor (GType type, goto error; } - if (NM_DEVICE_GET_CLASS (dev)->update_hw_address) - NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev); - - if (NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address) - NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address (dev); - - if (NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address) - NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address (dev); - priv->dhcp_manager = nm_dhcp_manager_get (); priv->fw_manager = nm_firewall_manager_get (); @@ -319,6 +310,24 @@ error: return NULL; } +static void +constructed (GObject *object) +{ + NMDevice *dev = NM_DEVICE (object); + + if (NM_DEVICE_GET_CLASS (dev)->update_hw_address) + NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev); + + if (NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address) + NM_DEVICE_GET_CLASS (dev)->update_permanent_hw_address (dev); + + if (NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address) + NM_DEVICE_GET_CLASS (dev)->update_initial_hw_address (dev); + + if (G_OBJECT_CLASS (nm_device_parent_class)->constructed) + G_OBJECT_CLASS (nm_device_parent_class)->constructed (object); +} + static gboolean nm_device_hw_is_up (NMDevice *self) { @@ -3598,6 +3607,7 @@ nm_device_class_init (NMDeviceClass *klass) object_class->set_property = set_property; object_class->get_property = get_property; object_class->constructor = constructor; + object_class->constructed = constructed; klass->get_type_capabilities = real_get_type_capabilities; klass->get_generic_capabilities = real_get_generic_capabilities; diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c index 8a519c0fb..7ddd6ce56 100644 --- a/src/nm-udev-manager.c +++ b/src/nm-udev-manager.c @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -35,6 +36,7 @@ #include "NetworkManagerUtils.h" #include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" +#include "nm-device-infiniband.h" #include "nm-device-ethernet.h" #include "wifi-utils.h" #if WITH_WIMAX @@ -381,6 +383,13 @@ is_wimax (const char *driver) return g_strcmp0 (driver, "i2400m_usb") == 0; } +static gboolean +is_infiniband (GUdevDevice *device) +{ + gint etype = g_udev_device_get_sysfs_attr_as_int (device, "type"); + return etype == ARPHRD_INFINIBAND; +} + static GObject * device_creator (NMUdevManager *manager, GUdevDevice *udev_device, @@ -454,7 +463,9 @@ device_creator (NMUdevManager *manager, #if WITH_WIMAX device = (GObject *) nm_device_wimax_new (path, ifname, driver); #endif - } else + } else if (is_infiniband (udev_device)) + device = (GObject *) nm_device_infiniband_new (path, ifname, driver); + else device = (GObject *) nm_device_ethernet_new (path, ifname, driver); out: @@ -488,7 +499,7 @@ net_add (NMUdevManager *self, GUdevDevice *device) * s390 CTC-type devices that report 256 for some reason. * FIXME: use something other than interface name to detect CTC here. */ - if ((etype != 1) && (is_ctc == FALSE)) { + if ((etype != ARPHRD_ETHER) && (etype != ARPHRD_INFINIBAND) && (is_ctc == FALSE)) { nm_log_dbg (LOGD_HW, "(%s): ignoring interface with type %d", iface, etype); return; } diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index d9ee2dc97..1dfcf990f 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -29,8 +29,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -53,8 +52,10 @@ #include #include #include +#include #include "../nm-device-ethernet.h" +#include "../nm-device-wired.h" #include "nm-dbus-glib-types.h" #include "nm-settings.h" #include "nm-settings-connection.h" @@ -1227,6 +1228,7 @@ have_connection_for_device (NMSettings *self, GByteArray *mac, NMDevice *device) gpointer data; NMSettingConnection *s_con; NMSettingWired *s_wired; + NMSettingInfiniband *s_infiniband; const GByteArray *setting_mac; gboolean ret = FALSE; @@ -1251,10 +1253,12 @@ have_connection_for_device (NMSettings *self, GByteArray *mac, NMDevice *device) } if ( strcmp (ctype, NM_SETTING_WIRED_SETTING_NAME) + && strcmp (ctype, NM_SETTING_INFINIBAND_SETTING_NAME) && strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) continue; s_wired = nm_connection_get_setting_wired (connection); + s_infiniband = nm_connection_get_setting_infiniband (connection); /* No wired setting; therefore the PPPoE connection applies to any device */ if (!s_wired && !strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) { @@ -1262,10 +1266,15 @@ have_connection_for_device (NMSettings *self, GByteArray *mac, NMDevice *device) break; } - setting_mac = nm_setting_wired_get_mac_address (s_wired); + g_assert (s_wired != NULL || s_infiniband != NULL); + + setting_mac = s_wired ? + nm_setting_wired_get_mac_address (s_wired) : + nm_setting_infiniband_get_mac_address (s_infiniband); if (setting_mac) { /* A connection mac-locked to this device */ - if (!memcmp (setting_mac->data, mac->data, ETH_ALEN)) { + if (mac->len == setting_mac->len && + !memcmp (setting_mac->data, mac->data, mac->len)) { ret = TRUE; break; } @@ -1281,7 +1290,7 @@ have_connection_for_device (NMSettings *self, GByteArray *mac, NMDevice *device) /* Search through the list of blacklisted MAC addresses in the config file. */ static gboolean -is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac) +is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac, int hwaddr_type) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GKeyFile *config; @@ -1305,15 +1314,15 @@ is_mac_auto_wired_blacklisted (NMSettings *self, const GByteArray *mac) list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, NULL, NULL); for (iter = list; iter && *iter; iter++) { - struct ether_addr *candidate; + guint8 *candidate, buffer[NM_UTILS_HWADDR_LEN_MAX]; - if (strcmp(g_strstrip(*iter), "*") == 0) { + if (strcmp (g_strstrip (*iter), "*") == 0) { found = TRUE; break; } - candidate = ether_aton (*iter); - if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) { + candidate = nm_utils_hwaddr_aton (*iter, hwaddr_type, buffer); + if (candidate && !memcmp (mac->data, candidate, mac->len)) { found = TRUE; break; } @@ -1336,6 +1345,7 @@ default_wired_deleted (NMDefaultWiredConnection *wired, { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMSettingConnection *s_con; + int hwaddr_type; char *tmp; GKeyFile *config; char **list, **iter, **updated; @@ -1367,20 +1377,27 @@ default_wired_deleted (NMDefaultWiredConnection *wired, if (!config) goto cleanup; + if (nm_connection_get_setting_wired (NM_CONNECTION (wired))) + hwaddr_type = ARPHRD_ETHER; + else if (nm_connection_get_setting_infiniband (NM_CONNECTION (wired))) + hwaddr_type = ARPHRD_INFINIBAND; + else + goto cleanup; + g_key_file_set_list_separator (config, ','); g_key_file_load_from_file (config, priv->config_file, G_KEY_FILE_KEEP_COMMENTS, NULL); list = g_key_file_get_string_list (config, "main", CONFIG_KEY_NO_AUTO_DEFAULT, &len, NULL); for (iter = list; iter && *iter; iter++) { - struct ether_addr *candidate; + guint8 *candidate, buffer[NM_UTILS_HWADDR_LEN_MAX]; - if (strcmp(g_strstrip(*iter), "*") == 0) { + if (strcmp (g_strstrip (*iter), "*") == 0) { found = TRUE; break; } - candidate = ether_aton (*iter); - if (candidate && !memcmp (mac->data, candidate->ether_addr_octet, ETH_ALEN)) { + candidate = nm_utils_hwaddr_aton (*iter, hwaddr_type, buffer); + if (candidate && !memcmp (mac->data, candidate, mac->len)) { found = TRUE; break; } @@ -1388,9 +1405,7 @@ default_wired_deleted (NMDefaultWiredConnection *wired, /* Add this device's MAC to the list */ if (!found) { - tmp = g_strdup_printf ("%02x:%02x:%02x:%02x:%02x:%02x", - mac->data[0], mac->data[1], mac->data[2], - mac->data[3], mac->data[4], mac->data[5]); + tmp = nm_utils_hwaddr_ntoa (mac->data, hwaddr_type); /* New list; size + 1 for the new element, + 1 again for ending NULL */ updated = g_malloc0 (sizeof (char*) * (len + 2)); @@ -1480,13 +1495,14 @@ nm_settings_device_added (NMSettings *self, NMDevice *device) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GByteArray *mac = NULL; - struct ether_addr tmp; + guint8 *hwaddr; + int hwaddr_type; NMDefaultWiredConnection *wired; gboolean read_only = TRUE; const char *id; char *defname; - if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET) + if (!NM_IS_DEVICE_WIRED (device)) return; /* If the device isn't managed or it already has a default wired connection, @@ -1496,13 +1512,14 @@ nm_settings_device_added (NMSettings *self, NMDevice *device) || g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG)) return; - nm_device_ethernet_get_address (NM_DEVICE_ETHERNET (device), &tmp); + hwaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)); + hwaddr_type = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (device)); - mac = g_byte_array_sized_new (ETH_ALEN); - g_byte_array_append (mac, tmp.ether_addr_octet, ETH_ALEN); + mac = g_byte_array_new (); + g_byte_array_append (mac, hwaddr, nm_utils_hwaddr_len (hwaddr_type)); if ( have_connection_for_device (self, mac, device) - || is_mac_auto_wired_blacklisted (self, mac)) + || is_mac_auto_wired_blacklisted (self, mac, hwaddr_type)) goto ignore; if (get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) @@ -1536,7 +1553,7 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device) { NMDefaultWiredConnection *connection; - if (nm_device_get_device_type (device) != NM_DEVICE_TYPE_ETHERNET) + if (!NM_IS_DEVICE_WIRED (device)) return; connection = (NMDefaultWiredConnection *) g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_TAG);