mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-31 18:20:10 +01:00
wwan: wait for pppd to exit before relaying the port to ModemManager
ModemManager needs to have CLOCAL set in the TTY termios configuration, in order
to notify the kernel that modem control lines are not in effect (e.g. so that a
transition to LOW in the DCD input control line doesn't trigger a hangup in the
TTY).
pppd in the other hand, needs CLOCAL unset in order to have proper modem control
lines in effect during the PPP session. So, when pppd starts it will store the
original termios settings, and before exiting it will restore the original
settings in the TTY. In other words, if CLOCAL was set before launching pppd,
CLOCAL will be also set after pppd exits.
Now, in order for this sequence to work correctly, NetworkManager also needs to
make sure that ModemManager is notified about the disconnection only after pppd
has really finished re-configuring the TTY.
https://bugzilla.gnome.org/show_bug.cgi?id=734347
----------------------
Once the patch is applied, we will be making sure that ModemManager is only
notified about the disconnection AFTER pppd has fully exited:
NetworkManager[27589]: <info> (ttyUSB2): device state change: activated -> deactivating (reason 'user-requested') [100 110 39]
Terminating on signal 15
nm-pppd-plugin-Message: nm-ppp-plugin: (nm_phasechange): status 10 / phase 'terminate'
nm-pppd-plugin-Message: nm-ppp-plugin: (nm_phasechange): status 8 / phase 'network'
Connect time 0.3 minutes.
Sent 56 bytes, received 0 bytes.
nm-pppd-plugin-Message: nm-ppp-plugin: (nm_phasechange): status 5 / phase 'establish'
nm-pppd-plugin-Message: nm-ppp-plugin: (nm_phasechange): status 11 / phase 'disconnect'
Connection terminated.
nm-pppd-plugin-Message: nm-ppp-plugin: (nm_phasechange): status 1 / phase 'dead'
nm-pppd-plugin-Message: nm-ppp-plugin: (nm_exit_notify): cleaning up
NetworkManager[27589]: <warn> pppd pid 27617 exited with error: pppd received a signal
NetworkManager[27589]: <info> (ttyUSB2): modem state changed, 'connected' --> 'disconnecting' (reason: user-requested)
NetworkManager[27589]: <info> (ttyUSB2): modem state changed, 'disconnecting' --> 'registered' (reason: user-requested)
NetworkManager[27589]: <info> (ttyUSB2) modem deactivation finished
NetworkManager[27589]: <info> (ttyUSB2): device state change: deactivating -> disconnected (reason 'user-requested') [110 30 39]
NetworkManager[27589]: <info> (ttyUSB2): deactivating device (reason 'user-requested') [39]
(cherry picked from commit fe090c34b7)
This commit is contained in:
parent
a274b66d37
commit
0cd5589add
5 changed files with 245 additions and 17 deletions
|
|
@ -437,6 +437,50 @@ deactivate (NMDevice *device)
|
|||
nm_modem_deactivate (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, device);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
static gboolean
|
||||
deactivate_async_finish (NMDevice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
modem_deactivate_async_ready (NMModem *modem,
|
||||
GAsyncResult *res,
|
||||
GSimpleAsyncResult *simple)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!nm_modem_deactivate_async_finish (modem, res, &error))
|
||||
g_simple_async_result_take_error (simple, error);
|
||||
g_simple_async_result_complete (simple);
|
||||
g_object_unref (simple);
|
||||
}
|
||||
|
||||
static void
|
||||
deactivate_async (NMDevice *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (self),
|
||||
callback,
|
||||
user_data,
|
||||
deactivate_async);
|
||||
nm_modem_deactivate_async (NM_DEVICE_MODEM_GET_PRIVATE (self)->modem,
|
||||
self,
|
||||
cancellable,
|
||||
(GAsyncReadyCallback) modem_deactivate_async_ready,
|
||||
simple);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
|
||||
static NMActStageReturn
|
||||
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
|
||||
{
|
||||
|
|
@ -710,6 +754,8 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass)
|
|||
device_class->check_connection_compatible = check_connection_compatible;
|
||||
device_class->check_connection_available = check_connection_available;
|
||||
device_class->complete_connection = complete_connection;
|
||||
device_class->deactivate_async = deactivate_async;
|
||||
device_class->deactivate_async_finish = deactivate_async_finish;
|
||||
device_class->deactivate = deactivate;
|
||||
device_class->act_stage1_prepare = act_stage1_prepare;
|
||||
device_class->act_stage2_config = act_stage2_config;
|
||||
|
|
|
|||
|
|
@ -928,6 +928,8 @@ disconnect (NMModem *self,
|
|||
return;
|
||||
}
|
||||
|
||||
nm_log_dbg (LOGD_MB, "(%s): notifying ModemManager about the modem disconnection",
|
||||
nm_modem_get_uid (NM_MODEM (ctx->self)));
|
||||
mm_modem_simple_disconnect (
|
||||
ctx->self->priv->simple_iface,
|
||||
NULL, /* bearer path; if NULL given ALL get disconnected */
|
||||
|
|
@ -939,7 +941,7 @@ disconnect (NMModem *self,
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
deactivate (NMModem *_self, NMDevice *device)
|
||||
deactivate_cleanup (NMModem *_self, NMDevice *device)
|
||||
{
|
||||
NMModemBroadband *self = NM_MODEM_BROADBAND (_self);
|
||||
|
||||
|
|
@ -953,7 +955,7 @@ deactivate (NMModem *_self, NMDevice *device)
|
|||
self->priv->pin_tries = 0;
|
||||
|
||||
/* Chain up parent's */
|
||||
NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate (_self, device);
|
||||
NM_MODEM_CLASS (nm_modem_broadband_parent_class)->deactivate_cleanup (_self, device);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -1183,7 +1185,7 @@ nm_modem_broadband_class_init (NMModemBroadbandClass *klass)
|
|||
modem_class->stage3_ip6_config_request = stage3_ip6_config_request;
|
||||
modem_class->disconnect = disconnect;
|
||||
modem_class->disconnect_finish = disconnect_finish;
|
||||
modem_class->deactivate = deactivate;
|
||||
modem_class->deactivate_cleanup = deactivate_cleanup;
|
||||
modem_class->set_mm_enabled = set_mm_enabled;
|
||||
modem_class->get_user_pass = get_user_pass;
|
||||
modem_class->check_connection_compatible = check_connection_compatible;
|
||||
|
|
|
|||
|
|
@ -839,7 +839,7 @@ nm_modem_complete_connection (NMModem *self,
|
|||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
deactivate (NMModem *self, NMDevice *device)
|
||||
deactivate_cleanup (NMModem *self, NMDevice *device)
|
||||
{
|
||||
NMModemPrivate *priv;
|
||||
int ifindex;
|
||||
|
|
@ -864,15 +864,17 @@ deactivate (NMModem *self, NMDevice *device)
|
|||
priv->ppp_manager = NULL;
|
||||
}
|
||||
|
||||
if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC ||
|
||||
priv->ip4_method == NM_MODEM_IP_METHOD_AUTO ||
|
||||
priv->ip6_method == NM_MODEM_IP_METHOD_STATIC ||
|
||||
priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) {
|
||||
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);
|
||||
if (device) {
|
||||
if (priv->ip4_method == NM_MODEM_IP_METHOD_STATIC ||
|
||||
priv->ip4_method == NM_MODEM_IP_METHOD_AUTO ||
|
||||
priv->ip6_method == NM_MODEM_IP_METHOD_STATIC ||
|
||||
priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN;
|
||||
|
|
@ -884,10 +886,176 @@ deactivate (NMModem *self, NMDevice *device)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
DEACTIVATE_CONTEXT_STEP_FIRST,
|
||||
DEACTIVATE_CONTEXT_STEP_CLEANUP,
|
||||
DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP,
|
||||
DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT,
|
||||
DEACTIVATE_CONTEXT_STEP_LAST
|
||||
} DeactivateContextStep;
|
||||
|
||||
typedef struct {
|
||||
NMModem *self;
|
||||
NMDevice *device;
|
||||
GCancellable *cancellable;
|
||||
GSimpleAsyncResult *result;
|
||||
DeactivateContextStep step;
|
||||
NMPPPManager *ppp_manager;
|
||||
} DeactivateContext;
|
||||
|
||||
static void
|
||||
deactivate_context_complete (DeactivateContext *ctx)
|
||||
{
|
||||
if (ctx->ppp_manager)
|
||||
g_object_unref (ctx->ppp_manager);
|
||||
if (ctx->cancellable)
|
||||
g_object_unref (ctx->cancellable);
|
||||
g_simple_async_result_complete_in_idle (ctx->result);
|
||||
g_object_unref (ctx->result);
|
||||
g_object_unref (ctx->device);
|
||||
g_object_unref (ctx->self);
|
||||
g_slice_free (DeactivateContext, ctx);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_modem_deactivate_async_finish (NMModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
|
||||
}
|
||||
|
||||
static void deactivate_step (DeactivateContext *ctx);
|
||||
|
||||
static void
|
||||
disconnect_ready (NMModem *self,
|
||||
GAsyncResult *res,
|
||||
DeactivateContext *ctx)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!NM_MODEM_GET_CLASS (self)->disconnect_finish (self, res, &error)) {
|
||||
g_simple_async_result_take_error (ctx->result, error);
|
||||
deactivate_context_complete (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Go on */
|
||||
ctx->step++;
|
||||
deactivate_step (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
ppp_manager_stop_ready (NMPPPManager *ppp_manager,
|
||||
GAsyncResult *res,
|
||||
DeactivateContext *ctx)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!nm_ppp_manager_stop_finish (ppp_manager, res, &error)) {
|
||||
nm_log_warn (LOGD_MB, "(%s) cannot stop PPP manager: %s",
|
||||
nm_modem_get_uid (ctx->self),
|
||||
error->message);
|
||||
g_simple_async_result_take_error (ctx->result, error);
|
||||
deactivate_context_complete (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Go on */
|
||||
ctx->step++;
|
||||
deactivate_step (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
deactivate_step (DeactivateContext *ctx)
|
||||
{
|
||||
NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (ctx->self);
|
||||
GError *error = NULL;
|
||||
|
||||
/* Check cancellable in each step */
|
||||
if (g_cancellable_set_error_if_cancelled (ctx->cancellable, &error)) {
|
||||
g_simple_async_result_take_error (ctx->result, error);
|
||||
deactivate_context_complete (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ctx->step) {
|
||||
case DEACTIVATE_CONTEXT_STEP_FIRST:
|
||||
ctx->step++;
|
||||
/* Fall down */
|
||||
|
||||
case DEACTIVATE_CONTEXT_STEP_CLEANUP:
|
||||
/* Make sure we keep a ref to the PPP manager if there is one */
|
||||
if (priv->ppp_manager)
|
||||
ctx->ppp_manager = g_object_ref (priv->ppp_manager);
|
||||
/* Run cleanup */
|
||||
NM_MODEM_GET_CLASS (ctx->self)->deactivate_cleanup (ctx->self, ctx->device);
|
||||
ctx->step++;
|
||||
/* Fall down */
|
||||
|
||||
case DEACTIVATE_CONTEXT_STEP_PPP_MANAGER_STOP:
|
||||
/* If we have a PPP manager, stop it */
|
||||
if (ctx->ppp_manager) {
|
||||
nm_ppp_manager_stop (ctx->ppp_manager,
|
||||
ctx->cancellable,
|
||||
(GAsyncReadyCallback) ppp_manager_stop_ready,
|
||||
ctx);
|
||||
return;
|
||||
}
|
||||
ctx->step++;
|
||||
/* Fall down */
|
||||
|
||||
case DEACTIVATE_CONTEXT_STEP_MM_DISCONNECT:
|
||||
/* Disconnect asynchronously */
|
||||
NM_MODEM_GET_CLASS (ctx->self)->disconnect (ctx->self,
|
||||
FALSE,
|
||||
ctx->cancellable,
|
||||
(GAsyncReadyCallback) disconnect_ready,
|
||||
ctx);
|
||||
return;
|
||||
|
||||
case DEACTIVATE_CONTEXT_STEP_LAST:
|
||||
nm_log_dbg (LOGD_MB, "(%s): modem deactivation finished",
|
||||
nm_modem_get_uid (ctx->self));
|
||||
deactivate_context_complete (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
void
|
||||
nm_modem_deactivate_async (NMModem *self,
|
||||
NMDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
DeactivateContext *ctx;
|
||||
|
||||
ctx = g_slice_new0 (DeactivateContext);
|
||||
ctx->self = g_object_ref (self);
|
||||
ctx->device = g_object_ref (device);
|
||||
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||
callback,
|
||||
user_data,
|
||||
nm_modem_deactivate_async);
|
||||
ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
|
||||
|
||||
/* Start */
|
||||
ctx->step = DEACTIVATE_CONTEXT_STEP_FIRST;
|
||||
deactivate_step (ctx);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
nm_modem_deactivate (NMModem *self, NMDevice *device)
|
||||
{
|
||||
NM_MODEM_GET_CLASS (self)->deactivate (self, device);
|
||||
/* First cleanup */
|
||||
NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, device);
|
||||
/* Then disconnect without waiting */
|
||||
NM_MODEM_GET_CLASS (self)->disconnect (self, FALSE, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -912,7 +1080,6 @@ nm_modem_device_state_changed (NMModem *self,
|
|||
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);
|
||||
|
|
@ -924,6 +1091,8 @@ nm_modem_device_state_changed (NMModem *self,
|
|||
/* Don't bother warning on FAILED since the modem is already gone */
|
||||
if (new_state == NM_DEVICE_STATE_FAILED)
|
||||
warn = FALSE;
|
||||
/* First cleanup */
|
||||
NM_MODEM_GET_CLASS (self)->deactivate_cleanup (self, NULL);
|
||||
NM_MODEM_GET_CLASS (self)->disconnect (self, warn, NULL, NULL, NULL);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1209,7 +1378,7 @@ nm_modem_class_init (NMModemClass *klass)
|
|||
|
||||
klass->act_stage1_prepare = act_stage1_prepare;
|
||||
klass->stage3_ip6_config_request = stage3_ip6_config_request;
|
||||
klass->deactivate = deactivate;
|
||||
klass->deactivate_cleanup = deactivate_cleanup;
|
||||
|
||||
/* Properties */
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ typedef struct {
|
|||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void (*deactivate) (NMModem *self, NMDevice *device);
|
||||
void (*deactivate_cleanup) (NMModem *self, NMDevice *device);
|
||||
|
||||
gboolean (*owns_port) (NMModem *self, const char *iface);
|
||||
|
||||
|
|
@ -225,6 +225,15 @@ gboolean nm_modem_get_secrets (NMModem *modem,
|
|||
|
||||
void nm_modem_deactivate (NMModem *modem, NMDevice *device);
|
||||
|
||||
void nm_modem_deactivate_async (NMModem *self,
|
||||
NMDevice *device,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean nm_modem_deactivate_async_finish (NMModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
void nm_modem_device_state_changed (NMModem *modem,
|
||||
NMDeviceState new_state,
|
||||
NMDeviceState old_state,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ global:
|
|||
nm_modem_check_connection_compatible;
|
||||
nm_modem_complete_connection;
|
||||
nm_modem_deactivate;
|
||||
nm_modem_deactivate_async;
|
||||
nm_modem_deactivate_async_finish;
|
||||
nm_modem_device_state_changed;
|
||||
nm_modem_get_capabilities;
|
||||
nm_modem_get_control_port;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue