diff options
Diffstat (limited to 'src/devices/wwan/nm-device-modem.c')
| -rw-r--r-- | src/devices/wwan/nm-device-modem.c | 207 |
1 files changed, 157 insertions, 50 deletions
diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index 678f7795..f681e59c 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -20,20 +20,22 @@ #include "config.h" +#include <string.h> #include <glib.h> #include "nm-device-modem.h" #include "nm-modem.h" -#include "nm-modem-old.h" #include "nm-device-private.h" #include "nm-rfkill-manager.h" #include "nm-logging.h" #include "nm-dbus-manager.h" #include "nm-settings-connection.h" - -#if WITH_MODEM_MANAGER_1 #include "nm-modem-broadband.h" -#endif +#include "NetworkManagerUtils.h" +#include "nm-core-internal.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceModem); G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE) @@ -91,7 +93,8 @@ modem_prepare_result (NMModem *modem, NMDeviceStateReason reason, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); + NMDeviceModem *self = NM_DEVICE_MODEM (user_data); + NMDevice *device = NM_DEVICE (self); NMDeviceState state; state = nm_device_get_state (device); @@ -106,8 +109,7 @@ modem_prepare_result (NMModem *modem, * the SIM if the incorrect PIN continues to be used. */ g_object_set (G_OBJECT (device), NM_DEVICE_AUTOCONNECT, FALSE, NULL); - nm_log_info (LOGD_MB, "(%s): disabling autoconnect due to failed SIM PIN", - nm_device_get_iface (device)); + _LOGI (LOGD_MB, "disabling autoconnect due to failed SIM PIN"); } nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); @@ -147,33 +149,110 @@ modem_auth_result (NMModem *modem, GError *error, gpointer user_data) } static void -modem_ip4_config_result (NMModem *self, +modem_ip4_config_result (NMModem *modem, NMIP4Config *config, GError *error, gpointer user_data) { - NMDevice *device = NM_DEVICE (user_data); + NMDeviceModem *self = NM_DEVICE_MODEM (user_data); + NMDevice *device = NM_DEVICE (self); g_return_if_fail (nm_device_activate_ip4_state_in_conf (device) == TRUE); if (error) { - nm_log_warn (LOGD_MB | LOGD_IP4, "retrieving IP4 configuration failed: (%d) %s", - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); + _LOGW (LOGD_MB | LOGD_IP4, "retrieving IPv4 configuration failed: (%d) %s", + error->code, error->message ? error->message : "(unknown)"); nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else - nm_device_activate_schedule_ip4_config_result (device, config); + } else { + nm_device_set_wwan_ip4_config (device, config); + nm_device_activate_schedule_ip4_config_result (device, NULL); + } +} + +static void +modem_ip6_config_result (NMModem *modem, + NMIP6Config *config, + gboolean do_slaac, + GError *error, + gpointer user_data) +{ + NMDeviceModem *self = NM_DEVICE_MODEM (user_data); + NMDevice *device = NM_DEVICE (self); + NMActStageReturn ret; + NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; + NMIP6Config *ignored = NULL; + gboolean got_config = !!config; + + g_return_if_fail (nm_device_activate_ip6_state_in_conf (device) == TRUE); + + if (error) { + _LOGW (LOGD_MB | LOGD_IP6, "retrieving IPv6 configuration failed: (%d) %s", + error->code, error->message ? error->message : "(unknown)"); + + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return; + } + + /* Re-enable IPv6 on the interface */ + nm_device_ipv6_sysctl_set (device, "disable_ipv6", "0"); + + if (config) + nm_device_set_wwan_ip6_config (device, config); + + if (do_slaac == FALSE) { + if (got_config) + nm_device_activate_schedule_ip6_config_result (device); + else { + _LOGW (LOGD_MB | LOGD_IP6, "retrieving IPv6 configuration failed: SLAAC not requested and no addresses"); + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + } + return; + } + + /* Start SLAAC now that we have a link-local address from the modem */ + ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage3_ip6_config_start (device, &ignored, &reason); + g_assert (ignored == NULL); + switch (ret) { + case NM_ACT_STAGE_RETURN_FAILURE: + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason); + break; + case NM_ACT_STAGE_RETURN_STOP: + /* all done */ + nm_device_activate_schedule_ip6_config_result (device); + break; + case NM_ACT_STAGE_RETURN_POSTPONE: + /* let SLAAC run */ + break; + default: + /* Should never get here since we've assured that the IPv6 method + * will either be "auto" or "ignored" when starting IPv6 configuration. + */ + g_assert_not_reached (); + } } static void data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); + const char *old = nm_device_get_ip_iface (self); + const char *new = nm_modem_get_data_port (modem); + gboolean changed = FALSE; + + if (new && g_strcmp0 (new, old)) + changed = TRUE; /* We set the IP iface in the device as soon as we know it, so that we * properly ifup it if needed */ - nm_device_set_ip_iface (self, nm_modem_get_data_port (modem)); + nm_device_set_ip_iface (self, new); + + /* Disable IPv6 immediately on the interface since NM handles IPv6 + * internally, and leaving it enabled could allow the kernel's IPv6 + * RA handling code to run before NM is ready. + */ + if (changed) + nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); } static void @@ -258,6 +337,7 @@ device_state_changed (NMDevice *device, NMDeviceState old_state, NMDeviceStateReason reason) { + NMDeviceModem *self = NM_DEVICE_MODEM (device); NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); NMConnection *connection = nm_device_get_connection (device); @@ -266,9 +346,8 @@ device_state_changed (NMDevice *device, if (new_state == NM_DEVICE_STATE_UNAVAILABLE && old_state < NM_DEVICE_STATE_UNAVAILABLE) { /* Log initial modem state */ - nm_log_info (LOGD_MB, "(%s): modem state '%s'", - nm_device_get_iface (device), - nm_modem_state_to_string (nm_modem_get_state (priv->modem))); + _LOGI (LOGD_MB, "modem state '%s'", + nm_modem_state_to_string (nm_modem_get_state (priv->modem))); } nm_modem_device_state_changed (priv->modem, new_state, old_state, reason); @@ -294,10 +373,10 @@ device_state_changed (NMDevice *device, } } -static guint -get_hw_address_length (NMDevice *device, gboolean *out_permanent) +static guint32 +get_generic_capabilities (NMDevice *device) { - return 0; + return NM_DEVICE_CAP_IS_NON_KERNEL; } static gboolean @@ -404,11 +483,24 @@ act_stage3_ip6_config_start (NMDevice *device, NMDeviceStateReason *reason) { return nm_modem_stage3_ip6_config_start (NM_DEVICE_MODEM_GET_PRIVATE (device)->modem, - device, - NM_DEVICE_CLASS (nm_device_modem_parent_class), + nm_device_get_act_request (device), reason); } +static gboolean +get_ip_iface_identifier (NMDevice *device, NMUtilsIPv6IfaceId *out_iid) +{ + NMDeviceModem *self = NM_DEVICE_MODEM (device); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); + gboolean success; + + g_return_val_if_fail (priv->modem, FALSE); + success = nm_modem_get_iid (priv->modem, out_iid); + if (!success) + success = NM_DEVICE_CLASS (nm_device_modem_parent_class)->get_ip_iface_identifier (device, out_iid); + return success; +} + /*****************************************************************************/ static gboolean @@ -444,23 +536,22 @@ set_enabled (NMDevice *device, gboolean enabled) } static gboolean -is_available (NMDevice *dev) +is_available (NMDevice *device) { - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (dev); + NMDeviceModem *self = NM_DEVICE_MODEM (device); + NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); NMModemState modem_state; if (!priv->rf_enabled) { - nm_log_dbg (LOGD_MB, "(%s): not available because WWAN airplane mode is on", - nm_device_get_iface (dev)); + _LOGD (LOGD_MB, "not available because WWAN airplane mode is on"); return FALSE; } g_assert (priv->modem); modem_state = nm_modem_get_state (priv->modem); if (modem_state <= NM_MODEM_STATE_INITIALIZING) { - nm_log_dbg (LOGD_MB, "(%s): not available because modem is not ready (%s)", - nm_device_get_iface (dev), - nm_modem_state_to_string (modem_state)); + _LOGD (LOGD_MB, "not available because modem is not ready (%s)", + nm_modem_state_to_string (modem_state)); return FALSE; } @@ -496,8 +587,10 @@ nm_device_modem_new (NMModem *modem) /* If the data port is known, set it as the IP interface immediately */ data_port = nm_modem_get_data_port (modem); - if (data_port) + if (data_port) { nm_device_set_ip_iface (device, data_port); + nm_device_ipv6_sysctl_set (device, "disable_ipv6", "1"); + } return device; } @@ -508,6 +601,18 @@ nm_device_modem_init (NMDeviceModem *self) } static void +constructed (GObject *object) +{ + G_OBJECT_CLASS (nm_device_modem_parent_class)->constructed (object); + + /* DHCP is always done by the modem firmware, not by the network, and + * by the time we get around to DHCP the firmware should already know + * the IP addressing details. So the DHCP timeout can be much shorter. + */ + nm_device_set_dhcp_timeout (NM_DEVICE (object), 15); +} + +static void set_modem (NMDeviceModem *self, NMModem *modem) { NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (self); @@ -519,6 +624,7 @@ set_modem (NMDeviceModem *self, NMModem *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_IP6_CONFIG_RESULT, G_CALLBACK (modem_ip6_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, NM_MODEM_STATE_CHANGED, G_CALLBACK (modem_state_cb), self); @@ -599,8 +705,9 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; + object_class->constructed = constructed; - device_class->get_hw_address_length = get_hw_address_length; + device_class->get_generic_capabilities = get_generic_capabilities; device_class->check_connection_compatible = check_connection_compatible; device_class->check_connection_available = check_connection_available; device_class->complete_connection = complete_connection; @@ -614,31 +721,31 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) device_class->set_enabled = set_enabled; device_class->owns_iface = owns_iface; device_class->is_available = is_available; + device_class->get_ip_iface_identifier = get_ip_iface_identifier; device_class->state_changed = device_state_changed; /* Properties */ g_object_class_install_property (object_class, PROP_MODEM, - g_param_spec_object (NM_DEVICE_MODEM_MODEM, - "Modem", - "Modem", + g_param_spec_object (NM_DEVICE_MODEM_MODEM, "", "", NM_TYPE_MODEM, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, PROP_CAPABILITIES, - g_param_spec_uint (NM_DEVICE_MODEM_CAPABILITIES, - "Modem Capabilities", - "Modem Capabilities", - 0, G_MAXUINT32, NM_DEVICE_MODEM_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_object_class_install_property (object_class, PROP_CURRENT_CAPABILITIES, - g_param_spec_uint (NM_DEVICE_MODEM_CURRENT_CAPABILITIES, - "Current modem Capabilities", - "Current modem Capabilities", - 0, G_MAXUINT32, NM_DEVICE_MODEM_CAPABILITY_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_CAPABILITIES, + g_param_spec_uint (NM_DEVICE_MODEM_CAPABILITIES, "", "", + 0, G_MAXUINT32, NM_DEVICE_MODEM_CAPABILITY_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_CURRENT_CAPABILITIES, + g_param_spec_uint (NM_DEVICE_MODEM_CURRENT_CAPABILITIES, "", "", + 0, G_MAXUINT32, NM_DEVICE_MODEM_CAPABILITY_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), G_TYPE_FROM_CLASS (mclass), |