NetworkManager/src/modem-manager/nm-modem.c
Dan Williams 9d50e9dbd9 mobile: fix removal of ethernet interfaces owned by modems
If the kernel doesn't tag a modem's ethernet interface with
DEVTYPE=wwan then NetworkManager has no idea that's a modem
(and cannot be used until connected via the control port).
Since DEVTYPE=wwan devices get ignored by NM, so should these
interfaces when NM knows they are modems.

That got broken at some point for ModemManager1, because the
data port isn't read until the modem is connected.  NM only
looked for and removed the data-port-as-ethernet-device when
the modem was added, long before the MM1 data port was found.

ModemManager does provide a list of ports owned by the modem
though, which we can use at modem addition time to remove
an ethernet device that is controled by the modem.
2014-02-21 09:45:06 -06:00

994 lines
28 KiB
C

/* -*- 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) 2009 - 2011 Red Hat, Inc.
* Copyright (C) 2009 Novell, Inc.
*/
#include <string.h>
#include "nm-modem.h"
#include "nm-platform.h"
#include "nm-dbus-manager.h"
#include "nm-setting-connection.h"
#include "nm-properties-changed-signal.h"
#include "nm-logging.h"
#include "NetworkManagerUtils.h"
#include "nm-device-private.h"
#include "nm-dbus-glib-types.h"
#include "nm-enum-types.h"
G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT)
#define NM_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MODEM, NMModemPrivate))
enum {
PROP_0,
PROP_CONTROL_PORT,
PROP_DATA_PORT,
PROP_PATH,
PROP_UID,
PROP_DRIVER,
PROP_IP_METHOD,
PROP_IP_TIMEOUT,
PROP_ENABLED,
PROP_CONNECTED,
LAST_PROP
};
typedef struct {
char *uid;
char *path;
char *driver;
char *control_port;
char *data_port;
char *ppp_iface;
guint32 ip_method;
NMPPPManager *ppp_manager;
NMActRequest *act_request;
guint32 secrets_tries;
guint32 secrets_id;
gboolean mm_enabled;
guint32 mm_ip_timeout;
gboolean mm_connected;
/* PPP stats */
guint32 in_bytes;
guint32 out_bytes;
} NMModemPrivate;
enum {
PPP_STATS,
PPP_FAILED,
PREPARE_RESULT,
IP4_CONFIG_RESULT,
AUTH_REQUESTED,
AUTH_RESULT,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/*****************************************************************************/
GQuark
nm_modem_error_quark (void)
{
static GQuark quark = 0;
if (!quark)
quark = g_quark_from_static_string ("nm-modem-error");
return quark;
}
/*****************************************************************************/
/* Get/Set enabled/connected */
gboolean
nm_modem_get_mm_enabled (NMModem *self)
{
return NM_MODEM_GET_PRIVATE (self)->mm_enabled;
}
void
nm_modem_set_mm_enabled (NMModem *self,
gboolean enabled)
{
NMModemPrivate *priv;
priv = NM_MODEM_GET_PRIVATE (self);
if (priv->mm_enabled != enabled)
NM_MODEM_GET_CLASS (self)->set_mm_enabled (self, enabled);
}
gboolean
nm_modem_get_mm_connected (NMModem *self)
{
return NM_MODEM_GET_PRIVATE (self)->mm_connected;
}
/*****************************************************************************/
/* IP method PPP */
static void
ppp_state_changed (NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data)
{
switch (status) {
case NM_PPP_STATUS_DISCONNECT:
g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_DISCONNECT);
break;
case NM_PPP_STATUS_DEAD:
g_signal_emit (NM_MODEM (user_data), signals[PPP_FAILED], 0, NM_DEVICE_STATE_REASON_PPP_FAILED);
break;
default:
break;
}
}
static void
ppp_ip4_config (NMPPPManager *ppp_manager,
const char *iface,
NMIP4Config *config,
gpointer user_data)
{
NMModem *self = NM_MODEM (user_data);
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
guint32 i, num;
guint32 bad_dns1 = htonl (0x0A0B0C0D);
guint32 good_dns1 = htonl (0x04020201); /* GTE nameserver */
guint32 bad_dns2 = htonl (0x0A0B0C0E);
guint32 good_dns2 = htonl (0x04020202); /* GTE nameserver */
gboolean dns_workaround = FALSE;
/* Notify about the new data port to use */
g_free (priv->ppp_iface);
priv->ppp_iface = g_strdup (iface);
g_object_notify (G_OBJECT (self), NM_MODEM_DATA_PORT);
/* Work around a PPP bug (#1732) which causes many mobile broadband
* providers to return 10.11.12.13 and 10.11.12.14 for the DNS servers.
* Apparently fixed in ppp-2.4.5 but we've had some reports that this is
* not the case.
*
* http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=2e09ef6886bbf00bc5a9a641110f801e372ffde6
* http://git.ozlabs.org/?p=ppp.git;a=commitdiff_plain;h=f8191bf07df374f119a07910a79217c7618f113e
*/
num = nm_ip4_config_get_num_nameservers (config);
if (num == 2) {
gboolean found1 = FALSE, found2 = FALSE;
for (i = 0; i < num; i++) {
guint32 ns = nm_ip4_config_get_nameserver (config, i);
if (ns == bad_dns1)
found1 = TRUE;
else if (ns == bad_dns2)
found2 = TRUE;
}
/* Be somewhat conservative about substitutions; the "bad" nameservers
* could actually be valid in some cases, so only substitute if ppp
* returns *only* the two bad nameservers.
*/
dns_workaround = (found1 && found2);
}
if (!num || dns_workaround) {
nm_log_warn (LOGD_PPP, "compensating for invalid PPP-provided nameservers");
nm_ip4_config_reset_nameservers (config);
nm_ip4_config_add_nameserver (config, good_dns1);
nm_ip4_config_add_nameserver (config, good_dns2);
}
g_signal_emit (self, signals[IP4_CONFIG_RESULT], 0, config, NULL);
}
static void
ppp_stats (NMPPPManager *ppp_manager,
guint32 in_bytes,
guint32 out_bytes,
gpointer user_data)
{
NMModem *self = NM_MODEM (user_data);
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
if (priv->in_bytes != in_bytes || priv->out_bytes != out_bytes) {
priv->in_bytes = in_bytes;
priv->out_bytes = out_bytes;
g_signal_emit (self, signals[PPP_STATS], 0, in_bytes, out_bytes);
}
}
static NMActStageReturn
ppp_stage3_ip4_config_start (NMModem *self,
NMActRequest *req,
NMDeviceStateReason *reason)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
const char *ppp_name = NULL;
GError *error = NULL;
NMActStageReturn ret;
guint ip_timeout = 20;
g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
if (NM_MODEM_GET_CLASS (self)->get_user_pass) {
NMConnection *connection = nm_act_request_get_connection (req);
g_assert (connection);
if (!NM_MODEM_GET_CLASS (self)->get_user_pass (self, connection, &ppp_name, NULL))
return NM_ACT_STAGE_RETURN_FAILURE;
}
/* Check if ModemManager requested a specific IP timeout to be used. If 0 reported,
* use the default one (20s) */
if (priv->mm_ip_timeout > 0) {
nm_log_info (LOGD_PPP, "using modem-specified IP timeout: %u seconds",
priv->mm_ip_timeout);
ip_timeout = priv->mm_ip_timeout;
}
priv->ppp_manager = nm_ppp_manager_new (priv->data_port);
if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) {
g_signal_connect (priv->ppp_manager, "state-changed",
G_CALLBACK (ppp_state_changed),
self);
g_signal_connect (priv->ppp_manager, "ip4-config",
G_CALLBACK (ppp_ip4_config),
self);
g_signal_connect (priv->ppp_manager, "stats",
G_CALLBACK (ppp_stats),
self);
ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else {
nm_log_err (LOGD_PPP, "error starting PPP: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_error_free (error);
g_object_unref (priv->ppp_manager);
priv->ppp_manager = NULL;
*reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED;
ret = NM_ACT_STAGE_RETURN_FAILURE;
}
return ret;
}
/*****************************************************************************/
NMActStageReturn
nm_modem_stage3_ip4_config_start (NMModem *self,
NMDevice *device,
NMDeviceClass *device_class,
NMDeviceStateReason *reason)
{
NMModemPrivate *priv;
NMActRequest *req;
NMActStageReturn ret;
g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (NM_IS_DEVICE (device), NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (NM_IS_DEVICE_CLASS (device_class), NM_ACT_STAGE_RETURN_FAILURE);
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
req = nm_device_get_act_request (device);
g_assert (req);
priv = NM_MODEM_GET_PRIVATE (self);
switch (priv->ip_method) {
case MM_MODEM_IP_METHOD_PPP:
ret = ppp_stage3_ip4_config_start (self, req, reason);
break;
case MM_MODEM_IP_METHOD_STATIC:
ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, reason);
break;
case MM_MODEM_IP_METHOD_DHCP:
ret = device_class->act_stage3_ip4_config_start (device, NULL, reason);
break;
default:
nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
ret = NM_ACT_STAGE_RETURN_FAILURE;
break;
}
return ret;
}
void
nm_modem_ip4_pre_commit (NMModem *modem,
NMDevice *device,
NMIP4Config *config)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (modem);
/* If the modem has an ethernet-type data interface (ie, not PPP and thus
* not point-to-point) and IP config has a /32 prefix, then we assume that
* ARP will be pointless and we turn it off.
*/
if ( priv->ip_method == MM_MODEM_IP_METHOD_STATIC
|| priv->ip_method == MM_MODEM_IP_METHOD_DHCP) {
const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, 0);
g_assert (address);
if (address->plen == 32)
nm_platform_link_set_noarp (nm_device_get_ip_ifindex (device));
}
}
/*****************************************************************************/
NMActStageReturn
nm_modem_stage3_ip6_config_start (NMModem *self,
NMDevice *device,
NMDeviceClass *device_class,
NMDeviceStateReason *reason)
{
/* FIXME: We don't support IPv6 on modems quite yet... */
nm_device_activate_schedule_ip6_config_timeout (device);
return NM_ACT_STAGE_RETURN_POSTPONE;
}
/*****************************************************************************/
static void
cancel_get_secrets (NMModem *self)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
if (priv->secrets_id) {
nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id);
priv->secrets_id = 0;
}
}
static void
modem_secrets_cb (NMActRequest *req,
guint32 call_id,
NMConnection *connection,
GError *error,
gpointer user_data)
{
NMModem *self = NM_MODEM (user_data);
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
g_return_if_fail (call_id == priv->secrets_id);
priv->secrets_id = 0;
if (error)
nm_log_warn (LOGD_MB, "%s", error->message);
g_signal_emit (self, signals[AUTH_RESULT], 0, error);
}
gboolean
nm_modem_get_secrets (NMModem *self,
const char *setting_name,
gboolean request_new,
const char *hint)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION;
cancel_get_secrets (self);
if (request_new)
flags |= NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW;
priv->secrets_id = nm_act_request_get_secrets (priv->act_request,
setting_name,
flags,
hint,
modem_secrets_cb,
self);
if (priv->secrets_id)
g_signal_emit (self, signals[AUTH_REQUESTED], 0);
return !!(priv->secrets_id);
}
/*****************************************************************************/
static NMActStageReturn
act_stage1_prepare (NMModem *modem,
NMConnection *connection,
NMDeviceStateReason *reason)
{
*reason = NM_DEVICE_STATE_REASON_UNKNOWN;
return NM_ACT_STAGE_RETURN_FAILURE;
}
NMActStageReturn
nm_modem_act_stage1_prepare (NMModem *self,
NMActRequest *req,
NMDeviceStateReason *reason)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
NMActStageReturn ret;
GPtrArray *hints = NULL;
const char *setting_name = NULL;
NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION;
NMConnection *connection;
if (priv->act_request)
g_object_unref (priv->act_request);
priv->act_request = g_object_ref (req);
connection = nm_act_request_get_connection (req);
g_assert (connection);
setting_name = nm_connection_need_secrets (connection, &hints);
if (!setting_name) {
/* Ready to connect */
g_assert (!hints);
return NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, connection, reason);
}
/* Secrets required... */
if (priv->secrets_tries++)
flags |= NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW;
priv->secrets_id = nm_act_request_get_secrets (req,
setting_name,
flags,
hints ? g_ptr_array_index (hints, 0) : NULL,
modem_secrets_cb,
self);
if (priv->secrets_id) {
g_signal_emit (self, signals[AUTH_REQUESTED], 0);
ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else {
*reason = NM_DEVICE_STATE_REASON_NO_SECRETS;
ret = NM_ACT_STAGE_RETURN_FAILURE;
}
if (hints)
g_ptr_array_free (hints, TRUE);
return ret;
}
/*****************************************************************************/
NMActStageReturn
nm_modem_act_stage2_config (NMModem *self,
NMActRequest *req,
NMDeviceStateReason *reason)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
/* Clear secrets tries counter since secrets were successfully used
* already if we get here.
*/
priv->secrets_tries = 0;
return NM_ACT_STAGE_RETURN_SUCCESS;
}
/*****************************************************************************/
gboolean
nm_modem_check_connection_compatible (NMModem *self,
NMConnection *connection,
GError **error)
{
if (NM_MODEM_GET_CLASS (self)->check_connection_compatible)
return NM_MODEM_GET_CLASS (self)->check_connection_compatible (self, connection, error);
return FALSE;
}
/*****************************************************************************/
gboolean
nm_modem_complete_connection (NMModem *self,
NMConnection *connection,
const GSList *existing_connections,
GError **error)
{
if (NM_MODEM_GET_CLASS (self)->complete_connection)
return NM_MODEM_GET_CLASS (self)->complete_connection (self, connection, existing_connections, error);
return FALSE;
}
/*****************************************************************************/
static void
deactivate (NMModem *self, NMDevice *device)
{
NMModemPrivate *priv;
int ifindex;
g_return_if_fail (NM_IS_MODEM (self));
g_return_if_fail (NM_IS_DEVICE (device));
priv = NM_MODEM_GET_PRIVATE (self);
priv->secrets_tries = 0;
if (priv->act_request) {
cancel_get_secrets (self);
g_object_unref (priv->act_request);
priv->act_request = NULL;
}
priv->in_bytes = priv->out_bytes = 0;
if (priv->ppp_manager) {
g_object_unref (priv->ppp_manager);
priv->ppp_manager = NULL;
}
switch (priv->ip_method) {
case MM_MODEM_IP_METHOD_PPP:
break;
case MM_MODEM_IP_METHOD_STATIC:
case MM_MODEM_IP_METHOD_DHCP:
ifindex = nm_device_get_ip_ifindex (device);
if (ifindex > 0) {
nm_platform_route_flush (ifindex);
nm_platform_address_flush (ifindex);
nm_platform_link_set_down (ifindex);
}
break;
default:
nm_log_err (LOGD_MB, "unknown IP method %d", priv->ip_method);
break;
}
g_free (priv->ppp_iface);
priv->ppp_iface = NULL;
}
/*****************************************************************************/
void
nm_modem_deactivate (NMModem *self, NMDevice *device)
{
NM_MODEM_GET_CLASS (self)->deactivate (self, device);
}
/*****************************************************************************/
void
nm_modem_device_state_changed (NMModem *self,
NMDeviceState new_state,
NMDeviceState old_state,
NMDeviceStateReason reason)
{
gboolean was_connected = FALSE, warn = TRUE;
NMModemPrivate *priv;
g_return_if_fail (NM_IS_MODEM (self));
if (old_state >= NM_DEVICE_STATE_PREPARE && old_state <= NM_DEVICE_STATE_DEACTIVATING)
was_connected = TRUE;
priv = NM_MODEM_GET_PRIVATE (self);
/* Make sure we don't leave the serial device open */
switch (new_state) {
case NM_DEVICE_STATE_UNMANAGED:
case NM_DEVICE_STATE_UNAVAILABLE:
case NM_DEVICE_STATE_DISCONNECTED:
case NM_DEVICE_STATE_FAILED:
if (priv->act_request) {
cancel_get_secrets (self);
g_object_unref (priv->act_request);
priv->act_request = NULL;
}
if (was_connected) {
/* Don't bother warning on FAILED since the modem is already gone */
if (new_state == NM_DEVICE_STATE_FAILED)
warn = FALSE;
NM_MODEM_GET_CLASS (self)->disconnect (self, warn);
}
break;
default:
break;
}
}
/*****************************************************************************/
const char *
nm_modem_get_uid (NMModem *self)
{
g_return_val_if_fail (NM_IS_MODEM (self), NULL);
return NM_MODEM_GET_PRIVATE (self)->uid;
}
const char *
nm_modem_get_path (NMModem *self)
{
g_return_val_if_fail (NM_IS_MODEM (self), NULL);
return NM_MODEM_GET_PRIVATE (self)->path;
}
const char *
nm_modem_get_driver (NMModem *self)
{
g_return_val_if_fail (NM_IS_MODEM (self), NULL);
return NM_MODEM_GET_PRIVATE (self)->driver;
}
const char *
nm_modem_get_control_port (NMModem *self)
{
g_return_val_if_fail (NM_IS_MODEM (self), NULL);
return NM_MODEM_GET_PRIVATE (self)->control_port;
}
const char *
nm_modem_get_data_port (NMModem *self)
{
g_return_val_if_fail (NM_IS_MODEM (self), NULL);
/* The ppp_iface takes precedence over the data interface when PPP is used,
* since data_iface is the TTY over which PPP is run, and that TTY can't
* do IP. The caller really wants the thing that's doing IP.
*/
return NM_MODEM_GET_PRIVATE (self)->ppp_iface ?
NM_MODEM_GET_PRIVATE (self)->ppp_iface : NM_MODEM_GET_PRIVATE (self)->data_port;
}
gboolean
nm_modem_owns_port (NMModem *self, const char *iface)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
g_return_val_if_fail (iface != NULL, FALSE);
if (NM_MODEM_GET_CLASS (self)->owns_port)
return NM_MODEM_GET_CLASS (self)->owns_port (self, iface);
/* Fall back to data/control ports */
if (priv->ppp_iface && (strcmp (priv->ppp_iface, iface) == 0))
return TRUE;
if (priv->data_port && (strcmp (priv->data_port, iface) == 0))
return TRUE;
if (priv->control_port && (strcmp (priv->control_port, iface) == 0))
return TRUE;
return FALSE;
}
/*****************************************************************************/
void
nm_modem_get_capabilities (NMModem *self,
NMDeviceModemCapabilities *modem_caps,
NMDeviceModemCapabilities *current_caps)
{
g_return_if_fail (NM_IS_MODEM (self));
NM_MODEM_GET_CLASS (self)->get_capabilities (self, modem_caps, current_caps);
}
/*****************************************************************************/
static void
nm_modem_init (NMModem *self)
{
}
static GObject*
constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
{
GObject *object;
NMModemPrivate *priv;
object = G_OBJECT_CLASS (nm_modem_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (!object)
return NULL;
priv = NM_MODEM_GET_PRIVATE (object);
if (!priv->data_port && !priv->control_port) {
nm_log_err (LOGD_HW, "neither modem command nor data interface provided");
goto err;
}
if (!priv->path) {
nm_log_err (LOGD_HW, "D-Bus path not provided");
goto err;
}
return object;
err:
g_object_unref (object);
return NULL;
}
static void
get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
switch (prop_id) {
case PROP_PATH:
g_value_set_string (value, priv->path);
break;
case PROP_DRIVER:
g_value_set_string (value, priv->driver);
break;
case PROP_CONTROL_PORT:
g_value_set_string (value, priv->control_port);
break;
case PROP_DATA_PORT:
g_value_set_string (value, nm_modem_get_data_port (NM_MODEM (object)));
break;
case PROP_UID:
g_value_set_string (value, priv->uid);
break;
case PROP_IP_METHOD:
g_value_set_uint (value, priv->ip_method);
break;
case PROP_IP_TIMEOUT:
g_value_set_uint (value, priv->mm_ip_timeout);
break;
case PROP_ENABLED:
g_value_set_boolean (value, priv->mm_enabled);
break;
case PROP_CONNECTED:
g_value_set_boolean (value, priv->mm_connected);
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)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
switch (prop_id) {
case PROP_PATH:
/* Construct only */
priv->path = g_value_dup_string (value);
break;
case PROP_DRIVER:
/* Construct only */
priv->driver = g_value_dup_string (value);
break;
case PROP_CONTROL_PORT:
priv->control_port = g_value_dup_string (value);
break;
case PROP_DATA_PORT:
priv->data_port = g_value_dup_string (value);
break;
case PROP_UID:
/* Construct only */
priv->uid = g_value_dup_string (value);
break;
case PROP_IP_METHOD:
priv->ip_method = g_value_get_uint (value);
break;
case PROP_IP_TIMEOUT:
priv->mm_ip_timeout = g_value_get_uint (value);
break;
case PROP_ENABLED:
priv->mm_enabled = g_value_get_boolean (value);
break;
case PROP_CONNECTED:
priv->mm_connected = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
dispose (GObject *object)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
if (priv->act_request) {
g_object_unref (priv->act_request);
priv->act_request = NULL;
}
G_OBJECT_CLASS (nm_modem_parent_class)->dispose (object);
}
static void
finalize (GObject *object)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
g_free (priv->uid);
g_free (priv->path);
g_free (priv->driver);
g_free (priv->control_port);
g_free (priv->data_port);
G_OBJECT_CLASS (nm_modem_parent_class)->finalize (object);
}
static void
nm_modem_class_init (NMModemClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
g_type_class_add_private (object_class, sizeof (NMModemPrivate));
/* Virtual methods */
object_class->constructor = constructor;
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->dispose = dispose;
object_class->finalize = finalize;
klass->act_stage1_prepare = act_stage1_prepare;
klass->deactivate = deactivate;
/* Properties */
g_object_class_install_property
(object_class, PROP_UID,
g_param_spec_string (NM_MODEM_UID,
"UID",
"Modem unique ID",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_PATH,
g_param_spec_string (NM_MODEM_PATH,
"DBus path",
"DBus path",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_DRIVER,
g_param_spec_string (NM_MODEM_DRIVER,
"Driver",
"Driver",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_CONTROL_PORT,
g_param_spec_string (NM_MODEM_CONTROL_PORT,
"Control port",
"The port controlling the modem",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_DATA_PORT,
g_param_spec_string (NM_MODEM_DATA_PORT,
"Data port",
"The port to connect to",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property
(object_class, PROP_IP_METHOD,
g_param_spec_uint (NM_MODEM_IP_METHOD,
"IP method",
"IP method",
MM_MODEM_IP_METHOD_PPP,
MM_MODEM_IP_METHOD_DHCP,
MM_MODEM_IP_METHOD_PPP,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class, PROP_IP_TIMEOUT,
g_param_spec_uint (NM_MODEM_IP_TIMEOUT,
"IP timeout",
"IP timeout",
0, 360, 20,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class, PROP_ENABLED,
g_param_spec_boolean (NM_MODEM_ENABLED,
"Enabled",
"Enabled",
TRUE,
G_PARAM_READWRITE));
g_object_class_install_property
(object_class, PROP_CONNECTED,
g_param_spec_boolean (NM_MODEM_CONNECTED,
"Connected",
"Connected",
TRUE,
G_PARAM_READWRITE));
/* Signals */
signals[PPP_STATS] =
g_signal_new ("ppp-stats",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMModemClass, ppp_stats),
NULL, NULL, NULL,
G_TYPE_NONE, 2,
G_TYPE_UINT, G_TYPE_UINT);
signals[PPP_FAILED] =
g_signal_new ("ppp-failed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMModemClass, ppp_failed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_UINT);
signals[IP4_CONFIG_RESULT] =
g_signal_new (NM_MODEM_IP4_CONFIG_RESULT,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMModemClass, ip4_config_result),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_OBJECT, G_TYPE_POINTER);
signals[PREPARE_RESULT] =
g_signal_new (NM_MODEM_PREPARE_RESULT,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMModemClass, prepare_result),
NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_BOOLEAN, G_TYPE_UINT);
signals[AUTH_REQUESTED] =
g_signal_new (NM_MODEM_AUTH_REQUESTED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMModemClass, auth_requested),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[AUTH_RESULT] =
g_signal_new (NM_MODEM_AUTH_RESULT,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMModemClass, auth_result),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_POINTER);
dbus_g_error_domain_register (NM_MODEM_ERROR,
NM_DBUS_INTERFACE_DEVICE_MODEM,
NM_TYPE_MODEM_ERROR);
}