static void
update_connection (NMDevice *device, NMConnection *connection)
{
	NMSettingInfiniband *s_infiniband = nm_connection_get_setting_infiniband (connection);
	const char *mac = nm_device_get_hw_address (device);
	char *mode_path, *contents = NULL;
	const char *transport_mode = "datagram";

	if (!s_infiniband) {
		s_infiniband = (NMSettingInfiniband *) nm_setting_infiniband_new ();
		nm_connection_add_setting (connection, (NMSetting *) s_infiniband);
	}

	if (mac && !nm_utils_hwaddr_matches (mac, -1, NULL, INFINIBAND_ALEN))
		g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL);

	mode_path = g_strdup_printf ("/sys/class/net/%s/mode",
	                             ASSERT_VALID_PATH_COMPONENT (nm_device_get_iface (device)));
	contents = nm_platform_sysctl_get (mode_path);
	g_free (mode_path);
	if (contents) {
		if (strstr (contents, "datagram"))
			transport_mode = "datagram";
		else if (strstr (contents, "connected"))
			transport_mode = "connected";
		g_free (contents);
	}
	g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, transport_mode, NULL);
}
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 gboolean
check_connection_compatible (NMDevice *device, NMConnection *connection)
{
	NMSettingInfiniband *s_infiniband;

	if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->check_connection_compatible (device, connection))
		return FALSE;

	if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME))
		return FALSE;

	s_infiniband = nm_connection_get_setting_infiniband (connection);
	if (!s_infiniband)
		return FALSE;

	if (s_infiniband) {
		const char *mac;

		mac = nm_setting_infiniband_get_mac_address (s_infiniband);
		if (mac && !nm_utils_hwaddr_matches (mac, -1, nm_device_get_hw_address (device), -1))
			return FALSE;
	}

	return TRUE;
}
static gboolean
connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
{
	NMSettingInfiniband *s_infiniband;
	const char *hwaddr, *setting_hwaddr;

	if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->connection_compatible (device, connection, error))
		return FALSE;

	if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
		g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
		                     _("The connection was not an InfiniBand connection."));
		return FALSE;
	}

	hwaddr = nm_device_infiniband_get_hw_address (NM_DEVICE_INFINIBAND (device));
	if (hwaddr) {
		if (!nm_utils_hwaddr_valid (hwaddr, INFINIBAND_ALEN)) {
			g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
			                     _("Invalid device MAC address."));
			return FALSE;
		}

		s_infiniband = nm_connection_get_setting_infiniband (connection);
		setting_hwaddr = nm_setting_infiniband_get_mac_address (s_infiniband);
		if (setting_hwaddr && !nm_utils_hwaddr_matches (setting_hwaddr, -1, hwaddr, -1)) {
			g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
			                     _("The MACs of the device and the connection didn't match."));
			return FALSE;
		}
	}

	return TRUE;
}
Exemple #5
0
/* return value must be freed by caller with g_free() */
static gchar *
get_mac_address_of_connection (NMConnection *connection)
{
  const GByteArray *mac = NULL;

  if (!connection)
    return NULL;

  /* check the connection type */
  if (nm_connection_is_type (connection,
                             NM_SETTING_WIRELESS_SETTING_NAME))
    {
      /* check wireless settings */
      NMSettingWireless *s_wireless = nm_connection_get_setting_wireless (connection);
      if (!s_wireless)
        return NULL;
      mac = nm_setting_wireless_get_mac_address (s_wireless);
      if (mac)
        return nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
    }
  else if (nm_connection_is_type (connection,
                                  NM_SETTING_WIRED_SETTING_NAME))
    {
      /* check wired settings */
      NMSettingWired *s_wired = nm_connection_get_setting_wired (connection);
      if (!s_wired)
        return NULL;
      mac = nm_setting_wired_get_mac_address (s_wired);
      if (mac)
        return nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
    }
  else if (nm_connection_is_type (connection,
                                  NM_SETTING_WIMAX_SETTING_NAME))
    {
      /* check wimax settings */
      NMSettingWimax *s_wimax = nm_connection_get_setting_wimax (connection);
      if (!s_wimax)
        return NULL;
      mac = nm_setting_wimax_get_mac_address (s_wimax);
      if (mac)
        return nm_utils_hwaddr_ntoa (mac->data, ARPHRD_ETHER);
    }
  else if (nm_connection_is_type (connection,
                                  NM_SETTING_INFINIBAND_SETTING_NAME))
    {
      /* check infiniband settings */
      NMSettingInfiniband *s_infiniband = \
        nm_connection_get_setting_infiniband (connection);
      if (!s_infiniband)
        return NULL;
      mac = nm_setting_infiniband_get_mac_address (s_infiniband);
      if (mac)
        return nm_utils_hwaddr_ntoa (mac->data,
                                     ARPHRD_INFINIBAND);
    }
  /* no MAC address found */
  return NULL;
}
static const GByteArray *
get_connection_hw_address (NMDevice *device,
                           NMConnection *connection)
{
	NMSettingInfiniband *s_ib;

	s_ib = nm_connection_get_setting_infiniband (connection);
	return s_ib ? nm_setting_infiniband_get_mac_address (s_ib) : NULL;
}
static void
nmt_page_infiniband_constructed (GObject *object)
{
    NmtPageInfiniband *infiniband = NMT_PAGE_INFINIBAND (object);
    NmtDeviceEntry *deventry;
    NmtPageGrid *grid;
    NMSettingInfiniband *s_ib;
    NmtNewtWidget *widget;
    NMConnection *conn;

    conn = nmt_editor_page_get_connection (NMT_EDITOR_PAGE (infiniband));
    s_ib = nm_connection_get_setting_infiniband (conn);
    if (!s_ib) {
        nm_connection_add_setting (conn, nm_setting_infiniband_new ());
        s_ib = nm_connection_get_setting_infiniband (conn);
    }
    /* initialize 'transport-mode' if it is NULL */
    if (!nm_setting_infiniband_get_transport_mode (s_ib)) {
        g_object_set (G_OBJECT (s_ib),
                      NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram",
                      NULL);
    }

    deventry = nmt_page_device_get_device_entry (NMT_PAGE_DEVICE (object));
    g_object_bind_property (s_ib, NM_SETTING_INFINIBAND_MAC_ADDRESS,
                            deventry, "mac-address",
                            G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);

    grid = NMT_PAGE_GRID (infiniband);

    widget = nmt_newt_popup_new (transport_mode);
    g_object_bind_property (s_ib, NM_SETTING_INFINIBAND_TRANSPORT_MODE,
                            widget, "active-id",
                            G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
    nmt_page_grid_append (grid, _("Transport mode"), widget, NULL);

    widget = nmt_mtu_entry_new ();
    g_object_bind_property (s_ib, NM_SETTING_INFINIBAND_MTU,
                            widget, "mtu",
                            G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
    nmt_page_grid_append (grid, _("MTU"), widget, NULL);

    G_OBJECT_CLASS (nmt_page_infiniband_parent_class)->constructed (object);
}
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
	NMActStageReturn ret;
	NMActRequest *req;
	NMConnection *connection;
	NMSettingInfiniband *s_infiniband;
	const char *transport_mode;
	char *mode_path;
	gboolean ok;

	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);

	ret = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason);
	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
		return ret;

	req = nm_device_get_act_request (dev);
	g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);

	connection = nm_act_request_get_connection (req);
	g_assert (connection);
	s_infiniband = nm_connection_get_setting_infiniband (connection);
	g_assert (s_infiniband);

	transport_mode = nm_setting_infiniband_get_transport_mode (s_infiniband);

	mode_path = g_strdup_printf ("/sys/class/net/%s/mode",
	                             ASSERT_VALID_PATH_COMPONENT (nm_device_get_iface (dev)));
	if (!g_file_test (mode_path, G_FILE_TEST_EXISTS)) {
		g_free (mode_path);

		if (!strcmp (transport_mode, "datagram"))
			return NM_ACT_STAGE_RETURN_SUCCESS;
		else {
			*reason = NM_DEVICE_STATE_REASON_INFINIBAND_MODE;
			return NM_ACT_STAGE_RETURN_FAILURE;
		}
	}

	ok = nm_platform_sysctl_set (mode_path, transport_mode);
	g_free (mode_path);

	if (!ok) {
		*reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
		return NM_ACT_STAGE_RETURN_FAILURE;
	}

	return NM_ACT_STAGE_RETURN_SUCCESS;
}
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
complete_connection (NMDevice *device,
                     NMConnection *connection,
                     const char *specific_object,
                     const GSList *existing_connections,
                     GError **error)
{
	NMSettingInfiniband *s_infiniband;
	const char *setting_mac;
	const char *hw_address;

	nm_utils_complete_generic (connection,
	                           NM_SETTING_INFINIBAND_SETTING_NAME,
	                           existing_connections,
	                           NULL,
	                           _("InfiniBand connection"),
	                           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));
	}

	setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
	hw_address = nm_device_get_hw_address (device);
	if (setting_mac) {
		/* Make sure the setting MAC (if any) matches the device's MAC */
		if (!nm_utils_hwaddr_matches (setting_mac, -1, hw_address, -1)) {
			g_set_error_literal (error,
			                     NM_CONNECTION_ERROR,
			                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
			                     _("connection does not match device"));
			g_prefix_error (error, "%s.%s: ", NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_MAC_ADDRESS);
			return FALSE;
		}
	} else {
		/* Lock the connection to this device by default */
		g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_MAC_ADDRESS, hw_address, NULL);
	}

	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
connection_compatible (NMDevice *device, NMConnection *connection, GError **error)
{
	NMSettingConnection *s_con;
	NMSettingInfiniband *s_infiniband;
	const char *ctype, *hwaddr_str;
	const GByteArray *mac;
	guint8 *hwaddr, hwaddr_buf[INFINIBAND_ALEN];

	s_con = nm_connection_get_setting_connection (connection);
	g_assert (s_con);

	ctype = nm_setting_connection_get_connection_type (s_con);
	if (strcmp (ctype, NM_SETTING_INFINIBAND_SETTING_NAME) != 0) {
		g_set_error (error, NM_DEVICE_INFINIBAND_ERROR, NM_DEVICE_INFINIBAND_ERROR_NOT_INFINIBAND_CONNECTION,
		             "The connection was not a InfiniBand connection.");
		return FALSE;
	}

	s_infiniband = nm_connection_get_setting_infiniband (connection);
	if (!s_infiniband) {
		g_set_error (error, NM_DEVICE_INFINIBAND_ERROR, NM_DEVICE_INFINIBAND_ERROR_INVALID_INFINIBAND_CONNECTION,
		             "The connection was not a valid InfiniBand connection.");
		return FALSE;
	}

	hwaddr_str = nm_device_infiniband_get_hw_address (NM_DEVICE_INFINIBAND (device));
	if (hwaddr_str) {
		hwaddr = nm_utils_hwaddr_aton (hwaddr_str, ARPHRD_INFINIBAND, hwaddr_buf);
		if (!hwaddr) {
			g_set_error (error, NM_DEVICE_INFINIBAND_ERROR, NM_DEVICE_INFINIBAND_ERROR_INVALID_DEVICE_MAC,
			             "Invalid device MAC address.");
			return FALSE;
		}
		mac = nm_setting_infiniband_get_mac_address (s_infiniband);

		/* We only match against the last 8 bytes */
		if (mac && hwaddr && memcmp (mac->data + INFINIBAND_ALEN - 8, hwaddr + INFINIBAND_ALEN - 8, 8)) {
			g_set_error (error, NM_DEVICE_INFINIBAND_ERROR, NM_DEVICE_INFINIBAND_ERROR_MAC_MISMATCH,
			             "The MACs of the device and the connection didn't match.");
			return FALSE;
		}
	}

	return NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->connection_compatible (device, connection, error);
}
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
real_ip4_config_pre_commit (NMDevice *self, NMIP4Config *config)
{
	NMConnection *connection;
	NMSettingInfiniband *s_infiniband;
	guint32 mtu;

	connection = nm_device_get_connection (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
check_connection_compatible (NMDevice *device,
                             NMConnection *connection,
                             GError **error)
{
	NMSettingInfiniband *s_infiniband;
	const GByteArray *mac;

	if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->check_connection_compatible (device, connection, error))
		return FALSE;

	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) {
		mac = nm_setting_infiniband_get_mac_address (s_infiniband);
		if (mac && memcmp (mac->data, nm_device_get_hw_address (device, NULL), 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_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 NMDevice *
create_virtual_device_for_connection (NMDeviceFactory *factory,
                                      NMConnection *connection,
                                      NMDevice *parent,
                                      GError **error)
{
	NMSettingInfiniband *s_infiniband;
	int p_key, parent_ifindex;
	const char *iface;

	if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME))
		return NULL;

	g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (parent), NULL);

	s_infiniband = nm_connection_get_setting_infiniband (connection);

	iface = nm_setting_infiniband_get_virtual_interface_name (s_infiniband);
	g_return_val_if_fail (iface != NULL, NULL);

	parent_ifindex = nm_device_get_ifindex (parent);
	p_key = nm_setting_infiniband_get_p_key (s_infiniband);

	if (   !nm_platform_infiniband_partition_add (parent_ifindex, p_key)
	    && nm_platform_get_error () != NM_PLATFORM_ERROR_EXISTS) {
		nm_log_warn (LOGD_DEVICE | LOGD_INFINIBAND, "(%s): failed to add InfiniBand P_Key interface for '%s': %s",
		             iface, nm_connection_get_id (connection),
		             nm_platform_get_error_msg ());
		return NULL;
	}

	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND,
	                                  NM_DEVICE_IFACE, iface,
	                                  NM_DEVICE_DRIVER, nm_device_get_driver (parent),
	                                  NM_DEVICE_TYPE_DESC, "InfiniBand",
	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND,
	                                  NULL);
}
CEPage *
ce_page_infiniband_new (NMConnection *connection,
                        GtkWindow *parent_window,
                        NMClient *client,
                        NMRemoteSettings *settings,
                        const char **out_secrets_setting_name,
                        GError **error)
{
	CEPageInfiniband *self;
	CEPageInfinibandPrivate *priv;

	self = CE_PAGE_INFINIBAND (ce_page_new (CE_TYPE_PAGE_INFINIBAND,
	                                        connection,
	                                        parent_window,
	                                        client,
	                                        settings,
	                                        UIDIR "/ce-page-infiniband.ui",
	                                        "InfinibandPage",
	                                        _("InfiniBand")));
	if (!self) {
		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC,
		                     _("Could not load InfiniBand user interface."));
		return NULL;
	}

	infiniband_private_init (self);
	priv = CE_PAGE_INFINIBAND_GET_PRIVATE (self);

	priv->setting = nm_connection_get_setting_infiniband (connection);
	if (!priv->setting) {
		priv->setting = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ());
		nm_connection_add_setting (connection, NM_SETTING (priv->setting));
	}

	g_signal_connect (self, "initialized", G_CALLBACK (finish_setup), NULL);

	return CE_PAGE (self);
}
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 gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
	NMSettingBondPrivate *priv = NM_SETTING_BOND_GET_PRIVATE (setting);
	GHashTableIter iter;
	const char *key, *value;
	int mode, miimon = 0, arp_interval = 0;
	int num_grat_arp = -1, num_unsol_na = -1;
	const char *mode_orig, *mode_new;
	const char *arp_ip_target = NULL;
	const char *lacp_rate;
	const char *primary;

	g_hash_table_iter_init (&iter, priv->options);
	while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) {
		if (!value[0] || !nm_setting_bond_validate_option (key, value)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("invalid option '%s' or its value '%s'"),
			             key, value);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	}

	value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_MIIMON);
	if (value)
		miimon = atoi (value);
	value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
	if (value)
		arp_interval = atoi (value);
	value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_NUM_GRAT_ARP);
	if (value)
		num_grat_arp = atoi (value);
	value = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_NUM_UNSOL_NA);
	if (value)
		num_unsol_na = atoi (value);

	/* Can only set one of miimon and arp_interval */
	if (miimon > 0 && arp_interval > 0) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("only one of '%s' and '%s' can be set"),
		             NM_SETTING_BOND_OPTION_MIIMON,
		             NM_SETTING_BOND_OPTION_ARP_INTERVAL);
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return FALSE;
	}

	/* Verify bond mode */
	mode_orig = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_MODE);
	if (!mode_orig) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("mandatory option '%s' is missing"),
		             NM_SETTING_BOND_OPTION_MODE);
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return FALSE;
	}
	mode = nm_utils_bond_mode_string_to_int (mode_orig);
	if (mode == -1) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%s' is not a valid value for '%s'"),
		             value, NM_SETTING_BOND_OPTION_MODE);
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return FALSE;
	}
	mode_new = nm_utils_bond_mode_int_to_string (mode);

	/* Make sure mode is compatible with other settings */
	if (   strcmp (mode_new, "balance-alb") == 0
	    || strcmp (mode_new, "balance-tlb") == 0) {
		if (arp_interval > 0) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s=%s' is incompatible with '%s > 0'"),
			             NM_SETTING_BOND_OPTION_MODE, mode_new, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	}

	primary = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_PRIMARY);
	if (strcmp (mode_new, "active-backup") == 0) {
		if (primary && !nm_utils_iface_valid_name (primary)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s' is not a valid interface name for '%s' option"),
			             primary, NM_SETTING_BOND_OPTION_PRIMARY);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	} else {
		if (primary) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s' option is only valid for '%s=%s'"),
			             NM_SETTING_BOND_OPTION_PRIMARY,
			             NM_SETTING_BOND_OPTION_MODE, "active-backup");
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	}

	if (nm_connection_get_setting_infiniband (connection)) {
		if (strcmp (mode_new, "active-backup") != 0) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s=%s' is not a valid configuration for '%s'"),
			             NM_SETTING_BOND_OPTION_MODE, mode_new, NM_SETTING_INFINIBAND_SETTING_NAME);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	}

	if (miimon == 0) {
		/* updelay and downdelay can only be used with miimon */
		if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_UPDELAY)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s' option requires '%s' option to be set"),
			             NM_SETTING_BOND_OPTION_UPDELAY, NM_SETTING_BOND_OPTION_MIIMON);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
		if (g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_DOWNDELAY)) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s' option requires '%s' option to be set"),
			             NM_SETTING_BOND_OPTION_DOWNDELAY, NM_SETTING_BOND_OPTION_MIIMON);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	}

	/* arp_ip_target can only be used with arp_interval, and must
	 * contain a comma-separated list of IPv4 addresses.
	 */
	arp_ip_target = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
	if (arp_interval > 0) {
		char **addrs;
		guint32 addr;
		int i;

		if (!arp_ip_target) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s' option requires '%s' option to be set"),
			             NM_SETTING_BOND_OPTION_ARP_INTERVAL, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}

		addrs = g_strsplit (arp_ip_target, ",", -1);
		if (!addrs[0]) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s' option is empty"),
			             NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			g_strfreev (addrs);
			return FALSE;
		}

		for (i = 0; addrs[i]; i++) {
			if (!inet_pton (AF_INET, addrs[i], &addr)) {
				g_set_error (error,
				             NM_CONNECTION_ERROR,
				             NM_CONNECTION_ERROR_INVALID_PROPERTY,
				             _("'%s' is not a valid IPv4 address for '%s' option"),
				             NM_SETTING_BOND_OPTION_ARP_IP_TARGET, addrs[i]);
				g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
				g_strfreev (addrs);
				return FALSE;
			}
		}
		g_strfreev (addrs);
	} else {
		if (arp_ip_target) {
			g_set_error (error,
			             NM_CONNECTION_ERROR,
			             NM_CONNECTION_ERROR_INVALID_PROPERTY,
			             _("'%s' option requires '%s' option to be set"),
			             NM_SETTING_BOND_OPTION_ARP_IP_TARGET, NM_SETTING_BOND_OPTION_ARP_INTERVAL);
			g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
			return FALSE;
		}
	}

	lacp_rate = g_hash_table_lookup (priv->options, NM_SETTING_BOND_OPTION_LACP_RATE);
	if (   lacp_rate
	    && g_strcmp0 (mode_new, "802.3ad")
	    && strcmp (lacp_rate, "slow") != 0
	    && strcmp (lacp_rate, "0") != 0) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%s' option is only valid with mode '%s'"),
		             NM_SETTING_BOND_OPTION_LACP_RATE, "802.3ad");
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return FALSE;
	}

	if (   (num_grat_arp != -1 && num_unsol_na != -1)
	    && (num_grat_arp != num_unsol_na)) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%s' and '%s' cannot have different values"),
		             NM_SETTING_BOND_OPTION_NUM_GRAT_ARP,
		             NM_SETTING_BOND_OPTION_NUM_UNSOL_NA);
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return FALSE;
	}

	if (!_nm_connection_verify_required_interface_name (connection, error))
		return FALSE;

	/* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */

	if (g_strcmp0 (mode_orig, mode_new) != 0) {
		g_set_error (error,
		             NM_CONNECTION_ERROR,
		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
		             _("'%s' option should be string"),
		             NM_SETTING_BOND_OPTION_MODE);
		g_prefix_error (error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, NM_SETTING_BOND_OPTIONS);
		return NM_SETTING_VERIFY_NORMALIZABLE;
	}

	return TRUE;
}