From 052a24343ef2c4cc304bc2f635963e642889d2c9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 24 Aug 2012 08:43:03 -0500 Subject: [PATCH] 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). --- src/modem-manager/nm-modem-cdma.c | 4 +- src/modem-manager/nm-modem-cdma.h | 3 +- src/modem-manager/nm-modem-gsm.c | 4 +- src/modem-manager/nm-modem-gsm.h | 3 +- src/modem-manager/nm-modem-manager.c | 12 +++-- src/modem-manager/nm-modem.c | 65 +++++++++++++++++++++++++--- src/modem-manager/nm-modem.h | 20 +++++++++ src/nm-device-modem.c | 14 ++++++ 8 files changed, 111 insertions(+), 14 deletions(-) diff --git a/src/modem-manager/nm-modem-cdma.c b/src/modem-manager/nm-modem-cdma.c index fa19a34253..2fcbc7ea02 100644 --- a/src/modem-manager/nm-modem-cdma.c +++ b/src/modem-manager/nm-modem-cdma.c @@ -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); } diff --git a/src/modem-manager/nm-modem-cdma.h b/src/modem-manager/nm-modem-cdma.h index 2229c18375..496f06c3fa 100644 --- a/src/modem-manager/nm-modem-cdma.h +++ b/src/modem-manager/nm-modem-cdma.h @@ -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 diff --git a/src/modem-manager/nm-modem-gsm.c b/src/modem-manager/nm-modem-gsm.c index 183b4780b7..c0a8f2e5f5 100644 --- a/src/modem-manager/nm-modem-gsm.c +++ b/src/modem-manager/nm-modem-gsm.c @@ -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); } diff --git a/src/modem-manager/nm-modem-gsm.h b/src/modem-manager/nm-modem-gsm.h index e1c94f045c..3afdf8945a 100644 --- a/src/modem-manager/nm-modem-gsm.h +++ b/src/modem-manager/nm-modem-gsm.h @@ -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 diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c index 051940f5ed..87e0489d00 100644 --- a/src/modem-manager/nm-modem-manager.c +++ b/src/modem-manager/nm-modem-manager.c @@ -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); diff --git a/src/modem-manager/nm-modem.c b/src/modem-manager/nm-modem.c index c9c9e9a467..e6bb2b5c44 100644 --- a/src/modem-manager/nm-modem.c +++ b/src/modem-manager/nm-modem.c @@ -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", diff --git a/src/modem-manager/nm-modem.h b/src/modem-manager/nm-modem.h index 8fe52bc05c..483dec150b 100644 --- a/src/modem-manager/nm-modem.h +++ b/src/modem-manager/nm-modem.h @@ -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 */ diff --git a/src/nm-device-modem.c b/src/nm-device-modem.c index e7cd9259bd..e3157504f0 100644 --- a/src/nm-device-modem.c +++ b/src/nm-device-modem.c @@ -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