/**
 * nm_device_modem_get_current_capabilities:
 * @self: a #NMDeviceModem
 *
 * Returns a bitfield of the generic access technology families the modem
 * supports without a firmware reload or reinitialization.  This value
 * represents the network types the modem can immediately connect to.
 *
 * Returns: the generic access technology families the modem supports without
 * a firmware reload or other reinitialization
 **/
NMDeviceModemCapabilities
nm_device_modem_get_current_capabilities (NMDeviceModem *self)
{
	g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NM_DEVICE_MODEM_CAPABILITY_NONE);

	return NM_DEVICE_MODEM_GET_PRIVATE (self)->current_caps;
}
static void
real_connection_secrets_updated (NMDevice *device,
								 NMConnection *connection,
								 GSList *updated_settings,
								 RequestSecretsCaller caller)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);
	NMActRequest *req;

	g_return_if_fail (IS_ACTIVATING_STATE (nm_device_get_state (device)));

	req = nm_device_get_act_request (device);
	g_assert (req);

	if (!nm_modem_connection_secrets_updated (priv->modem,
                                              req,
                                              connection,
                                              updated_settings,
                                              caller)) {
		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS);
		return;
	}

	/* PPP handles stuff itself... */
	if (caller == SECRETS_CALLER_PPP)
		return;

	/* Otherwise, on success for modem secrets we need to schedule stage1 again */
	g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH);
	nm_device_activate_schedule_stage1_device_prepare (device);
}
/**
 * nm_device_modem_get_modem_capabilities:
 * @self: a #NMDeviceModem
 *
 * Returns a bitfield of the generic access technology families the modem
 * supports.  Not all capabilities are available concurrently however; some
 * may require a firmware reload or reinitialization.
 *
 * Returns: the generic access technology families the modem supports
 **/
NMDeviceModemCapabilities
nm_device_modem_get_modem_capabilities (NMDeviceModem *self)
{
	g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NM_DEVICE_MODEM_CAPABILITY_NONE);

	_nm_object_ensure_inited (NM_OBJECT (self));
	return NM_DEVICE_MODEM_GET_PRIVATE (self)->caps;
}
static NMActStageReturn
real_act_stage3_ip4_config_start (NMDevice *device, NMDeviceStateReason *reason)
{
	return nm_modem_stage3_ip4_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem,
	                                         device,
	                                         NM_DEVICE_CLASS (nm_device_modem_parent_class),
	                                         reason);
}
NMModem *
nm_device_modem_get_modem (NMDeviceModem *self)
{
	g_return_val_if_fail (self != NULL, NULL);
	g_return_val_if_fail (NM_IS_DEVICE_MODEM (self), NULL);

	return NM_DEVICE_MODEM_GET_PRIVATE (self)->modem;
}
static void
dispose (GObject *object)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);

	g_clear_object (&priv->proxy);

	G_OBJECT_CLASS (nm_device_modem_parent_class)->dispose (object);
}
static gboolean
real_check_connection_compatible (NMDevice *device,
                                  NMConnection *connection,
                                  GError **error)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);

	return nm_modem_check_connection_compatible (priv->modem, connection, error);
}
static NMConnection *
real_get_best_auto_connection (NMDevice *device,
							   GSList *connections,
							   char **specific_object)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);

	return nm_modem_get_best_auto_connection (priv->modem, connections, specific_object);
}
static void
finalize (GObject *object)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);

	g_object_unref (priv->modem);
	priv->modem = NULL;

	G_OBJECT_CLASS (nm_device_modem_parent_class)->finalize (object);
}
static void
constructed (GObject *object)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);

	G_OBJECT_CLASS (nm_device_modem_parent_class)->constructed (object);

	priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_MODEM);
	register_properties (NM_DEVICE_MODEM (object));
}
static void
modem_enabled_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data)
{
	NMDeviceModem *self = NM_DEVICE_MODEM (user_data);
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self);

	real_set_enabled (NM_DEVICE (self), nm_modem_get_mm_enabled (priv->modem));

	g_signal_emit (G_OBJECT (self), signals[ENABLE_CHANGED], 0);
}
static NMActStageReturn
real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
{
	NMActRequest *req;

	req = nm_device_get_act_request (device);
	g_assert (req);

	return nm_modem_act_stage2_config (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, req, reason);
}
static gboolean
real_complete_connection (NMDevice *device,
                          NMConnection *connection,
                          const char *specific_object,
                          const GSList *existing_connections,
                          GError **error)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);

	return nm_modem_complete_connection (priv->modem, connection, existing_connections, error);
}
static void
device_state_changed (NMDevice *device,
                      NMDeviceState new_state,
                      NMDeviceState old_state,
                      NMDeviceStateReason reason,
                      gpointer user_data)
{
	nm_modem_device_state_changed (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem,
	                               new_state,
	                               old_state,
	                               reason);
}
static void
register_properties (NMDeviceModem *device)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device);
	const NMPropertiesInfo property_info[] = {
		{ NM_DEVICE_MODEM_MODEM_CAPABILITIES,   &priv->caps },
		{ NM_DEVICE_MODEM_CURRENT_CAPABILITIES, &priv->current_caps },
		{ NULL },
	};

	_nm_object_register_properties (NM_OBJECT (device),
	                                priv->proxy,
	                                property_info);
}
static void
get_property (GObject *object, guint prop_id,
			  GValue *value, GParamSpec *pspec)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);

	switch (prop_id) {
	case PROP_MODEM:
		g_value_set_object (value, priv->modem);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}
static void
set_modem (NMDeviceModem *self, NMModem *modem)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self);

	g_return_if_fail (modem != NULL);

	priv->modem = g_object_ref (modem);

	g_signal_connect (modem, NM_MODEM_PPP_FAILED, G_CALLBACK (ppp_failed), self);
	g_signal_connect (modem, NM_MODEM_PREPARE_RESULT, G_CALLBACK (modem_prepare_result), self);
	g_signal_connect (modem, NM_MODEM_IP4_CONFIG_RESULT, G_CALLBACK (modem_ip4_config_result), self);
	g_signal_connect (modem, NM_MODEM_AUTH_REQUESTED, G_CALLBACK (modem_auth_requested), self);
	g_signal_connect (modem, NM_MODEM_AUTH_RESULT, G_CALLBACK (modem_auth_result), self);
	g_signal_connect (modem, "notify::" NM_MODEM_ENABLED, G_CALLBACK (modem_enabled_cb), self);
}
static void
init_dbus (NMObject *object)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);
	const NMPropertiesInfo property_info[] = {
		{ NM_DEVICE_MODEM_MODEM_CAPABILITIES,   &priv->caps },
		{ NM_DEVICE_MODEM_CURRENT_CAPABILITIES, &priv->current_caps },
		{ NULL },
	};

	NM_OBJECT_CLASS (nm_device_modem_parent_class)->init_dbus (object);

	_nm_object_register_properties (object,
	                                NM_DBUS_INTERFACE_DEVICE_MODEM,
	                                property_info);
}
static void
constructed (GObject *object)
{
	NMDeviceModemPrivate *priv;

	G_OBJECT_CLASS (nm_device_modem_parent_class)->constructed (object);

	priv = NM_DEVICE_MODEM_GET_PRIVATE (object);

	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
	                                         NM_DBUS_SERVICE,
	                                         nm_object_get_path (NM_OBJECT (object)),
	                                         NM_DBUS_INTERFACE_DEVICE_MODEM);

	register_properties (NM_DEVICE_MODEM (object));
}
static void
real_set_enabled (NMDevice *device, gboolean enabled)
{
	NMDeviceModem *self = NM_DEVICE_MODEM (device);
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self);
	NMDeviceState state;

	if (priv->modem) {
		nm_modem_set_mm_enabled (priv->modem, enabled);

		if (enabled == FALSE) {
			state = nm_device_get_state (NM_DEVICE (device));
			if (state == NM_DEVICE_STATE_ACTIVATED) {
				nm_device_state_changed (NM_DEVICE (device),
				                         NM_DEVICE_STATE_DISCONNECTED,
				                         NM_DEVICE_STATE_REASON_NONE);
			}
		}
	}
}
static void
set_property (GObject *object, guint prop_id,
			  const GValue *value, GParamSpec *pspec)
{
	NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (object);

	switch (prop_id) {
	case PROP_MODEM:
		/* construct-only */
		set_modem (NM_DEVICE_MODEM (object), g_value_get_object (value));
		break;
	case PROP_CAPABILITIES:
		priv->caps = g_value_get_uint (value);
		break;
	case PROP_CURRENT_CAPABILITIES:
		priv->current_caps = g_value_get_uint (value);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}
static gboolean
real_hw_bring_up (NMDevice *device, gboolean *no_firmware)
{
	return nm_modem_hw_bring_up (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device, no_firmware);
}
static gboolean
real_hw_is_up (NMDevice *device)
{
	return nm_modem_hw_is_up (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device);
}
static void
real_deactivate (NMDevice *device)
{
	nm_modem_deactivate (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device);
}
static gboolean
real_get_enabled (NMDevice *device)
{
	return nm_modem_get_mm_enabled (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem);
}