static gboolean hwaddr_matches (NMDevice *device, NMConnection *connection, const guint8 *other_hwaddr, guint other_hwaddr_len, gboolean fail_if_no_hwaddr) { NMSettingInfiniband *s_ib; const guint8 *devaddr; const GByteArray *mac = NULL; int devtype; devtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (device)); devaddr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)); g_return_val_if_fail (devaddr != NULL, FALSE); s_ib = nm_connection_get_setting_infiniband (connection); if (s_ib) mac = nm_setting_infiniband_get_mac_address (s_ib); if (mac) { g_return_val_if_fail (mac->len == INFINIBAND_ALEN, FALSE); if (other_hwaddr) { g_return_val_if_fail (other_hwaddr_len == INFINIBAND_ALEN, FALSE); if (memcmp (mac->data, other_hwaddr, mac->len) == 0) return TRUE; } else if (memcmp (mac->data, devaddr, mac->len) == 0) return TRUE; } else if (fail_if_no_hwaddr == FALSE) return TRUE; return FALSE; }
static void real_update_hw_address (NMDevice *dev) { const guint8 *hw_addr; guint8 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 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_get_state (NM_DEVICE (self)); if (state == NM_DEVICE_STATE_UNAVAILABLE) { if (priv->carrier) nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); else { /* clear any queued state changes if they wouldn't be valid when the * carrier is off. */ if (nm_device_queued_state_peek (NM_DEVICE (self)) >= NM_DEVICE_STATE_DISCONNECTED) nm_device_queued_state_clear (NM_DEVICE (self)); } } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { if (!priv->carrier) nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); } return FALSE; }
static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (object); GPtrArray *slaves; GSList *list, *iter; char *hwaddr; switch (prop_id) { case PROP_HW_ADDRESS: hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, nm_utils_hwaddr_type (priv->hw_addr_len)); g_value_take_string (value, hwaddr); break; case PROP_CARRIER: g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object))); break; case PROP_SLAVES: slaves = g_ptr_array_new (); list = nm_device_master_get_slaves (NM_DEVICE (object)); for (iter = list; iter; iter = iter->next) g_ptr_array_add (slaves, g_strdup (nm_device_get_path (NM_DEVICE (iter->data)))); g_slist_free (list); g_value_take_boxed (value, slaves); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean hw_bring_up (NMDevice *dev, gboolean *no_firmware) { gboolean success, carrier; guint32 caps; success = nm_system_iface_set_up (nm_device_get_ip_ifindex (dev), TRUE, no_firmware); if (success) { caps = nm_device_get_capabilities (dev); if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { carrier = get_carrier_sync (NM_DEVICE_WIRED (dev)); set_carrier (NM_DEVICE_WIRED (dev), carrier, carrier ? FALSE : TRUE); } } return success; }
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; caps = nm_device_get_capabilities (device); g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT); /* 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_get_state (device); if (state > NM_DEVICE_STATE_DISCONNECTED) defer = TRUE; set_carrier (self, FALSE, defer); } }
static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { const 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 gboolean 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 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 real_complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, const GSList *existing_connections, GError **error) { NMSettingInfiniband *s_infiniband; const GByteArray *setting_mac; const 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); } if (!nm_setting_infiniband_get_transport_mode (s_infiniband)) g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL); return TRUE; }
static gboolean 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 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 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)) { caps = nm_device_get_capabilities (device); g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT); set_carrier (self, TRUE, FALSE); set_speed (self, ethtool_get_speed (self)); } }
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) { const 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 void 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 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) { const 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 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 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 if (nm_device_get_device_type (self) == NM_DEVICE_TYPE_BOND) { /* We may not know the hardware address type until a slave is added */ priv->hw_addr_type = ARPHRD_ETHER; priv->hw_addr_len = ETH_ALEN; } else g_assert_not_reached (); caps = nm_device_get_capabilities (self); if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { /* 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); priv->carrier = get_carrier_sync (NM_DEVICE_WIRED (self)); 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. */ nm_netlink_monitor_request_status (priv->monitor); } 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; }