modem: track modem state and fail device if modem disconnects

This worked fine with PPP because PPP terminates, and NM watches
for that and handles it fine.  But modems with pseudo-ethernet ports
don't have anything like that, so we have to watch the modem's state
property instead.  This works only with MM 0.5.4 and later (including
0.6).
This commit is contained in:
Dan Williams 2012-08-24 08:43:03 -05:00
parent 722ce46aaa
commit 052a24343e
8 changed files with 111 additions and 14 deletions

View file

@ -64,7 +64,8 @@ NMModem *
nm_modem_cdma_new (const char *path,
const char *device,
const char *data_device,
guint32 ip_method)
guint32 ip_method,
NMModemState state)
{
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (device != NULL, NULL);
@ -75,6 +76,7 @@ nm_modem_cdma_new (const char *path,
NM_MODEM_DEVICE, device,
NM_MODEM_IFACE, data_device,
NM_MODEM_IP_METHOD, ip_method,
NM_MODEM_STATE, state,
NULL);
}

View file

@ -55,7 +55,8 @@ GType nm_modem_cdma_get_type (void);
NMModem *nm_modem_cdma_new (const char *path,
const char *device,
const char *data_device,
guint32 ip_method);
guint32 ip_method,
NMModemState state);
G_END_DECLS

View file

@ -104,7 +104,8 @@ NMModem *
nm_modem_gsm_new (const char *path,
const char *device,
const char *data_device,
guint32 ip_method)
guint32 ip_method,
NMModemState state)
{
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (device != NULL, NULL);
@ -115,6 +116,7 @@ nm_modem_gsm_new (const char *path,
NM_MODEM_DEVICE, device,
NM_MODEM_IFACE, data_device,
NM_MODEM_IP_METHOD, ip_method,
NM_MODEM_STATE, state,
NULL);
}

View file

@ -55,7 +55,8 @@ GType nm_modem_gsm_get_type (void);
NMModem *nm_modem_gsm_new (const char *path,
const char *device,
const char *data_device,
guint32 ip_method);
guint32 ip_method,
NMModemState state);
G_END_DECLS

View file

@ -77,7 +77,8 @@ get_modem_properties (DBusGConnection *connection,
char **driver,
guint32 *type,
guint32 *ip_method,
guint32 *ip_timeout)
guint32 *ip_timeout,
NMModemState *state)
{
DBusGProxy *proxy;
GError *err = NULL;
@ -122,6 +123,8 @@ get_modem_properties (DBusGConnection *connection,
*driver = g_value_dup_string (value);
else if (g_strcmp0 (prop, "IpTimeout") == 0)
*ip_timeout = g_value_get_uint (value);
else if (g_strcmp0 (prop, "State") == 0)
*state = g_value_get_uint (value);
}
g_hash_table_unref (props);
@ -140,6 +143,7 @@ create_modem (NMModemManager *manager, const char *path)
uint modem_type = MM_MODEM_TYPE_UNKNOWN;
uint ip_method = MM_MODEM_IP_METHOD_PPP;
uint ip_timeout = 0;
NMModemState state = NM_MODEM_STATE_UNKNOWN;
if (g_hash_table_lookup (priv->modems, path)) {
nm_log_warn (LOGD_MB, "modem with path %s already exists, ignoring", path);
@ -148,7 +152,7 @@ create_modem (NMModemManager *manager, const char *path)
if (!get_modem_properties (nm_dbus_manager_get_connection (priv->dbus_mgr),
path, &master_device, &data_device, &driver,
&modem_type, &ip_method, &ip_timeout))
&modem_type, &ip_method, &ip_timeout, &state))
return;
if (modem_type == MM_MODEM_TYPE_UNKNOWN) {
@ -172,9 +176,9 @@ create_modem (NMModemManager *manager, const char *path)
}
if (modem_type == MM_MODEM_TYPE_GSM)
modem = nm_modem_gsm_new (path, master_device, data_device, ip_method);
modem = nm_modem_gsm_new (path, master_device, data_device, ip_method, state);
else if (modem_type == MM_MODEM_TYPE_CDMA)
modem = nm_modem_cdma_new (path, master_device, data_device, ip_method);
modem = nm_modem_cdma_new (path, master_device, data_device, ip_method, state);
else
nm_log_warn (LOGD_MB, "unknown modem type '%d'", modem_type);

View file

@ -44,6 +44,7 @@ enum {
PROP_IP_METHOD,
PROP_IP_TIMEOUT,
PROP_ENABLED,
PROP_STATE,
LAST_PROP
};
@ -67,6 +68,7 @@ typedef struct {
gboolean mm_enabled;
guint32 mm_ip_timeout;
NMModemState state;
/* PPP stats */
guint32 in_bytes;
@ -105,6 +107,14 @@ nm_modem_get_mm_enabled (NMModem *self)
return NM_MODEM_GET_PRIVATE (self)->mm_enabled;
}
NMModemState
nm_modem_get_state (NMModem *self)
{
g_return_val_if_fail (NM_IS_MODEM (self), NM_MODEM_STATE_UNKNOWN);
return NM_MODEM_GET_PRIVATE (self)->state;
}
DBusGProxy *
nm_modem_get_proxy (NMModem *self,
const char *interface)
@ -798,6 +808,7 @@ modem_properties_changed (DBusGProxy *proxy,
NMModem *self = NM_MODEM (user_data);
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self);
GValue *value;
NMModemState new_state;
if (strcmp (interface, MM_DBUS_INTERFACE_MODEM))
return;
@ -812,6 +823,15 @@ modem_properties_changed (DBusGProxy *proxy,
priv->ip_method = g_value_get_uint (value);
g_object_notify (G_OBJECT (self), NM_MODEM_IP_METHOD);
}
value = g_hash_table_lookup (props, "State");
if (value && G_VALUE_HOLDS_UINT (value)) {
new_state = g_value_get_uint (value);
if (new_state != priv->state) {
priv->state = new_state;
g_object_notify (G_OBJECT (self), NM_MODEM_STATE);
}
}
}
/*****************************************************************************/
@ -912,11 +932,13 @@ get_property (GObject *object, guint prop_id,
case PROP_ENABLED:
g_value_set_boolean (value, priv->mm_enabled);
break;
case PROP_STATE:
g_value_set_boolean (value, priv->state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
@ -947,6 +969,9 @@ set_property (GObject *object, guint prop_id,
break;
case PROP_ENABLED:
break;
case PROP_STATE:
priv->state = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -954,20 +979,37 @@ set_property (GObject *object, guint prop_id,
}
static void
finalize (GObject *object)
dispose (GObject *object)
{
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object);
if (priv->act_request)
if (priv->act_request) {
g_object_unref (priv->act_request);
priv->act_request = NULL;
}
if (priv->proxy)
if (priv->proxy) {
g_object_unref (priv->proxy);
priv->proxy = NULL;
}
if (priv->props_proxy)
if (priv->props_proxy) {
g_object_unref (priv->props_proxy);
priv->props_proxy = NULL;
}
g_object_unref (priv->dbus_mgr);
if (priv->dbus_mgr) {
g_object_unref (priv->dbus_mgr);
priv->dbus_mgr = 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->iface);
g_free (priv->path);
@ -987,6 +1029,7 @@ nm_modem_class_init (NMModemClass *klass)
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 = real_act_stage1_prepare;
@ -1043,6 +1086,16 @@ nm_modem_class_init (NMModemClass *klass)
TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | NM_PROPERTY_PARAM_NO_EXPORT));
g_object_class_install_property
(object_class, PROP_STATE,
g_param_spec_uint (NM_MODEM_STATE,
"ModemManager modem state",
"ModemManager modem state",
NM_MODEM_STATE_UNKNOWN,
NM_MODEM_STATE_LAST,
NM_MODEM_STATE_UNKNOWN,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
/* Signals */
signals[PPP_STATS] =
g_signal_new ("ppp-stats",

View file

@ -42,6 +42,7 @@ G_BEGIN_DECLS
#define NM_MODEM_IP_METHOD "ip-method"
#define NM_MODEM_IP_TIMEOUT "ip-timeout"
#define NM_MODEM_ENABLED "enabled"
#define NM_MODEM_STATE "state"
#define NM_MODEM_PPP_STATS "ppp-stats"
#define NM_MODEM_PPP_FAILED "ppp-failed"
@ -50,6 +51,23 @@ G_BEGIN_DECLS
#define NM_MODEM_AUTH_REQUESTED "auth-requested"
#define NM_MODEM_AUTH_RESULT "auth-result"
/* From ModemManager */
typedef enum {
NM_MODEM_STATE_UNKNOWN = 0,
NM_MODEM_STATE_DISABLED = 10,
NM_MODEM_STATE_DISABLING = 20,
NM_MODEM_STATE_ENABLING = 30,
NM_MODEM_STATE_ENABLED = 40,
NM_MODEM_STATE_SEARCHING = 50,
NM_MODEM_STATE_REGISTERED = 60,
NM_MODEM_STATE_DISCONNECTING = 70,
NM_MODEM_STATE_CONNECTING = 80,
NM_MODEM_STATE_CONNECTED = 90,
NM_MODEM_STATE_LAST = NM_MODEM_STATE_CONNECTED
} NMModemState;
typedef struct {
GObject parent;
} NMModem;
@ -155,6 +173,8 @@ gboolean nm_modem_get_mm_enabled (NMModem *self);
void nm_modem_set_mm_enabled (NMModem *self, gboolean enabled);
NMModemState nm_modem_get_state (NMModem *self);
G_END_DECLS
#endif /* NM_MODEM_H */

View file

@ -166,6 +166,19 @@ modem_enabled_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data)
g_signal_emit (G_OBJECT (self), signals[ENABLE_CHANGED], 0);
}
static void
modem_state_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data)
{
NMDeviceModem *self = NM_DEVICE_MODEM (user_data);
NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self);
if ( nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED
&& nm_modem_get_state (priv->modem) != NM_MODEM_STATE_CONNECTED) {
/* Fail the device if the modem disconnects unexpectedly */
nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER);
}
}
/*****************************************************************************/
NMModem *
@ -379,6 +392,7 @@ set_modem (NMDeviceModem *self, NMModem *modem)
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);
g_signal_connect (modem, "notify::" NM_MODEM_STATE, G_CALLBACK (modem_state_cb), self);
}
static void