static void
add_pan_connection (NmaBtDevice *self)
{
	NmaBtDevicePrivate *priv = NMA_BT_DEVICE_GET_PRIVATE (self);
	NMConnection *connection;
	NMSetting *setting, *bt_setting, *ip_setting;
	char *id, *uuid;

	/* The connection */
	connection = nm_connection_new ();

	/* The connection settings */
	setting = nm_setting_connection_new ();
	id = g_strdup_printf (_("%s Network"), priv->alias ? priv->alias : priv->bdaddr);
	uuid = nm_utils_uuid_generate ();
	g_object_set (G_OBJECT (setting),
	              NM_SETTING_CONNECTION_ID, id,
	              NM_SETTING_CONNECTION_UUID, uuid,
	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_BLUETOOTH_SETTING_NAME,
	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
	              NULL);
	g_free (id);
	g_free (uuid);
	nm_setting_connection_add_permission ((NMSettingConnection *) setting, "user", g_get_user_name (), NULL);
	nm_connection_add_setting (connection, setting);

	/* The Bluetooth settings */
	bt_setting = nm_setting_bluetooth_new ();
	g_object_set (G_OBJECT (bt_setting),
	              NM_SETTING_BLUETOOTH_BDADDR, priv->bdaddr_array,
	              NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
	              NULL);
	nm_connection_add_setting (connection, bt_setting);

	/* IPv4 */
	ip_setting = nm_setting_ip4_config_new ();
	g_object_set (G_OBJECT (ip_setting),
	              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
	              NM_SETTING_IP4_CONFIG_MAY_FAIL, FALSE,
	              NULL);
	nm_connection_add_setting (connection, ip_setting);

	/* IPv6 */
	ip_setting = nm_setting_ip6_config_new ();
	g_object_set (G_OBJECT (ip_setting),
	              NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO,
	              NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE,
	              NULL);
	nm_connection_add_setting (connection, ip_setting);

	/* Add the connection to the settings service */
	nm_remote_settings_add_connection (priv->settings,
	                                   connection,
	                                   pan_add_cb,
	                                   self);
}
static void
wizard_done_cb (NMAMobileWizard *wizard,
                gboolean canceled,
                NMAMobileWizardAccessMethod *method,
                gpointer user_data)
{
	NmaBtDevice *self = NMA_BT_DEVICE (user_data);
	NmaBtDevicePrivate *priv = NMA_BT_DEVICE_GET_PRIVATE (self);
	NMConnection *connection = NULL;
	NMSetting *s_bt;

	g_return_if_fail (wizard == priv->wizard);

	g_message ("%s: mobile wizard done", __func__);

	if (canceled || !method) {
		dun_error (self, __func__, NULL, _("Mobile wizard was canceled"));
		return;
	}

	if (method->devtype == NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)
		connection = dun_new_cdma (method);
	else if (method->devtype == NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)
		connection = dun_new_gsm (method);
	else {
		dun_error (self, __func__, NULL, _("Unknown phone device type (not GSM or CDMA)"));
		return;
	}

	nma_mobile_wizard_destroy (priv->wizard);
	priv->wizard = NULL;

	g_assert (connection);

	/* The Bluetooth settings */
	s_bt = nm_setting_bluetooth_new ();
	g_object_set (G_OBJECT (s_bt),
	              NM_SETTING_BLUETOOTH_BDADDR, priv->bdaddr_array,
	              NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_DUN,
	              NULL);
	nm_connection_add_setting (connection, s_bt);

	g_message ("%s: adding new setting", __func__);

	/* Add the connection to the settings service */
	nm_remote_settings_add_connection (priv->settings,
	                                   connection,
	                                   dun_add_cb,
	                                   self);

	g_message ("%s: waiting for add connection result...", __func__);
}
CEPage *
ce_page_bluetooth_new (NMConnectionEditor *editor,
                       NMConnection *connection,
                       GtkWindow *parent_window,
                       NMClient *client,
                       const char **out_secrets_setting_name,
                       GError **error)
{
	CEPageBluetooth *self;
	CEPageBluetoothPrivate *priv;

	self = CE_PAGE_BLUETOOTH (ce_page_new (CE_TYPE_PAGE_BLUETOOTH,
	                          editor,
	                          connection,
	                          parent_window,
	                          client,
	                          UIDIR "/ce-page-bluetooth.ui",
	                          "BluetoothPage",
	                          _("Bluetooth")));
	if (!self) {
		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not load Bluetooth user interface."));
		return NULL;
	}

	bluetooth_private_init (self);
	priv = CE_PAGE_BLUETOOTH_GET_PRIVATE (self);

	priv->setting = nm_connection_get_setting_bluetooth (connection);
	if (!priv->setting) {
		priv->setting = NM_SETTING_BLUETOOTH (nm_setting_bluetooth_new ());
		nm_connection_add_setting (connection, NM_SETTING (priv->setting));
	}

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

	*out_secrets_setting_name = NM_SETTING_BLUETOOTH_SETTING_NAME;

	return CE_PAGE (self);
}
static void
pan_connection_check_create (NMBluezDevice *self)
{
	NMConnection *connection;
	NMConnection *added;
	NMSetting *setting;
	char *uuid, *id;
	GError *error = NULL;
	NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self);

	g_return_if_fail (priv->capabilities & NM_BT_CAPABILITY_NAP);
	g_return_if_fail (priv->connections == NULL);
	g_return_if_fail (priv->name);

	if (priv->pan_connection || priv->pan_connection_no_autocreate) {
		/* already have a connection or we don't want to create one, nothing to do. */
		return;
	}

	/* Only try once to create a connection. If it does not succeed, we do not try again. Also,
	 * if the connection gets deleted later, do not create another one for this device. */
	priv->pan_connection_no_autocreate = TRUE;

	/* create a new connection */

	connection = nm_simple_connection_new ();

	/* Setting: Connection */
	uuid = nm_utils_uuid_generate ();
	id = g_strdup_printf (_("%s Network"), priv->name);
	setting = nm_setting_connection_new ();
	g_object_set (setting,
	              NM_SETTING_CONNECTION_ID, id,
	              NM_SETTING_CONNECTION_UUID, uuid,
	              NM_SETTING_CONNECTION_AUTOCONNECT, FALSE,
	              NM_SETTING_CONNECTION_TYPE, NM_SETTING_BLUETOOTH_SETTING_NAME,
	              NULL);
	nm_connection_add_setting (connection, setting);

	/* Setting: Bluetooth */
	setting = nm_setting_bluetooth_new ();
	g_object_set (G_OBJECT (setting),
	              NM_SETTING_BLUETOOTH_BDADDR, priv->address,
	              NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
	              NULL);
	nm_connection_add_setting (connection, setting);

	/* Setting: IPv4 */
	setting = nm_setting_ip4_config_new ();
	g_object_set (G_OBJECT (setting),
	              NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO,
	              NM_SETTING_IP4_CONFIG_MAY_FAIL, FALSE,
	              NULL);
	nm_connection_add_setting (connection, setting);

	/* Setting: IPv6 */
	setting = nm_setting_ip6_config_new ();
	g_object_set (G_OBJECT (setting),
	              NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO,
	              NM_SETTING_IP6_CONFIG_MAY_FAIL, TRUE,
	              NULL);
	nm_connection_add_setting (connection, setting);

	/* Adding a new connection raises a signal which eventually calls check_emit_usable (again)
	 * which then already finds the suitable connection in priv->connections. This is confusing,
	 * so block the signal. check_emit_usable will succeed after this function call returns. */
	g_signal_handlers_block_by_func (priv->provider, cp_connection_added, self);
	added = nm_connection_provider_add_connection (priv->provider, connection, FALSE, &error);
	g_signal_handlers_unblock_by_func (priv->provider, cp_connection_added, self);

	if (added) {
		g_assert (!g_slist_find (priv->connections, added));
		g_assert (connection_compatible (self, added));
		g_assert (nm_connection_compare (added, connection, NM_SETTING_COMPARE_FLAG_EXACT));

		priv->connections = g_slist_prepend (priv->connections, g_object_ref (added));
		priv->pan_connection = added;
		priv->pan_connection_original = connection;
		nm_log_dbg (LOGD_BT, "bluez[%s] added new Bluetooth connection for NAP device: '%s' (%s)", priv->path, id, uuid);
	} else {
		nm_log_warn (LOGD_BT, "bluez[%s] couldn't add new Bluetooth connection for NAP device: '%s' (%s): %d / %s",
		             priv->path, id, uuid, error ? error->code : -1,
		             (error && error->message) ? error->message : "(unknown)");
		g_clear_error (&error);

		g_object_unref (connection);
	}

	g_free (id);
	g_free (uuid);
}
static gboolean
complete_connection (NMDevice *device,
                     NMConnection *connection,
                     const char *specific_object,
                     const GSList *existing_connections,
                     GError **error)
{
    NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device);
    NMSettingBluetooth *s_bt;
    const GByteArray *setting_bdaddr;
    struct ether_addr *devaddr = ether_aton (priv->bdaddr);
    const char *ctype;
    gboolean is_dun = FALSE, is_pan = FALSE;
    NMSettingGsm *s_gsm;
    NMSettingCdma *s_cdma;
    NMSettingSerial *s_serial;
    NMSettingPPP *s_ppp;
    const char *format = NULL, *preferred = NULL;

    s_gsm = nm_connection_get_setting_gsm (connection);
    s_cdma = nm_connection_get_setting_cdma (connection);
    s_serial = nm_connection_get_setting_serial (connection);
    s_ppp = nm_connection_get_setting_ppp (connection);

    s_bt = nm_connection_get_setting_bluetooth (connection);
    if (!s_bt) {
        s_bt = (NMSettingBluetooth *) nm_setting_bluetooth_new ();
        nm_connection_add_setting (connection, NM_SETTING (s_bt));
    }

    ctype = nm_setting_bluetooth_get_connection_type (s_bt);
    if (ctype) {
        if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_DUN))
            is_dun = TRUE;
        else if (!strcmp (ctype, NM_SETTING_BLUETOOTH_TYPE_PANU))
            is_pan = TRUE;
    } else {
        if (s_gsm || s_cdma)
            is_dun = TRUE;
        else if (priv->capabilities & NM_BT_CAPABILITY_NAP)
            is_pan = TRUE;
    }

    if (is_pan) {
        /* Make sure the device supports PAN */
        if (!(priv->capabilities & NM_BT_CAPABILITY_NAP)) {
            g_set_error_literal (error,
                                 NM_SETTING_BLUETOOTH_ERROR,
                                 NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
                                 "PAN required but Bluetooth device does not support NAP");
            return FALSE;
        }

        /* PAN can't use any DUN-related settings */
        if (s_gsm || s_cdma || s_serial || s_ppp) {
            g_set_error_literal (error,
                                 NM_SETTING_BLUETOOTH_ERROR,
                                 NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
                                 "PAN incompatible with GSM, CDMA, or serial settings");
            return FALSE;
        }

        g_object_set (G_OBJECT (s_bt),
                      NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU,
                      NULL);

        format = _("PAN connection %d");
    } else if (is_dun) {
        /* Make sure the device supports PAN */
        if (!(priv->capabilities & NM_BT_CAPABILITY_DUN)) {
            g_set_error_literal (error,
                                 NM_SETTING_BLUETOOTH_ERROR,
                                 NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
                                 "DUN required but Bluetooth device does not support DUN");
            return FALSE;
        }

        /* Need at least a GSM or a CDMA setting */
        if (!s_gsm && !s_cdma) {
            g_set_error_literal (error,
                                 NM_SETTING_BLUETOOTH_ERROR,
                                 NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
                                 "Setting requires DUN but no GSM or CDMA setting is present");
            return FALSE;
        }

        g_object_set (G_OBJECT (s_bt),
                      NM_SETTING_BLUETOOTH_TYPE, NM_SETTING_BLUETOOTH_TYPE_DUN,
                      NULL);

        if (s_gsm) {
            format = _("GSM connection %d");
            if (!nm_setting_gsm_get_number (s_gsm))
                g_object_set (G_OBJECT (s_gsm), NM_SETTING_GSM_NUMBER, "*99#", NULL);
        } else if (s_cdma) {
            format = _("CDMA connection %d");
            if (!nm_setting_cdma_get_number (s_cdma))
                g_object_set (G_OBJECT (s_cdma), NM_SETTING_GSM_NUMBER, "#777", NULL);
        } else
            format = _("DUN connection %d");
    } else {
        g_set_error_literal (error,
                             NM_SETTING_BLUETOOTH_ERROR,
                             NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
                             "Unknown/unhandled Bluetooth connection type");
        return FALSE;
    }

    nm_utils_complete_generic (connection,
                               NM_SETTING_BLUETOOTH_SETTING_NAME,
                               existing_connections,
                               format,
                               preferred,
                               is_dun ? FALSE : TRUE); /* No IPv6 yet for DUN */

    setting_bdaddr = nm_setting_bluetooth_get_bdaddr (s_bt);
    if (setting_bdaddr) {
        /* Make sure the setting BT Address (if any) matches the device's */
        if (memcmp (setting_bdaddr->data, devaddr->ether_addr_octet, ETH_ALEN)) {
            g_set_error_literal (error,
                                 NM_SETTING_BLUETOOTH_ERROR,
                                 NM_SETTING_BLUETOOTH_ERROR_INVALID_PROPERTY,
                                 NM_SETTING_BLUETOOTH_BDADDR);
            return FALSE;
        }
    } else {
        GByteArray *bdaddr;
        const guint8 null_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };

        /* Lock the connection to this device by default */
        if (memcmp (devaddr->ether_addr_octet, null_mac, ETH_ALEN)) {
            bdaddr = g_byte_array_sized_new (ETH_ALEN);
            g_byte_array_append (bdaddr, devaddr->ether_addr_octet, ETH_ALEN);
            g_object_set (G_OBJECT (s_bt), NM_SETTING_BLUETOOTH_BDADDR, bdaddr, NULL);
            g_byte_array_free (bdaddr, TRUE);
        }
    }

    return TRUE;
}
static void
new_connection_mobile_wizard_done (NMAMobileWizard *wizard,
                                   gboolean canceled,
                                   NMAMobileWizardAccessMethod *method,
                                   gpointer user_data)
{
	WizardInfo *info = user_data;
	NMConnection *connection = NULL;
	char *detail = NULL;
	NMSetting *type_setting = NULL;

	if (canceled)
		goto out;

	if (method) {
		switch (method->devtype) {
		case NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS:
			type_setting = nm_setting_gsm_new ();
			/* De-facto standard for GSM */
			g_object_set (type_setting,
			              NM_SETTING_GSM_NUMBER, "*99#",
			              NM_SETTING_GSM_USERNAME, method->username,
			              NM_SETTING_GSM_PASSWORD, method->password,
			              NM_SETTING_GSM_APN, method->gsm_apn,
			              NULL);
			break;
		case NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO:
			type_setting = nm_setting_cdma_new ();
			/* De-facto standard for CDMA */
			g_object_set (type_setting,
			              NM_SETTING_CDMA_NUMBER, "#777",
			              NM_SETTING_GSM_USERNAME, method->username,
			              NM_SETTING_GSM_PASSWORD, method->password,
			              NULL);
			break;
		default:
			g_assert_not_reached ();
			break;
		}

		if (method->plan_name)
			detail = g_strdup_printf ("%s %s %%d", method->provider_name, method->plan_name);
		else
			detail = g_strdup_printf ("%s connection %%d", method->provider_name);
	}

	if (!detail)
		detail = g_strdup (_("Bluetooth connection %d"));
	connection = ce_page_new_connection (detail,
	                                     NM_SETTING_BLUETOOTH_SETTING_NAME,
	                                     FALSE,
	                                     info->client,
	                                     user_data);
	g_free (detail);
	nm_connection_add_setting (connection, nm_setting_bluetooth_new ());
	g_object_set (nm_connection_get_setting_bluetooth (connection),
	              NM_SETTING_BLUETOOTH_TYPE, info->type, NULL);

	if (type_setting) {
		nm_connection_add_setting (connection, type_setting);
		nm_connection_add_setting (connection, nm_setting_ppp_new ());
	}

out:
	(*info->result_func) (connection, canceled, NULL, info->user_data);

	if (wizard)
		nma_mobile_wizard_destroy (wizard);

	g_object_unref (info->client);
	g_free (info);
}