diff options
Diffstat (limited to 'src/devices/wwan')
| -rw-r--r-- | src/devices/wwan/libnm-wwan.ver | 41 | ||||
| -rw-r--r-- | src/devices/wwan/meson.build | 92 | ||||
| -rw-r--r-- | src/devices/wwan/nm-device-modem.c | 957 | ||||
| -rw-r--r-- | src/devices/wwan/nm-device-modem.h | 36 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-broadband.c | 1625 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-broadband.h | 29 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-manager.c | 876 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-manager.h | 45 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-ofono.c | 1239 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem-ofono.h | 35 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem.c | 2037 | ||||
| -rw-r--r-- | src/devices/wwan/nm-modem.h | 269 | ||||
| -rw-r--r-- | src/devices/wwan/nm-service-providers.c | 455 | ||||
| -rw-r--r-- | src/devices/wwan/nm-service-providers.h | 24 | ||||
| -rw-r--r-- | src/devices/wwan/nm-wwan-factory.c | 146 | ||||
| -rw-r--r-- | src/devices/wwan/tests/test-service-providers.c | 130 | ||||
| -rw-r--r-- | src/devices/wwan/tests/test-service-providers.xml | 73 |
17 files changed, 0 insertions, 8109 deletions
diff --git a/src/devices/wwan/libnm-wwan.ver b/src/devices/wwan/libnm-wwan.ver deleted file mode 100644 index c368a590..00000000 --- a/src/devices/wwan/libnm-wwan.ver +++ /dev/null @@ -1,41 +0,0 @@ -{ -global: - nm_modem_act_stage1_prepare; - nm_modem_act_stage2_config; - nm_modem_check_connection_compatible; - nm_modem_claim; - nm_modem_complete_connection; - nm_modem_deactivate; - nm_modem_deactivate_async; - nm_modem_device_state_changed; - nm_modem_get_apn; - nm_modem_get_capabilities; - nm_modem_get_configured_mtu; - nm_modem_get_control_port; - nm_modem_get_device_id; - nm_modem_get_driver; - nm_modem_get_iid; - nm_modem_get_ip_ifindex; - nm_modem_get_operator_code; - nm_modem_get_path; - nm_modem_get_secrets; - nm_modem_get_state; - nm_modem_get_type; - nm_modem_get_uid; - nm_modem_ip4_pre_commit; - nm_modem_is_claimed; - nm_modem_manager_get; - nm_modem_manager_get_modems; - nm_modem_manager_get_type; - nm_modem_manager_name_owner_get; - nm_modem_manager_name_owner_ref; - nm_modem_manager_name_owner_unref; - nm_modem_owns_port; - nm_modem_set_mm_enabled; - nm_modem_stage3_ip4_config_start; - nm_modem_stage3_ip6_config_start; - nm_modem_state_to_string; - nm_modem_unclaim; -local: - *; -}; diff --git a/src/devices/wwan/meson.build b/src/devices/wwan/meson.build deleted file mode 100644 index 97252edc..00000000 --- a/src/devices/wwan/meson.build +++ /dev/null @@ -1,92 +0,0 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -nm_service_providers_source = files('nm-service-providers.c') - -sources = nm_service_providers_source + files( - 'nm-modem-broadband.c', - 'nm-modem.c', - 'nm-modem-manager.c', -) - -deps = [ - daemon_nm_default_dep, - libsystemd_dep, - mm_glib_dep, -] - -if enable_ofono - sources += files('nm-modem-ofono.c') -endif - -linker_script = join_paths(meson.current_source_dir(), 'libnm-wwan.ver') - -libnm_wwan = shared_module( - 'nm-wwan', - sources: sources, - dependencies: deps, - c_args: daemon_c_flags, - link_args: '-Wl,--version-script,@0@'.format(linker_script), - link_depends: linker_script, - install: true, - install_dir: nm_plugindir, -) - -wwan_inc = include_directories('.') - -libnm_wwan_dep = declare_dependency( - include_directories: wwan_inc, - link_with: libnm_wwan, -) - -core_plugins += libnm_wwan - -test( - 'check-wwan', - check_exports, - args: [libnm_wwan.full_path(), linker_script], -) - -sources = files( - 'nm-device-modem.c', - 'nm-wwan-factory.c', -) - -libnm_device_plugin_wwan = shared_module( - 'nm-device-plugin-wwan', - sources: sources, - dependencies: deps, - c_args: daemon_c_flags, - link_with: libnm_wwan, - link_args: ldflags_linker_script_devices, - link_depends: linker_script_devices, - install: true, - install_dir: nm_plugindir, - install_rpath: nm_plugindir, -) - -core_plugins += libnm_device_plugin_wwan - -run_target( - 'check-local-devices-wwan', - command: [check_exports, libnm_device_plugin_wwan.full_path(), linker_script_devices], - depends: libnm_device_plugin_wwan, -) - -if enable_tests - test_unit = 'test-service-providers' - - exe = executable( - test_unit, - ['tests/' + test_unit + '.c'] + nm_service_providers_source, - include_directories: wwan_inc, - dependencies: libnetwork_manager_test_dep, - c_args: test_c_flags, - ) - - test( - 'wwan/' + test_unit, - test_script, - timeout: default_test_timeout, - args: test_args + [exe.full_path()], - ) -endif diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c deleted file mode 100644 index f77de85a..00000000 --- a/src/devices/wwan/nm-device-modem.c +++ /dev/null @@ -1,957 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2019 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-modem.h" - -#include "nm-modem.h" -#include "nm-ip4-config.h" -#include "devices/nm-device-private.h" -#include "nm-rfkill-manager.h" -#include "settings/nm-settings-connection.h" -#include "nm-modem-broadband.h" -#include "NetworkManagerUtils.h" -#include "nm-core-internal.h" - -#include "devices/nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceModem); - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceModem, - PROP_MODEM, - PROP_CAPABILITIES, - PROP_CURRENT_CAPABILITIES, - PROP_DEVICE_ID, - PROP_OPERATOR_CODE, - PROP_APN, ); - -typedef struct { - NMModem * modem; - NMDeviceModemCapabilities caps; - NMDeviceModemCapabilities current_caps; - char * device_id; - char * operator_code; - char * apn; - bool rf_enabled : 1; - NMDeviceStageState stage1_state : 3; -} NMDeviceModemPrivate; - -struct _NMDeviceModem { - NMDevice parent; - NMDeviceModemPrivate _priv; -}; - -struct _NMDeviceModemClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE) - -#define NM_DEVICE_MODEM_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDeviceModem, NM_IS_DEVICE_MODEM, NMDevice) - -/*****************************************************************************/ - -static void -ppp_failed(NMModem *modem, guint i_reason, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDeviceStateReason reason = i_reason; - - switch (nm_device_get_state(device)) { - case NM_DEVICE_STATE_PREPARE: - case NM_DEVICE_STATE_CONFIG: - case NM_DEVICE_STATE_NEED_AUTH: - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, reason); - break; - case NM_DEVICE_STATE_IP_CONFIG: - case NM_DEVICE_STATE_IP_CHECK: - case NM_DEVICE_STATE_SECONDARIES: - case NM_DEVICE_STATE_ACTIVATED: - if (nm_device_activate_ip4_state_in_conf(device)) - nm_device_activate_schedule_ip_config_timeout(device, AF_INET); - else if (nm_device_activate_ip6_state_in_conf(device)) - nm_device_activate_schedule_ip_config_timeout(device, AF_INET6); - else if (nm_device_activate_ip4_state_done(device)) { - nm_device_ip_method_failed(device, - AF_INET, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else if (nm_device_activate_ip6_state_done(device)) { - nm_device_ip_method_failed(device, - AF_INET6, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else { - _LOGW(LOGD_MB, - "PPP failure in unexpected state %u", - (guint) nm_device_get_state(device)); - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } - break; - default: - break; - } -} - -static void -modem_prepare_result(NMModem *modem, gboolean success, guint i_reason, gpointer user_data) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - NMDevice * device = NM_DEVICE(self); - NMDeviceStateReason reason = i_reason; - - if (nm_device_get_state(device) != NM_DEVICE_STATE_PREPARE - || priv->stage1_state != NM_DEVICE_STAGE_STATE_PENDING) { - nm_assert_not_reached(); - success = FALSE; - } - - if (!success) { - /* There are several reasons to block autoconnection at device level: - * - * - Wrong SIM-PIN: The device won't autoconnect because it doesn't make sense - * to retry the connection with the same PIN. This error also makes autoconnection - * blocked at settings level, so not even a modem unplug and replug will allow - * autoconnection again. It is somewhat redundant to block autoconnection at - * both device and setting level really. - * - * - SIM wrong or not inserted: If the modem is reporting a SIM not inserted error, - * we can block autoconnection at device level, so that if the same device is - * unplugged and replugged with a SIM (or if a SIM hotplug event happens in MM, - * recreating the device completely), we can try the autoconnection again. - * - * - Modem initialization failed: For some reason unknown to NM, the modem wasn't - * initialized correctly, which leads to an unusable device. A device unplug and - * replug may solve the issue, so make it a device-level autoconnection blocking - * reason. - */ - switch (nm_device_state_reason_check(reason)) { - case NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED: - case NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED: - case NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: - nm_device_autoconnect_blocked_set(device, NM_DEVICE_AUTOCONNECT_BLOCKED_WRONG_PIN); - break; - case NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED: - case NM_DEVICE_STATE_REASON_GSM_SIM_WRONG: - nm_device_autoconnect_blocked_set(device, NM_DEVICE_AUTOCONNECT_BLOCKED_SIM_MISSING); - break; - case NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED: - nm_device_autoconnect_blocked_set(device, NM_DEVICE_AUTOCONNECT_BLOCKED_INIT_FAILED); - break; - default: - break; - } - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, reason); - return; - } - - priv->stage1_state = NM_DEVICE_STAGE_STATE_COMPLETED; - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -modem_auth_requested(NMModem *modem, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - /* Auth requests (PIN, PAP/CHAP passwords, etc) only get handled - * during activation. - */ - if (!nm_device_is_activating(device)) - return; - - nm_device_state_changed(device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); -} - -static void -modem_auth_result(NMModem *modem, GError *error, gpointer user_data) -{ - NMDevice * device = NM_DEVICE(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - g_return_if_fail(nm_device_get_state(device) == NM_DEVICE_STATE_NEED_AUTH); - - if (error) { - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NO_SECRETS); - return; - } - - priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT; - nm_device_activate_schedule_stage1_device_prepare(device, FALSE); -} - -static void -modem_ip4_config_result(NMModem *modem, NMIP4Config *config, GError *error, gpointer 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) { - _LOGW(LOGD_MB | LOGD_IP4, "retrieving IPv4 configuration failed: %s", error->message); - nm_device_ip_method_failed(device, AF_INET, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else { - nm_device_set_dev2_ip_config(device, AF_INET, NM_IP_CONFIG_CAST(config)); - nm_device_activate_schedule_ip_config_result(device, AF_INET, 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 failure_reason = NM_DEVICE_STATE_REASON_NONE; - gs_unref_object 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: %s", error->message); - nm_device_ip_method_failed(device, AF_INET6, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - /* Re-enable IPv6 on the interface */ - nm_device_sysctl_ip_conf_set(device, AF_INET6, "disable_ipv6", "0"); - - if (config) - nm_device_set_dev2_ip_config(device, AF_INET6, NM_IP_CONFIG_CAST(config)); - - if (do_slaac == FALSE) { - if (got_config) - nm_device_activate_schedule_ip_config_result(device, AF_INET6, NULL); - else { - _LOGW(LOGD_MB | LOGD_IP6, - "retrieving IPv6 configuration failed: SLAAC not requested and no addresses"); - nm_device_ip_method_failed(device, - AF_INET6, - 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_ip_config_start(device, AF_INET6, (gpointer *) &ignored, &failure_reason); - - nm_assert(ignored == NULL); - - switch (ret) { - case NM_ACT_STAGE_RETURN_FAILURE: - nm_device_ip_method_failed(device, AF_INET6, failure_reason); - break; - case NM_ACT_STAGE_RETURN_IP_FAIL: - /* all done */ - nm_device_activate_schedule_ip_config_result(device, AF_INET6, NULL); - 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. - */ - nm_assert_not_reached(); - } -} - -static void -ip_ifindex_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDevice *device = NM_DEVICE(user_data); - - if (!nm_device_is_activating(device)) - return; - - if (!nm_device_set_ip_ifindex(device, nm_modem_get_ip_ifindex(modem))) { - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return; - } - - /* 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. - */ - nm_device_sysctl_ip_conf_set(device, AF_INET6, "disable_ipv6", "1"); -} - -static void -operator_code_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - const char * operator_code = nm_modem_get_operator_code(modem); - - if (g_strcmp0(priv->operator_code, operator_code) != 0) { - g_free(priv->operator_code); - priv->operator_code = g_strdup(operator_code); - _notify(self, PROP_OPERATOR_CODE); - } -} - -static void -apn_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - const char * apn = nm_modem_get_apn(modem); - - if (g_strcmp0(priv->apn, apn) != 0) { - g_free(priv->apn); - priv->apn = g_strdup(apn); - _notify(self, PROP_APN); - } -} - -static void -ids_changed_cb(NMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - nm_device_recheck_available_connections(NM_DEVICE(user_data)); -} - -static void -modem_state_cb(NMModem *modem, int new_state_i, int old_state_i, gpointer user_data) -{ - NMModemState new_state = new_state_i; - NMModemState old_state = old_state_i; - NMDevice * device = NM_DEVICE(user_data); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - NMDeviceState dev_state = nm_device_get_state(device); - - if (new_state <= NM_MODEM_STATE_DISABLING && old_state > NM_MODEM_STATE_DISABLING - && priv->rf_enabled) { - /* Called when the ModemManager modem enabled state is changed externally - * to NetworkManager (eg something using MM's D-Bus API directly). - */ - if (nm_device_is_activating(device) || dev_state == NM_DEVICE_STATE_ACTIVATED) { - /* user-initiated action, hence DISCONNECTED not FAILED */ - nm_device_state_changed(device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - return; - } - } - - if (new_state < NM_MODEM_STATE_CONNECTING && old_state >= NM_MODEM_STATE_CONNECTING - && dev_state >= NM_DEVICE_STATE_NEED_AUTH && dev_state <= NM_DEVICE_STATE_ACTIVATED) { - /* Fail the device if the modem disconnects unexpectedly while the - * device is activating/activated. */ - nm_device_state_changed(device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; - } - - if (new_state > NM_MODEM_STATE_LOCKED && old_state == NM_MODEM_STATE_LOCKED) { - /* If the modem is now unlocked, enable/disable it according to the - * device's enabled/disabled state. - */ - nm_modem_set_mm_enabled(priv->modem, priv->rf_enabled); - - if (dev_state == NM_DEVICE_STATE_NEED_AUTH) { - /* The modem was unlocked externally to NetworkManager, - * deactivate so the default connection can be - * automatically activated again */ - nm_device_state_changed(device, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_MODEM_AVAILABLE); - } - - /* Now allow connections without a PIN to be available */ - nm_device_recheck_available_connections(device); - } - - nm_device_queue_recheck_available(device, - NM_DEVICE_STATE_REASON_MODEM_AVAILABLE, - NM_DEVICE_STATE_REASON_MODEM_FAILED); -} - -static void -modem_removed_cb(NMModem *modem, gpointer user_data) -{ - g_signal_emit_by_name(NM_DEVICE(user_data), NM_DEVICE_REMOVED); -} - -/*****************************************************************************/ - -static gboolean -owns_iface(NMDevice *device, const char *iface) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - g_return_val_if_fail(priv->modem, FALSE); - - return nm_modem_owns_port(priv->modem, iface); -} - -/*****************************************************************************/ - -static void -device_state_changed(NMDevice * device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - - g_return_if_fail(priv->modem); - - if (new_state == NM_DEVICE_STATE_UNAVAILABLE && old_state < NM_DEVICE_STATE_UNAVAILABLE) { - /* Log initial modem state */ - _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); -} - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *device) -{ - return NM_DEVICE_CAP_IS_NON_KERNEL; -} - -static const char * -get_type_description(NMDevice *device) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - if (NM_FLAGS_HAS(priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS)) - return "gsm"; - if (NM_FLAGS_HAS(priv->current_caps, NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO)) - return "cdma"; - return NM_DEVICE_CLASS(nm_device_modem_parent_class)->get_type_description(device); -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - GError *local = NULL; - - if (!NM_DEVICE_CLASS(nm_device_modem_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (!nm_modem_check_connection_compatible(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem, - connection, - error ? &local : NULL)) { - if (error) { - g_set_error(error, - NM_UTILS_ERROR, - g_error_matches(local, - NM_UTILS_ERROR, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE) - ? NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE - : NM_UTILS_ERROR_UNKNOWN, - "modem is incompatible with connection: %s", - local->message); - g_error_free(local); - } - return FALSE; - } - return TRUE; -} - -static gboolean -check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - NMModemState state; - - if (!priv->rf_enabled) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "RFKILL for modem enabled"); - return FALSE; - } - - if (!priv->modem) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem not available"); - return FALSE; - } - - state = nm_modem_get_state(priv->modem); - if (state <= NM_MODEM_STATE_INITIALIZING) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem not initialized"); - return FALSE; - } - - if (state == NM_MODEM_STATE_LOCKED) { - if (!nm_connection_get_setting_gsm(connection)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem is locked without pin available"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - return nm_modem_complete_connection(priv->modem, - nm_device_get_iface(device), - connection, - existing_connections, - error); -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - nm_modem_deactivate(priv->modem, device); - priv->stage1_state = NM_DEVICE_STAGE_STATE_INIT; -} - -/*****************************************************************************/ - -static void -modem_deactivate_async_cb(NMModem *modem, GError *error, gpointer user_data) -{ - gs_unref_object NMDevice * self = NULL; - NMDeviceDeactivateCallback callback; - gpointer callback_user_data; - - nm_utils_user_data_unpack(user_data, &self, &callback, &callback_user_data); - callback(self, error, callback_user_data); -} - -static void -deactivate_async(NMDevice * self, - GCancellable * cancellable, - NMDeviceDeactivateCallback callback, - gpointer user_data) -{ - nm_assert(G_IS_CANCELLABLE(cancellable)); - nm_assert(callback); - - nm_modem_deactivate_async(NM_DEVICE_MODEM_GET_PRIVATE(self)->modem, - self, - cancellable, - modem_deactivate_async_cb, - nm_utils_user_data_pack(g_object_ref(self), callback, user_data)); -} - -/*****************************************************************************/ - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - NMActRequest * req; - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - if (priv->stage1_state == NM_DEVICE_STAGE_STATE_INIT) { - priv->stage1_state = NM_DEVICE_STAGE_STATE_PENDING; - return nm_modem_act_stage1_prepare(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem, - req, - out_failure_reason); - } - - if (priv->stage1_state == NM_DEVICE_STAGE_STATE_PENDING) - return NM_ACT_STAGE_RETURN_POSTPONE; - - nm_assert(priv->stage1_state == NM_DEVICE_STAGE_STATE_COMPLETED); - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - nm_modem_act_stage2_config(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem); - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage3_ip_config_start(NMDevice * device, - int addr_family, - gpointer * out_config, - NMDeviceStateReason *out_failure_reason) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - - nm_assert_addr_family(addr_family); - - if (addr_family == AF_INET) { - return nm_modem_stage3_ip4_config_start(priv->modem, - device, - NM_DEVICE_CLASS(nm_device_modem_parent_class), - out_failure_reason); - } else { - return nm_modem_stage3_ip6_config_start(priv->modem, device, out_failure_reason); - } -} - -static void -ip4_config_pre_commit(NMDevice *device, NMIP4Config *config) -{ - nm_modem_ip4_pre_commit(NM_DEVICE_MODEM_GET_PRIVATE(device)->modem, device, config); -} - -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 -get_enabled(NMDevice *device) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(device); - NMModemState modem_state = nm_modem_get_state(priv->modem); - - return priv->rf_enabled && (modem_state >= NM_MODEM_STATE_LOCKED); -} - -static void -set_enabled(NMDevice *device, gboolean enabled) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - - /* Called only by the Manager in response to rfkill switch changes or - * global user WWAN enable/disable preference changes. - */ - priv->rf_enabled = enabled; - - if (priv->modem) { - /* Sync the ModemManager modem enabled/disabled with rfkill/user preference */ - nm_modem_set_mm_enabled(priv->modem, enabled); - } - - if (enabled == FALSE) { - nm_device_state_changed(device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_NONE); - } -} - -static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - NMDeviceModem * self = NM_DEVICE_MODEM(device); - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - NMModemState modem_state; - - if (!priv->rf_enabled) - return FALSE; - - g_assert(priv->modem); - modem_state = nm_modem_get_state(priv->modem); - if (modem_state <= NM_MODEM_STATE_INITIALIZING) - return FALSE; - - return TRUE; -} - -/*****************************************************************************/ - -static void -set_modem(NMDeviceModem *self, NMModem *modem) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(self); - - g_return_if_fail(modem != NULL); - - priv->modem = nm_modem_claim(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); - g_signal_connect(modem, NM_MODEM_REMOVED, G_CALLBACK(modem_removed_cb), self); - - g_signal_connect(modem, - "notify::" NM_MODEM_IP_IFINDEX, - G_CALLBACK(ip_ifindex_changed_cb), - self); - g_signal_connect(modem, "notify::" NM_MODEM_DEVICE_ID, G_CALLBACK(ids_changed_cb), self); - g_signal_connect(modem, "notify::" NM_MODEM_SIM_ID, G_CALLBACK(ids_changed_cb), self); - g_signal_connect(modem, "notify::" NM_MODEM_SIM_OPERATOR_ID, G_CALLBACK(ids_changed_cb), self); - g_signal_connect(modem, - "notify::" NM_MODEM_OPERATOR_CODE, - G_CALLBACK(operator_code_changed_cb), - self); - g_signal_connect(modem, "notify::" NM_MODEM_APN, G_CALLBACK(apn_changed_cb), self); -} - -static guint32 -get_dhcp_timeout_for_device(NMDevice *device, int addr_family) -{ - /* 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. - */ - return 15; -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_MODEM: - g_value_set_object(value, priv->modem); - break; - case PROP_CAPABILITIES: - g_value_set_uint(value, priv->caps); - break; - case PROP_CURRENT_CAPABILITIES: - g_value_set_uint(value, priv->current_caps); - break; - case PROP_DEVICE_ID: - g_value_set_string(value, priv->device_id); - break; - case PROP_OPERATOR_CODE: - g_value_set_string(value, priv->operator_code); - break; - case PROP_APN: - g_value_set_string(value, priv->apn); - 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) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(object); - - switch (prop_id) { - case PROP_MODEM: - /* construct-only */ - set_modem(NM_DEVICE_MODEM(object), g_value_get_object(value)); - break; - case PROP_CAPABILITIES: - priv->caps = g_value_get_uint(value); - break; - case PROP_CURRENT_CAPABILITIES: - priv->current_caps = g_value_get_uint(value); - break; - case PROP_DEVICE_ID: - /* construct-only */ - priv->device_id = g_value_dup_string(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_device_modem_init(NMDeviceModem *self) -{} - -NMDevice * -nm_device_modem_new(NMModem *modem) -{ - NMDeviceModemCapabilities caps = NM_DEVICE_MODEM_CAPABILITY_NONE; - NMDeviceModemCapabilities current_caps = NM_DEVICE_MODEM_CAPABILITY_NONE; - - g_return_val_if_fail(NM_IS_MODEM(modem), NULL); - - /* Load capabilities */ - nm_modem_get_capabilities(modem, &caps, ¤t_caps); - - return g_object_new(NM_TYPE_DEVICE_MODEM, - NM_DEVICE_UDI, - nm_modem_get_path(modem), - NM_DEVICE_IFACE, - nm_modem_get_uid(modem), - NM_DEVICE_DRIVER, - nm_modem_get_driver(modem), - NM_DEVICE_TYPE_DESC, - "Broadband", - NM_DEVICE_DEVICE_TYPE, - NM_DEVICE_TYPE_MODEM, - NM_DEVICE_RFKILL_TYPE, - RFKILL_TYPE_WWAN, - NM_DEVICE_MODEM_MODEM, - modem, - NM_DEVICE_MODEM_CAPABILITIES, - caps, - NM_DEVICE_MODEM_CURRENT_CAPABILITIES, - current_caps, - NM_DEVICE_MODEM_DEVICE_ID, - nm_modem_get_device_id(modem), - NULL); -} - -static void -dispose(GObject *object) -{ - NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE(object); - - if (priv->modem) { - g_signal_handlers_disconnect_by_data(priv->modem, NM_DEVICE_MODEM(object)); - nm_clear_pointer(&priv->modem, nm_modem_unclaim); - } - - nm_clear_g_free(&priv->device_id); - nm_clear_g_free(&priv->operator_code); - nm_clear_g_free(&priv->apn); - - G_OBJECT_CLASS(nm_device_modem_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_modem = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_MODEM, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("ModemCapabilities", - "u", - NM_DEVICE_MODEM_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("CurrentCapabilities", - "u", - NM_DEVICE_MODEM_CURRENT_CAPABILITIES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("DeviceId", - "s", - NM_DEVICE_MODEM_DEVICE_ID), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("OperatorCode", - "s", - NM_DEVICE_MODEM_OPERATOR_CODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Apn", "s", NM_DEVICE_MODEM_APN), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_modem_class_init(NMDeviceModemClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_modem); - - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->get_type_description = get_type_description; - 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 = deactivate; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; - device_class->ip4_config_pre_commit = ip4_config_pre_commit; - device_class->get_enabled = get_enabled; - 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->get_configured_mtu = nm_modem_get_configured_mtu; - device_class->get_dhcp_timeout_for_device = get_dhcp_timeout_for_device; - - device_class->state_changed = device_state_changed; - - obj_properties[PROP_MODEM] = - g_param_spec_object(NM_DEVICE_MODEM_MODEM, - "", - "", - NM_TYPE_MODEM, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[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); - - obj_properties[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); - - obj_properties[PROP_DEVICE_ID] = - g_param_spec_string(NM_DEVICE_MODEM_DEVICE_ID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_OPERATOR_CODE] = - g_param_spec_string(NM_DEVICE_MODEM_OPERATOR_CODE, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_APN] = g_param_spec_string(NM_DEVICE_MODEM_APN, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/wwan/nm-device-modem.h b/src/devices/wwan/nm-device-modem.h deleted file mode 100644 index caabeb6c..00000000 --- a/src/devices/wwan/nm-device-modem.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_MODEM_H__ -#define __NETWORKMANAGER_DEVICE_MODEM_H__ - -#include "devices/nm-device.h" -#include "nm-modem.h" - -#define NM_TYPE_DEVICE_MODEM (nm_device_modem_get_type()) -#define NM_DEVICE_MODEM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModem)) -#define NM_DEVICE_MODEM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) -#define NM_IS_DEVICE_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DEVICE_MODEM)) -#define NM_IS_DEVICE_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DEVICE_MODEM)) -#define NM_DEVICE_MODEM_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DEVICE_MODEM, NMDeviceModemClass)) - -#define NM_DEVICE_MODEM_MODEM "modem" -#define NM_DEVICE_MODEM_CAPABILITIES "modem-capabilities" -#define NM_DEVICE_MODEM_CURRENT_CAPABILITIES "current-capabilities" -#define NM_DEVICE_MODEM_DEVICE_ID "device-id" -#define NM_DEVICE_MODEM_OPERATOR_CODE "operator-code" -#define NM_DEVICE_MODEM_APN "apn" - -typedef struct _NMDeviceModem NMDeviceModem; -typedef struct _NMDeviceModemClass NMDeviceModemClass; - -GType nm_device_modem_get_type(void); - -NMDevice *nm_device_modem_new(NMModem *modem); - -#endif /* __NETWORKMANAGER_DEVICE_MODEM_H__ */ diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c deleted file mode 100644 index 7b3a13a3..00000000 --- a/src/devices/wwan/nm-modem-broadband.c +++ /dev/null @@ -1,1625 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2012 Aleksander Morgado <aleksander@gnu.org> - */ - -#include "nm-default.h" - -#include "nm-modem-broadband.h" -#include "nm-service-providers.h" - -#include <arpa/inet.h> -#include <libmm-glib.h> - -#include "nm-core-internal.h" -#include "NetworkManagerUtils.h" -#include "devices/nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" - -#define NM_MODEM_BROADBAND_MODEM "modem" - -static gboolean -MODEM_CAPS_3GPP(MMModemCapability caps) -{ - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - /* MM_MODEM_CAPABILITY_LTE_ADVANCED is marked as deprecated since ModemManager 1.14.0. - * - * The flag probably was never used, it certainly isn't used since 1.14.0. - * - * Still, just to be sure, there is no harm in checking it here. Suppress the - * warning, it should have no bad effect. - */ - return NM_FLAGS_ANY(caps, - (MM_MODEM_CAPABILITY_GSM_UMTS | MM_MODEM_CAPABILITY_LTE - | MM_MODEM_CAPABILITY_LTE_ADVANCED)); - G_GNUC_END_IGNORE_DEPRECATIONS -} - -#define MODEM_CAPS_3GPP2(caps) (caps & (MM_MODEM_CAPABILITY_CDMA_EVDO)) - -/* Maximum time to keep the DBus call waiting for a connection result. - * This value is greater than the default timeout in ModemManager (180s since - * 1.16), so that whenever possible the timeout happens first there instead of - * in NetworkManager. */ -#define MODEM_CONNECT_TIMEOUT_SECS 200 - -/*****************************************************************************/ - -typedef enum { - CONNECT_STEP_FIRST, - CONNECT_STEP_WAIT_FOR_SIM, - CONNECT_STEP_UNLOCK, - CONNECT_STEP_WAIT_FOR_READY, - CONNECT_STEP_CONNECT, - CONNECT_STEP_LAST, -} ConnectStep; - -typedef struct { - NMModemBroadband *self; - ConnectStep step; - - MMModemCapability caps; - NMConnection * connection; - GCancellable * cancellable; - MMSimpleConnectProperties *connect_properties; - GArray * ip_types; - guint ip_types_i; - guint ip_type_tries; - GError * first_error; -} ConnectContext; - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_MODEM, ); - -typedef struct { - /* The modem object from dbus */ - MMObject *modem_object; - /* Per-interface objects */ - MMModem * modem_iface; - MMModem3gpp * modem_3gpp_iface; - MMModemSimple *simple_iface; - MMSim * sim_iface; - - /* Connection setup */ - ConnectContext *ctx; - - MMBearer * bearer; - MMBearerIpConfig *ipv4_config; - MMBearerIpConfig *ipv6_config; - - guint idle_id_ip4; - guint idle_id_ip6; - - guint32 pin_tries; -} NMModemBroadbandPrivate; - -struct _NMModemBroadband { - NMModem parent; - NMModemBroadbandPrivate _priv; -}; - -struct _NMModemBroadbandClass { - NMModemClass parent; -}; - -G_DEFINE_TYPE(NMModemBroadband, nm_modem_broadband, NM_TYPE_MODEM) - -#define NM_MODEM_BROADBAND_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMModemBroadband, NM_IS_MODEM_BROADBAND) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_MB -#define _NMLOG_PREFIX_NAME "modem-broadband" -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - \ - if (nm_logging_enabled(_level, (_NMLOG_DOMAIN))) { \ - NMModemBroadband *const __self = (self); \ - char __prefix_name[128]; \ - const char * __uid; \ - \ - _nm_log(_level, \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - ((__self && __self->_priv.ctx) \ - ? nm_connection_get_uuid(__self->_priv.ctx->connection) \ - : NULL), \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - (__self ? ({ \ - ((__uid = nm_modem_get_uid((NMModem *) __self)) \ - ? nm_sprintf_buf(__prefix_name, "[%s]", __uid) \ - : "(null)"); \ - }) \ - : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static NMDeviceStateReason -translate_mm_error(NMModemBroadband *self, GError *error) -{ - NMDeviceStateReason reason; - - g_return_val_if_fail(error != NULL, NM_DEVICE_STATE_REASON_UNKNOWN); - - if (g_error_matches(error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_CARRIER)) - reason = NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER; - else if (g_error_matches(error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_DIALTONE)) - reason = NM_DEVICE_STATE_REASON_MODEM_NO_DIAL_TONE; - else if (g_error_matches(error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_BUSY)) - reason = NM_DEVICE_STATE_REASON_MODEM_BUSY; - else if (g_error_matches(error, MM_CONNECTION_ERROR, MM_CONNECTION_ERROR_NO_ANSWER)) - reason = NM_DEVICE_STATE_REASON_MODEM_DIAL_TIMEOUT; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NETWORK_NOT_ALLOWED)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_DENIED; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NETWORK_TIMEOUT)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_TIMEOUT; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_NO_NETWORK)) - reason = NM_DEVICE_STATE_REASON_GSM_REGISTRATION_NOT_SEARCHING; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_SIM_NOT_INSERTED)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_NOT_INSERTED; - else if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_PIN_REQUIRED; - else if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_PUK_REQUIRED; - else if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_WRONG)) - reason = NM_DEVICE_STATE_REASON_GSM_SIM_WRONG; - else if (g_error_matches(error, - MM_MOBILE_EQUIPMENT_ERROR, - MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD)) - reason = NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT; - else { - /* unable to map the ModemManager error to a NM_DEVICE_STATE_REASON */ - _LOGD("unmapped error detected: '%s'", error->message); - reason = NM_DEVICE_STATE_REASON_UNKNOWN; - } - - return reason; -} - -/*****************************************************************************/ - -static void -get_capabilities(NMModem * _self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(_self); - MMModemCapability all_supported = MM_MODEM_CAPABILITY_NONE; - MMModemCapability *supported; - guint n_supported; - - /* For now, we don't care about the capability combinations, just merge all - * combinations in a single mask */ - if (mm_modem_get_supported_capabilities(self->_priv.modem_iface, &supported, &n_supported)) { - guint i; - - for (i = 0; i < n_supported; i++) - all_supported |= supported[i]; - - g_free(supported); - } - - *modem_caps = (NMDeviceModemCapabilities) all_supported; - *current_caps = - (NMDeviceModemCapabilities) mm_modem_get_current_capabilities(self->_priv.modem_iface); -} - -static gboolean -owns_port(NMModem *_self, const char *iface) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(_self); - const MMModemPortInfo *ports = NULL; - guint n_ports = 0, i; - - mm_modem_peek_ports(self->_priv.modem_iface, &ports, &n_ports); - for (i = 0; i < n_ports; i++) { - if (nm_streq0(iface, ports[i].name)) - return TRUE; - } - return FALSE; -} - -/*****************************************************************************/ - -static void -ask_for_pin(NMModemBroadband *self) -{ - guint32 tries; - - tries = self->_priv.pin_tries++; - nm_modem_get_secrets(NM_MODEM(self), - NM_SETTING_GSM_SETTING_NAME, - tries ? TRUE : FALSE, - NM_SETTING_GSM_PIN); -} - -static NMModemIPMethod -get_bearer_ip_method(MMBearerIpConfig *config) -{ - MMBearerIpMethod mm_method; - - mm_method = mm_bearer_ip_config_get_method(config); - if (mm_method == MM_BEARER_IP_METHOD_PPP) - return NM_MODEM_IP_METHOD_PPP; - else if (mm_method == MM_BEARER_IP_METHOD_STATIC) - return NM_MODEM_IP_METHOD_STATIC; - else if (mm_method == MM_BEARER_IP_METHOD_DHCP) - return NM_MODEM_IP_METHOD_AUTO; - return NM_MODEM_IP_METHOD_UNKNOWN; -} - -static MMSimpleConnectProperties * -create_cdma_connect_properties(NMConnection *connection) -{ - MMSimpleConnectProperties *properties; - - properties = mm_simple_connect_properties_new(); - -#if !MM_CHECK_VERSION(1, 9, 1) - { - NMSettingCdma *setting; - const char * str; - - setting = nm_connection_get_setting_cdma(connection); - str = nm_setting_cdma_get_number(setting); - if (str) - mm_simple_connect_properties_set_number(properties, str); - } -#endif - - return properties; -} - -static MMSimpleConnectProperties * -create_gsm_connect_properties(NMConnection *connection, - const char * apn, - const char * username, - const char * password) -{ - NMSettingGsm * setting; - NMSettingPpp * s_ppp; - MMSimpleConnectProperties *properties; - const char * str; - - setting = nm_connection_get_setting_gsm(connection); - - properties = mm_simple_connect_properties_new(); - - mm_simple_connect_properties_set_apn(properties, apn ?: ""); - if (username) - mm_simple_connect_properties_set_user(properties, username); - if (password) - mm_simple_connect_properties_set_password(properties, password); - - str = nm_setting_gsm_get_network_id(setting); - if (str) - mm_simple_connect_properties_set_operator_id(properties, str); - - str = nm_setting_gsm_get_pin(setting); - if (str) - mm_simple_connect_properties_set_pin(properties, str); - - /* Roaming */ - if (nm_setting_gsm_get_home_only(setting)) - mm_simple_connect_properties_set_allow_roaming(properties, FALSE); - - /* For IpMethod == STATIC or DHCP */ - s_ppp = nm_connection_get_setting_ppp(connection); - if (s_ppp) { - MMBearerAllowedAuth allowed_auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; - - if (nm_setting_ppp_get_noauth(s_ppp)) - allowed_auth = MM_BEARER_ALLOWED_AUTH_NONE; - if (!nm_setting_ppp_get_refuse_pap(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_PAP; - if (!nm_setting_ppp_get_refuse_chap(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_CHAP; - if (!nm_setting_ppp_get_refuse_mschap(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAP; - if (!nm_setting_ppp_get_refuse_mschapv2(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_MSCHAPV2; - if (!nm_setting_ppp_get_refuse_eap(s_ppp)) - allowed_auth |= MM_BEARER_ALLOWED_AUTH_EAP; - - mm_simple_connect_properties_set_allowed_auth(properties, allowed_auth); - } - - return properties; -} - -static void -connect_context_clear(NMModemBroadband *self) -{ - if (self->_priv.ctx) { - ConnectContext *ctx = self->_priv.ctx; - - g_clear_error(&ctx->first_error); - nm_clear_pointer(&ctx->ip_types, g_array_unref); - nm_clear_g_cancellable(&ctx->cancellable); - g_clear_object(&ctx->connection); - g_clear_object(&ctx->connect_properties); - g_clear_object(&ctx->self); - g_slice_free(ConnectContext, ctx); - self->_priv.ctx = NULL; - } -} - -static void connect_context_step(NMModemBroadband *self); - -static void -connect_ready(MMModemSimple *simple_iface, GAsyncResult *res, NMModemBroadband *self) -{ - ConnectContext *ctx; - GError * error = NULL; - NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; - NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - MMBearer * bearer; - - bearer = mm_modem_simple_connect_finish(simple_iface, res, &error); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - g_error_free(error); - return; - } - - ctx = self->_priv.ctx; - - if (!ctx) - return; - - self->_priv.bearer = bearer; - - if (!self->_priv.bearer) { - if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) - || (g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) - && mm_modem_get_unlock_required(self->_priv.modem_iface) - == MM_MODEM_LOCK_SIM_PIN)) { - g_error_free(error); - - /* Request PIN */ - ask_for_pin(self); - connect_context_clear(self); - return; - } - - /* Save the error, if it's the first one */ - if (!ctx->first_error) { - /* Strip remote error info before saving it */ - if (g_dbus_error_is_remote_error(error)) - g_dbus_error_strip_remote_error(error); - ctx->first_error = error; - } else - g_clear_error(&error); - - if (ctx->ip_type_tries == 0 && g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_RETRY)) { - /* Try one more time */ - ctx->ip_type_tries++; - } else { - /* If the modem/provider lies and the IP type we tried isn't supported, - * retry with the next one, if any. - */ - ctx->ip_types_i++; - ctx->ip_type_tries = 0; - } - connect_context_step(self); - return; - } - - /* Grab IP configurations */ - self->_priv.ipv4_config = mm_bearer_get_ipv4_config(self->_priv.bearer); - if (self->_priv.ipv4_config) - ip4_method = get_bearer_ip_method(self->_priv.ipv4_config); - - self->_priv.ipv6_config = mm_bearer_get_ipv6_config(self->_priv.bearer); - if (self->_priv.ipv6_config) - ip6_method = get_bearer_ip_method(self->_priv.ipv6_config); - - if (!nm_modem_set_data_port(NM_MODEM(self), - NM_PLATFORM_GET, - mm_bearer_get_interface(self->_priv.bearer), - ip4_method, - ip6_method, - mm_bearer_get_ip_timeout(self->_priv.bearer), - &error)) { - _LOGW("failed to connect modem: %s", error->message); - g_error_free(error); - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - connect_context_clear(self); - return; - } - - ctx->step++; - connect_context_step(self); -} - -static void -send_pin_ready(MMSim *sim, GAsyncResult *result, NMModemBroadband *self) -{ - gs_free_error GError *error = NULL; - - mm_sim_send_pin_finish(sim, result, &error); - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - if (!self->_priv.ctx || self->_priv.ctx->step != CONNECT_STEP_UNLOCK) - g_return_if_reached(); - - if (error) { - if (g_error_matches(error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) - || (g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) - && mm_modem_get_unlock_required(self->_priv.modem_iface) == MM_MODEM_LOCK_SIM_PIN)) - ask_for_pin(self); - else - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, translate_mm_error(self, error)); - return; - } - - self->_priv.ctx->step++; - connect_context_step(self); -} - -static void -find_gsm_apn_cb(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data) -{ - NMModemBroadband * self = user_data; - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - ConnectContext * ctx = priv->ctx; - - if (error) { - _LOGW("failed to connect '%s': APN not found: %s", - nm_connection_get_id(ctx->connection), - error->message); - - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); - connect_context_clear(self); - return; - } - - /* Blank APN ("") means the default subscription APN */ - ctx->connect_properties = - create_gsm_connect_properties(ctx->connection, apn, username, password); - g_return_if_fail(ctx->connect_properties); - connect_context_step(self); -} - -static gboolean -try_create_connect_properties(NMModemBroadband *self) -{ - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - ConnectContext * ctx = priv->ctx; - - if (MODEM_CAPS_3GPP(ctx->caps)) { - NMSettingGsm *s_gsm = nm_connection_get_setting_gsm(ctx->connection); - - if (!s_gsm || nm_setting_gsm_get_auto_config(s_gsm)) { - gs_unref_object MMModem3gpp *modem_3gpp = NULL; - const char * network_id = NULL; - - s_gsm = nm_connection_get_setting_gsm(ctx->connection); - if (s_gsm) - network_id = nm_setting_gsm_get_network_id(s_gsm); - if (!network_id) { - if (mm_modem_get_state(self->_priv.modem_iface) < MM_MODEM_STATE_REGISTERED) - return FALSE; - modem_3gpp = mm_object_get_modem_3gpp(priv->modem_object); - network_id = mm_modem_3gpp_get_operator_code(modem_3gpp); - } - if (!network_id) { - _LOGW("failed to connect '%s': unable to determine the network id", - nm_connection_get_id(ctx->connection)); - goto out; - } - - nm_service_providers_find_gsm_apn(MOBILE_BROADBAND_PROVIDER_INFO_DATABASE, - network_id, - ctx->cancellable, - find_gsm_apn_cb, - self); - } else { - ctx->connect_properties = - create_gsm_connect_properties(ctx->connection, - nm_setting_gsm_get_apn(s_gsm), - nm_setting_gsm_get_username(s_gsm), - nm_setting_gsm_get_password(s_gsm)); - g_return_val_if_fail(ctx->connect_properties, TRUE); - } - - return TRUE; - } else if (MODEM_CAPS_3GPP2(ctx->caps)) { - ctx->connect_properties = create_cdma_connect_properties(ctx->connection); - g_return_val_if_fail(ctx->connect_properties, FALSE); - return TRUE; - } else { - _LOGW("failed to connect '%s': not a mobile broadband modem", - nm_connection_get_id(ctx->connection)); - } - -out: - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); - connect_context_clear(self); - return TRUE; -} - -static void -connect_context_step(NMModemBroadband *self) -{ - ConnectContext *ctx = self->_priv.ctx; - - switch (ctx->step) { - case CONNECT_STEP_FIRST: - ctx->step++; - /* fall-through */ - - case CONNECT_STEP_WAIT_FOR_SIM: - if (MODEM_CAPS_3GPP(ctx->caps) && !self->_priv.sim_iface) { - /* Have to wait for the SIM to show up */ - break; - } - ctx->step++; - /* fall-through */ - - case CONNECT_STEP_UNLOCK: - if (MODEM_CAPS_3GPP(ctx->caps) - && mm_modem_get_unlock_required(self->_priv.modem_iface) == MM_MODEM_LOCK_SIM_PIN) { - NMSettingGsm *s_gsm = nm_connection_get_setting_gsm(ctx->connection); - const char * pin = nm_setting_gsm_get_pin(s_gsm); - - /* If we have a PIN already, send it. If we don't, get it. */ - if (pin) { - mm_sim_send_pin(self->_priv.sim_iface, - pin, - ctx->cancellable, - (GAsyncReadyCallback) send_pin_ready, - self); - } else { - ask_for_pin(self); - } - break; - } - ctx->step++; - /* fall-through */ - case CONNECT_STEP_WAIT_FOR_READY: - { - GError *error = NULL; - - if (mm_modem_get_state(self->_priv.modem_iface) <= MM_MODEM_STATE_LOCKED) - break; - - if (!try_create_connect_properties(self)) - break; - - if (!self->_priv.ctx) - break; - - /* Build up list of IP types that we need to use in the retries */ - ctx->ip_types = nm_modem_get_connection_ip_type(NM_MODEM(self), ctx->connection, &error); - if (!ctx->ip_types) { - _LOGW("failed to connect '%s': %s", - nm_connection_get_id(ctx->connection), - error->message); - g_clear_error(&error); - - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); - connect_context_clear(self); - break; - } - - ctx->step++; - } - /* fall-through */ - case CONNECT_STEP_CONNECT: - if (!ctx->connect_properties) - break; - - if (ctx->ip_types_i < ctx->ip_types->len) { - NMModemIPType current; - - current = g_array_index(ctx->ip_types, NMModemIPType, ctx->ip_types_i); - - if (current == NM_MODEM_IP_TYPE_IPV4) - mm_simple_connect_properties_set_ip_type(ctx->connect_properties, - MM_BEARER_IP_FAMILY_IPV4); - else if (current == NM_MODEM_IP_TYPE_IPV6) - mm_simple_connect_properties_set_ip_type(ctx->connect_properties, - MM_BEARER_IP_FAMILY_IPV6); - else if (current == NM_MODEM_IP_TYPE_IPV4V6) - mm_simple_connect_properties_set_ip_type(ctx->connect_properties, - MM_BEARER_IP_FAMILY_IPV4V6); - else - g_return_if_reached(); - - _nm_modem_set_apn(NM_MODEM(self), - mm_simple_connect_properties_get_apn(ctx->connect_properties)); - - _LOGD("launching connection with ip type '%s' (try %d)", - nm_modem_ip_type_to_string(current), - ctx->ip_type_tries + 1); - - mm_modem_simple_connect(self->_priv.simple_iface, - ctx->connect_properties, - ctx->cancellable, - (GAsyncReadyCallback) connect_ready, - self); - break; - } - - ctx->step++; - /* fall-through */ - - case CONNECT_STEP_LAST: - if (self->_priv.ipv4_config || self->_priv.ipv6_config) - nm_modem_emit_prepare_result(NM_MODEM(self), TRUE, NM_DEVICE_STATE_REASON_NONE); - else { - /* If we have a saved error from a previous attempt, use it */ - if (!ctx->first_error) - ctx->first_error = g_error_new_literal(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "invalid bearer IP configuration"); - - _LOGW("failed to connect modem: %s", ctx->first_error->message); - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - translate_mm_error(self, ctx->first_error)); - } - - connect_context_clear(self); - break; - } -} - -static NMActStageReturn -modem_act_stage1_prepare(NMModem * _self, - NMConnection * connection, - NMDeviceStateReason *out_failure_reason) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(_self); - - /* Make sure we can get the Simple interface from the modem */ - if (!self->_priv.simple_iface) { - self->_priv.simple_iface = mm_object_get_modem_simple(self->_priv.modem_object); - if (!self->_priv.simple_iface) { - _LOGW("cannot access the Simple mobile broadband modem interface"); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - } - - connect_context_clear(self); - - /* Allocate new context for this connect stage attempt */ - self->_priv.ctx = g_slice_new0(ConnectContext); - self->_priv.ctx->caps = mm_modem_get_current_capabilities(self->_priv.modem_iface); - self->_priv.ctx->cancellable = g_cancellable_new(); - self->_priv.ctx->connection = g_object_ref(connection); - - g_dbus_proxy_set_default_timeout(G_DBUS_PROXY(self->_priv.simple_iface), - MODEM_CONNECT_TIMEOUT_SECS * 1000); - connect_context_step(self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -static gboolean -check_connection_compatible_with_modem(NMModem *_self, NMConnection *connection, GError **error) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(_self); - MMModemCapability modem_caps; - - modem_caps = mm_modem_get_current_capabilities(self->_priv.modem_iface); - - if (MODEM_CAPS_3GPP(modem_caps)) { - if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, error)) - return FALSE; - - return TRUE; - } - - if (MODEM_CAPS_3GPP2(modem_caps)) { - if (!_nm_connection_check_main_setting(connection, NM_SETTING_CDMA_SETTING_NAME, error)) - return FALSE; - - return TRUE; - } - - if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, NULL) - && !_nm_connection_check_main_setting(connection, NM_SETTING_CDMA_SETTING_NAME, NULL)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "connection type %s is not supported by modem", - nm_connection_get_connection_type(connection)); - return FALSE; - } - - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem lacks capabilities for %s profile", - nm_connection_get_connection_type(connection)); - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -complete_connection(NMModem * modem, - const char * iface, - NMConnection * connection, - NMConnection *const *existing_connections, - GError ** error) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(modem); - MMModemCapability modem_caps; - NMSettingPpp * s_ppp; - - modem_caps = mm_modem_get_current_capabilities(self->_priv.modem_iface); - - /* PPP settings common to 3GPP and 3GPP2 */ - s_ppp = nm_connection_get_setting_ppp(connection); - if (!s_ppp) { - s_ppp = (NMSettingPpp *) nm_setting_ppp_new(); - g_object_set(G_OBJECT(s_ppp), - NM_SETTING_PPP_LCP_ECHO_FAILURE, - 5, - NM_SETTING_PPP_LCP_ECHO_INTERVAL, - 30, - NULL); - nm_connection_add_setting(connection, NM_SETTING(s_ppp)); - } - - if (MODEM_CAPS_3GPP(modem_caps)) { - NMSettingGsm *s_gsm; - - s_gsm = nm_connection_get_setting_gsm(connection); - if (!s_gsm) { - s_gsm = (NMSettingGsm *) nm_setting_gsm_new(); - nm_connection_add_setting(connection, NM_SETTING(s_gsm)); - g_object_set(G_OBJECT(s_gsm), NM_SETTING_GSM_AUTO_CONFIG, TRUE, NULL); - } - - if (!nm_setting_gsm_get_device_id(s_gsm)) { - g_object_set(G_OBJECT(s_gsm), - NM_SETTING_GSM_DEVICE_ID, - nm_modem_get_device_id(modem), - NULL); - } - - nm_utils_complete_generic(NM_PLATFORM_GET, - connection, - NM_SETTING_GSM_SETTING_NAME, - existing_connections, - NULL, - _("GSM connection"), - NULL, - NULL, - FALSE); /* No IPv6 yet by default */ - - return TRUE; - } - - if (MODEM_CAPS_3GPP2(modem_caps)) { - NMSettingCdma *s_cdma; - - s_cdma = nm_connection_get_setting_cdma(connection); - if (!s_cdma) { - s_cdma = (NMSettingCdma *) nm_setting_cdma_new(); - nm_connection_add_setting(connection, NM_SETTING(s_cdma)); - } - - if (!nm_setting_cdma_get_number(s_cdma)) - g_object_set(G_OBJECT(s_cdma), NM_SETTING_CDMA_NUMBER, "#777", NULL); - - nm_utils_complete_generic(NM_PLATFORM_GET, - connection, - NM_SETTING_CDMA_SETTING_NAME, - existing_connections, - NULL, - _("CDMA connection"), - NULL, - iface, - FALSE); /* No IPv6 yet by default */ - - return TRUE; - } - - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Device is not a mobile broadband modem"); - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -get_user_pass(NMModem *modem, NMConnection *connection, const char **user, const char **pass) -{ - NMSettingGsm * s_gsm; - NMSettingCdma *s_cdma; - - s_gsm = nm_connection_get_setting_gsm(connection); - s_cdma = nm_connection_get_setting_cdma(connection); - if (!s_gsm && !s_cdma) - return FALSE; - - if (user) { - if (s_gsm) - *user = nm_setting_gsm_get_username(s_gsm); - else if (s_cdma) - *user = nm_setting_cdma_get_username(s_cdma); - } - if (pass) { - if (s_gsm) - *pass = nm_setting_gsm_get_password(s_gsm); - else if (s_cdma) - *pass = nm_setting_cdma_get_password(s_cdma); - } - - return TRUE; -} - -/*****************************************************************************/ -/* Query/Update enabled state */ - -static void -set_power_state_low_ready(MMModem *modem, GAsyncResult *result, NMModemBroadband *self) -{ - GError *error = NULL; - - if (!mm_modem_set_power_state_finish(modem, result, &error)) { - /* Log but ignore errors; not all modems support low power state */ - _LOGD("failed to set modem low power state: %s", NM_G_ERROR_MSG(error)); - g_clear_error(&error); - } - - /* Balance refcount */ - g_object_unref(self); -} - -static void -modem_disable_ready(MMModem *modem_iface, GAsyncResult *res, NMModemBroadband *self) -{ - GError *error = NULL; - - if (mm_modem_disable_finish(modem_iface, res, &error)) { - /* Once disabled, move to low-power mode */ - mm_modem_set_power_state(modem_iface, - MM_MODEM_POWER_STATE_LOW, - NULL, - (GAsyncReadyCallback) set_power_state_low_ready, - g_object_ref(self)); - } else { - _LOGW("failed to disable modem: %s", NM_G_ERROR_MSG(error)); - nm_modem_set_prev_state(NM_MODEM(self), "disable failed"); - g_clear_error(&error); - } - - /* Balance refcount */ - g_object_unref(self); -} - -static void -modem_enable_ready(MMModem *modem_iface, GAsyncResult *res, NMModemBroadband *self) -{ - GError *error = NULL; - - if (!mm_modem_enable_finish(modem_iface, res, &error)) { - _LOGW("failed to enable modem: %s", NM_G_ERROR_MSG(error)); - nm_modem_set_prev_state(NM_MODEM(self), "enable failed"); - g_clear_error(&error); - } - - /* Balance refcount */ - g_object_unref(self); -} - -static void -set_mm_enabled(NMModem *_self, gboolean enabled) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(_self); - - if (enabled) { - mm_modem_enable(self->_priv.modem_iface, - NULL, /* cancellable */ - (GAsyncReadyCallback) modem_enable_ready, - g_object_ref(self)); - } else { - mm_modem_disable(self->_priv.modem_iface, - NULL, /* cancellable */ - (GAsyncReadyCallback) modem_disable_ready, - g_object_ref(self)); - } -} - -/*****************************************************************************/ -/* IPv4 method static */ - -static gboolean -static_stage3_ip4_done(NMModemBroadband *self) -{ - GError * error = NULL; - gs_unref_object NMIP4Config *config = NULL; - const char * data_port; - const char * address_string; - const char * gw_string; - guint32 address_network; - guint32 gw = 0; - NMPlatformIP4Address address; - const char ** dns; - guint i; - guint32 ip4_route_table, ip4_route_metric; - NMPlatformIP4Route * r; - guint32 mtu_n; - - g_return_val_if_fail(self->_priv.ipv4_config, FALSE); - g_return_val_if_fail(self->_priv.bearer, FALSE); - - self->_priv.idle_id_ip4 = 0; - - _LOGI("IPv4 static configuration:"); - - /* Fully fail if invalid IP address retrieved */ - address_string = mm_bearer_ip_config_get_address(self->_priv.ipv4_config); - if (!address_string - || !nm_utils_parse_inaddr_bin(AF_INET, address_string, NULL, &address_network)) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IP4 configuration failed: invalid address given %s%s%s", - nm_modem_get_uid(NM_MODEM(self)), - NM_PRINT_FMT_QUOTE_STRING(address_string)); - goto out; - } - - /* Missing gateway not a hard failure */ - gw_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv4_config); - if (gw_string && !nm_utils_parse_inaddr_bin(AF_INET, gw_string, NULL, &gw)) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IP4 configuration failed: invalid gateway address \"%s\"", - nm_modem_get_uid(NM_MODEM(self)), - gw_string); - goto out; - } - - data_port = mm_bearer_get_interface(self->_priv.bearer); - g_return_val_if_fail(data_port, FALSE); - config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), - nm_platform_link_get_ifindex(NM_PLATFORM_GET, data_port)); - - memset(&address, 0, sizeof(address)); - address.address = address_network; - address.peer_address = address_network; - address.plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv4_config); - address.addr_source = NM_IP_CONFIG_SOURCE_WWAN; - if (address.plen <= 32) - nm_ip4_config_add_address(config, &address); - - _LOGI(" address %s/%d", address_string, address.plen); - - nm_modem_get_route_parameters(NM_MODEM(self), &ip4_route_table, &ip4_route_metric, NULL, NULL); - r = &(NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_WWAN, - .gateway = gw, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, - }; - nm_ip4_config_add_route(config, r, NULL); - _LOGI(" gateway %s", gw_string); - - /* DNS servers */ - dns = mm_bearer_ip_config_get_dns(self->_priv.ipv4_config); - for (i = 0; dns && dns[i]; i++) { - if (nm_utils_parse_inaddr_bin(AF_INET, dns[i], NULL, &address_network) - && address_network > 0) { - nm_ip4_config_add_nameserver(config, address_network); - _LOGI(" DNS %s", dns[i]); - } - } - -#if MM_CHECK_VERSION(1, 4, 0) - mtu_n = mm_bearer_ip_config_get_mtu(self->_priv.ipv4_config); - if (mtu_n) { - nm_ip4_config_set_mtu(config, mtu_n, NM_IP_CONFIG_SOURCE_WWAN); - _LOGI(" MTU %u", mtu_n); - } -#endif - -out: - g_signal_emit_by_name(self, NM_MODEM_IP4_CONFIG_RESULT, config, error); - g_clear_error(&error); - return FALSE; -} - -static NMActStageReturn -static_stage3_ip4_config_start(NMModem * modem, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(modem); - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - - /* We schedule it in an idle just to follow the same logic as in the - * generic modem implementation. */ - nm_clear_g_source(&priv->idle_id_ip4); - priv->idle_id_ip4 = g_idle_add((GSourceFunc) static_stage3_ip4_done, self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ -/* IPv6 method static */ - -static gboolean -stage3_ip6_done(NMModemBroadband *self) -{ - GError * error = NULL; - NMIP6Config * config = NULL; - const char * data_port; - const char * address_string; - NMPlatformIP6Address address; - NMModemIPMethod ip_method; - const char ** dns; - guint i; - - g_return_val_if_fail(self->_priv.ipv6_config, FALSE); - - self->_priv.idle_id_ip6 = 0; - memset(&address, 0, sizeof(address)); - - ip_method = get_bearer_ip_method(self->_priv.ipv6_config); - - address_string = mm_bearer_ip_config_get_address(self->_priv.ipv6_config); - if (!address_string) { - /* DHCP/SLAAC is allowed to skip addresses; other methods require it */ - if (ip_method != NM_MODEM_IP_METHOD_AUTO) { - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: no address given", - nm_modem_get_uid(NM_MODEM(self))); - } - goto out; - } - - /* Fail if invalid IP address retrieved */ - if (!inet_pton(AF_INET6, address_string, (void *) &(address.address))) { - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: invalid address given '%s'", - nm_modem_get_uid(NM_MODEM(self)), - address_string); - goto out; - } - - _LOGI("IPv6 base configuration:"); - - data_port = mm_bearer_get_interface(self->_priv.bearer); - g_return_val_if_fail(data_port, FALSE); - - config = nm_ip6_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), - nm_platform_link_get_ifindex(NM_PLATFORM_GET, data_port)); - - address.plen = mm_bearer_ip_config_get_prefix(self->_priv.ipv6_config); - if (address.plen <= 128) - nm_ip6_config_add_address(config, &address); - - _LOGI(" address %s/%d", address_string, address.plen); - - address_string = mm_bearer_ip_config_get_gateway(self->_priv.ipv6_config); - if (address_string) { - guint32 ip6_route_table, ip6_route_metric; - - if (inet_pton(AF_INET6, address_string, &address.address) != 1) { - error = - g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: invalid gateway given '%s'", - nm_modem_get_uid(NM_MODEM(self)), - address_string); - goto out; - } - - nm_modem_get_route_parameters(NM_MODEM(self), - NULL, - NULL, - &ip6_route_table, - &ip6_route_metric); - { - const NMPlatformIP6Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_WWAN, - .gateway = address.address, - .table_coerced = nm_platform_route_table_coerce(ip6_route_table), - .metric = ip6_route_metric, - }; - - _LOGI(" gateway %s", address_string); - nm_ip6_config_add_route(config, &r, NULL); - } - } else if (ip_method == NM_MODEM_IP_METHOD_STATIC) { - /* Gateway required for the 'static' method */ - error = g_error_new(NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "(%s) retrieving IPv6 configuration failed: missing gateway", - nm_modem_get_uid(NM_MODEM(self))); - goto out; - } - - /* DNS servers */ - dns = mm_bearer_ip_config_get_dns(self->_priv.ipv6_config); - for (i = 0; dns && dns[i]; i++) { - struct in6_addr addr; - - if (inet_pton(AF_INET6, dns[i], &addr)) { - nm_ip6_config_add_nameserver(config, &addr); - _LOGI(" DNS %s", dns[i]); - } - } - -out: - nm_modem_emit_ip6_config_result(NM_MODEM(self), config, error); - g_clear_object(&config); - g_clear_error(&error); - return FALSE; -} - -static NMActStageReturn -stage3_ip6_config_request(NMModem *modem, NMDeviceStateReason *out_failure_reason) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(modem); - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - - /* We schedule it in an idle just to follow the same logic as in the - * generic modem implementation. */ - nm_clear_g_source(&priv->idle_id_ip6); - priv->idle_id_ip6 = g_idle_add((GSourceFunc) stage3_ip6_done, self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ -/* Disconnect */ - -typedef struct { - NMModemBroadband * self; - _NMModemDisconnectCallback callback; - gpointer callback_user_data; - GCancellable * cancellable; - gboolean warn; -} DisconnectContext; - -static void -disconnect_context_complete(DisconnectContext *ctx, GError *error) -{ - if (ctx->callback) - ctx->callback(NM_MODEM(ctx->self), error, ctx->callback_user_data); - nm_g_object_unref(ctx->cancellable); - g_object_unref(ctx->self); - g_slice_free(DisconnectContext, ctx); -} - -static void -disconnect_context_complete_on_idle(gpointer user_data, GCancellable *cancellable) -{ - DisconnectContext *ctx = user_data; - gs_free_error GError *cancelled_error = NULL; - - g_cancellable_set_error_if_cancelled(cancellable, &cancelled_error); - disconnect_context_complete(ctx, cancelled_error); -} - -static void -simple_disconnect_ready(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - MMModemSimple * modem_iface = MM_MODEM_SIMPLE(source_object); - DisconnectContext *ctx = user_data; - gs_free_error GError *error = NULL; - - if (!mm_modem_simple_disconnect_finish(modem_iface, res, &error)) { - if (ctx->warn && !g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { - NMModemBroadband *self = ctx->self; - - _LOGW("failed to disconnect modem: %s", error->message); - } - } - - disconnect_context_complete(ctx, error); -} - -static void -disconnect(NMModem * modem, - gboolean warn, - GCancellable * cancellable, - _NMModemDisconnectCallback callback, - gpointer user_data) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(modem); - DisconnectContext *ctx; - - connect_context_clear(self); - _nm_modem_set_apn(NM_MODEM(self), NULL); - - ctx = g_slice_new0(DisconnectContext); - ctx->self = g_object_ref(self); - ctx->cancellable = nm_g_object_ref(cancellable); - ctx->callback = callback; - ctx->callback_user_data = user_data; - - /* Don't bother warning on FAILED since the modem is already gone */ - ctx->warn = warn; - - /* Already cancelled or no simple-iface? We are done. */ - if (!ctx->self->_priv.simple_iface || g_cancellable_is_cancelled(cancellable)) { - nm_utils_invoke_on_idle(cancellable, disconnect_context_complete_on_idle, ctx); - return; - } - - _LOGD("notifying ModemManager about the modem disconnection"); - mm_modem_simple_disconnect(self->_priv.simple_iface, - NULL, /* bearer path; if NULL given ALL get disconnected */ - cancellable, - simple_disconnect_ready, - ctx); -} - -/*****************************************************************************/ - -static void -deactivate_cleanup(NMModem *modem, NMDevice *device, gboolean stop_ppp_manager) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(modem); - - /* TODO: cancel SimpleConnect() if any */ - - /* Cleanup IPv4 addresses and routes */ - g_clear_object(&self->_priv.ipv4_config); - g_clear_object(&self->_priv.ipv6_config); - g_clear_object(&self->_priv.bearer); - - self->_priv.pin_tries = 0; - - NM_MODEM_CLASS(nm_modem_broadband_parent_class) - ->deactivate_cleanup(modem, device, stop_ppp_manager); -} - -/*****************************************************************************/ - -#define MAP_STATE(name) \ - case MM_MODEM_STATE_##name: \ - return NM_MODEM_STATE_##name; - -static NMModemState -mm_state_to_nm(MMModemState mm_state) -{ - switch (mm_state) { - MAP_STATE(UNKNOWN) - MAP_STATE(FAILED) - MAP_STATE(INITIALIZING) - MAP_STATE(LOCKED) - MAP_STATE(DISABLED) - MAP_STATE(DISABLING) - MAP_STATE(ENABLING) - MAP_STATE(ENABLED) - MAP_STATE(SEARCHING) - MAP_STATE(REGISTERED) - MAP_STATE(DISCONNECTING) - MAP_STATE(CONNECTING) - MAP_STATE(CONNECTED) - } - return NM_MODEM_STATE_UNKNOWN; -} - -static void -modem_state_changed(MMModem * modem, - MMModemState old_state, - MMModemState new_state, - MMModemStateChangeReason reason, - NMModemBroadband * self) -{ - /* After the SIM is unlocked MM1 will move the device to INITIALIZING which - * is an unavailable state. That makes state handling confusing here, so - * suppress this state change and let the modem move from LOCKED to DISABLED. - */ - if (new_state == MM_MODEM_STATE_INITIALIZING && old_state == MM_MODEM_STATE_LOCKED) - return; - - nm_modem_set_state(NM_MODEM(self), - mm_state_to_nm(new_state), - mm_modem_state_change_reason_get_string(reason)); - - if (self->_priv.ctx && self->_priv.ctx->step == CONNECT_STEP_WAIT_FOR_READY) - connect_context_step(self); -} - -/*****************************************************************************/ - -static NMModemIPType -mm_ip_family_to_nm(MMBearerIpFamily family) -{ - NMModemIPType nm_type = NM_MODEM_IP_TYPE_UNKNOWN; - - if (family & MM_BEARER_IP_FAMILY_IPV4) - nm_type |= NM_MODEM_IP_TYPE_IPV4; - if (family & MM_BEARER_IP_FAMILY_IPV6) - nm_type |= NM_MODEM_IP_TYPE_IPV6; - if (family & MM_BEARER_IP_FAMILY_IPV4V6) - nm_type |= MM_BEARER_IP_FAMILY_IPV4V6; - - return nm_type; -} - -static void -get_sim_ready(MMModem *modem, GAsyncResult *res, NMModemBroadband *self) -{ - GError *error = NULL; - MMSim * new_sim; - - new_sim = mm_modem_get_sim_finish(modem, res, &error); - if (new_sim != self->_priv.sim_iface) { - g_clear_object(&self->_priv.sim_iface); - self->_priv.sim_iface = new_sim; - } else - g_clear_object(&new_sim); - - if (self->_priv.sim_iface) { - g_object_set(G_OBJECT(self), - NM_MODEM_SIM_ID, - mm_sim_get_identifier(self->_priv.sim_iface), - NM_MODEM_SIM_OPERATOR_ID, - mm_sim_get_operator_identifier(self->_priv.sim_iface), - NULL); - - /* If we're waiting for the SIM during a connect, proceed with the connect */ - if (self->_priv.ctx && self->_priv.ctx->step == CONNECT_STEP_WAIT_FOR_SIM) - connect_context_step(self); - } else { - _NMLOG(g_error_matches(error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND) ? LOGL_INFO - : LOGL_WARN, - "failed to retrieve SIM object: %s", - NM_G_ERROR_MSG(error)); - } - g_clear_error(&error); - g_object_unref(self); -} - -static void -sim_changed(MMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(user_data); - - g_return_if_fail(modem == self->_priv.modem_iface); - - if (mm_modem_get_sim_path(self->_priv.modem_iface)) { - mm_modem_get_sim(self->_priv.modem_iface, - NULL, /* cancellable */ - (GAsyncReadyCallback) get_sim_ready, - g_object_ref(self)); - } else - g_object_set(G_OBJECT(self), NM_MODEM_SIM_ID, NULL, NM_MODEM_SIM_OPERATOR_ID, NULL, NULL); -} - -static void -supported_ip_families_changed(MMModem *modem, GParamSpec *pspec, gpointer user_data) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(user_data); - - g_return_if_fail(modem == self->_priv.modem_iface); - - g_object_set(G_OBJECT(self), - NM_MODEM_IP_TYPES, - mm_ip_family_to_nm(mm_modem_get_supported_ip_families(modem)), - NULL); -} - -static void -operator_code_changed(MMModem3gpp *modem_3gpp, GParamSpec *pspec, gpointer user_data) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(user_data); - - g_return_if_fail(modem_3gpp == self->_priv.modem_3gpp_iface); - _nm_modem_set_operator_code(NM_MODEM(self), mm_modem_3gpp_get_operator_code(modem_3gpp)); -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(object); - - switch (prop_id) { - case PROP_MODEM: - g_value_set_object(value, self->_priv.modem_object); - 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) -{ - NMModemBroadband *self = NM_MODEM_BROADBAND(object); - - switch (prop_id) { - case PROP_MODEM: - /* construct-only */ - self->_priv.modem_object = g_value_dup_object(value); - self->_priv.modem_iface = mm_object_get_modem(self->_priv.modem_object); - g_return_if_fail(self->_priv.modem_iface); - self->_priv.modem_3gpp_iface = mm_object_get_modem_3gpp(self->_priv.modem_object); - - g_signal_connect(self->_priv.modem_iface, - "state-changed", - G_CALLBACK(modem_state_changed), - self); - g_signal_connect(self->_priv.modem_iface, "notify::sim", G_CALLBACK(sim_changed), self); - sim_changed(self->_priv.modem_iface, NULL, self); - g_signal_connect(self->_priv.modem_iface, - "notify::supported-ip-families", - G_CALLBACK(supported_ip_families_changed), - self); - - if (self->_priv.modem_3gpp_iface) { - g_signal_connect(self->_priv.modem_3gpp_iface, - "notify::operator-code", - G_CALLBACK(operator_code_changed), - self); - } - - /* Note: don't grab the Simple iface here; the Modem interface is the - * only one assumed to be always valid and available */ - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_modem_broadband_init(NMModemBroadband *self) -{} - -NMModem * -nm_modem_broadband_new(GObject *object, GError **error) -{ - MMObject * modem_object; - MMModem * modem_iface; - MMModem3gpp * modem_3gpp_iface; - const char *const *drivers; - const char * operator_code = NULL; - gs_free char * driver = NULL; - - g_return_val_if_fail(MM_IS_OBJECT(object), NULL); - modem_object = MM_OBJECT(object); - - /* Ensure we have the 'Modem' interface and the primary port at least */ - modem_iface = mm_object_peek_modem(modem_object); - g_return_val_if_fail(modem_iface, NULL); - g_return_val_if_fail(mm_modem_get_primary_port(modem_iface), NULL); - - /* Build a single string with all drivers listed */ - drivers = mm_modem_get_drivers(modem_iface); - if (drivers) - driver = g_strjoinv(", ", (char **) drivers); - - modem_3gpp_iface = mm_object_peek_modem_3gpp(modem_object); - if (modem_3gpp_iface) - operator_code = mm_modem_3gpp_get_operator_code(modem_3gpp_iface); - - return g_object_new(NM_TYPE_MODEM_BROADBAND, - NM_MODEM_PATH, - mm_object_get_path(modem_object), - NM_MODEM_UID, - mm_modem_get_primary_port(modem_iface), - NM_MODEM_CONTROL_PORT, - mm_modem_get_primary_port(modem_iface), - NM_MODEM_IP_TYPES, - mm_ip_family_to_nm(mm_modem_get_supported_ip_families(modem_iface)), - NM_MODEM_STATE, - (int) mm_state_to_nm(mm_modem_get_state(modem_iface)), - NM_MODEM_DEVICE_ID, - mm_modem_get_device_identifier(modem_iface), - NM_MODEM_BROADBAND_MODEM, - modem_object, - NM_MODEM_DRIVER, - driver, - NM_MODEM_OPERATOR_CODE, - operator_code, - NULL); -} - -static void -dispose(GObject *object) -{ - NMModemBroadband * self = NM_MODEM_BROADBAND(object); - NMModemBroadbandPrivate *priv = NM_MODEM_BROADBAND_GET_PRIVATE(self); - - nm_clear_g_source(&priv->idle_id_ip4); - nm_clear_g_source(&priv->idle_id_ip6); - - connect_context_clear(self); - g_clear_object(&self->_priv.ipv4_config); - g_clear_object(&self->_priv.ipv6_config); - g_clear_object(&self->_priv.bearer); - - if (self->_priv.modem_iface) { - g_signal_handlers_disconnect_by_data(self->_priv.modem_iface, self); - g_clear_object(&self->_priv.modem_iface); - } - - if (self->_priv.modem_3gpp_iface) { - g_signal_handlers_disconnect_by_data(self->_priv.modem_3gpp_iface, self); - g_clear_object(&self->_priv.modem_3gpp_iface); - } - - g_clear_object(&self->_priv.simple_iface); - g_clear_object(&self->_priv.sim_iface); - g_clear_object(&self->_priv.modem_object); - - G_OBJECT_CLASS(nm_modem_broadband_parent_class)->dispose(object); -} - -static void -nm_modem_broadband_class_init(NMModemBroadbandClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - NMModemClass *modem_class = NM_MODEM_CLASS(klass); - - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - modem_class->get_capabilities = get_capabilities; - modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; - modem_class->stage3_ip6_config_request = stage3_ip6_config_request; - modem_class->disconnect = disconnect; - 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_with_modem = check_connection_compatible_with_modem; - modem_class->complete_connection = complete_connection; - modem_class->modem_act_stage1_prepare = modem_act_stage1_prepare; - modem_class->owns_port = owns_port; - - obj_properties[PROP_MODEM] = - g_param_spec_object(NM_MODEM_BROADBAND_MODEM, - "", - "", - MM_GDBUS_TYPE_OBJECT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} diff --git a/src/devices/wwan/nm-modem-broadband.h b/src/devices/wwan/nm-modem-broadband.h deleted file mode 100644 index 5a822f6f..00000000 --- a/src/devices/wwan/nm-modem-broadband.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2012 - Aleksander Morgado <aleksander@gnu.org> - */ - -#ifndef __NETWORKMANAGER_MODEM_BROADBAND_H__ -#define __NETWORKMANAGER_MODEM_BROADBAND_H__ - -#include "nm-modem.h" - -#define NM_TYPE_MODEM_BROADBAND (nm_modem_broadband_get_type()) -#define NM_MODEM_BROADBAND(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadband)) -#define NM_MODEM_BROADBAND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) -#define NM_IS_MODEM_BROADBAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_BROADBAND)) -#define NM_IS_MODEM_BROADBAND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM_BROADBAND)) -#define NM_MODEM_BROADBAND_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MODEM_BROADBAND, NMModemBroadbandClass)) - -typedef struct _NMModemBroadband NMModemBroadband; -typedef struct _NMModemBroadbandClass NMModemBroadbandClass; - -GType nm_modem_broadband_get_type(void); - -NMModem *nm_modem_broadband_new(GObject *object, GError **error); - -#endif /* __NETWORKMANAGER_MODEM_BROADBAND_H__ */ diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c deleted file mode 100644 index 65f7c9f9..00000000 --- a/src/devices/wwan/nm-modem-manager.c +++ /dev/null @@ -1,876 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2014 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - * Copyright (C) 2009 - 2013 Canonical Ltd. - */ - -#include "nm-default.h" - -#include "nm-modem-manager.h" - -#include <libmm-glib.h> - -#if HAVE_LIBSYSTEMD - #include <systemd/sd-daemon.h> -#else - #define sd_booted() FALSE -#endif - -#include "nm-std-aux/nm-dbus-compat.h" -#include "nm-modem.h" -#include "nm-modem-broadband.h" - -#if WITH_OFONO - #include "nm-modem-ofono.h" -#endif - -#define MODEM_POKE_INTERVAL 120 - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMModemManager, PROP_NAME_OWNER, ); - -enum { - MODEM_ADDED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct { - GDBusConnection *dbus_connection; - - /* used during g_bus_get() and later during mm_manager_new(). */ - GCancellable *main_cancellable; - - struct { - MMManager * manager; - GCancellable *poke_cancellable; - gulong handle_name_owner_changed_id; - gulong handle_object_added_id; - gulong handle_object_removed_id; - guint relaunch_id; - - /* this only has one use: that the <info> logging line about - * ModemManager available distinguishes between first-time - * and later name-owner-changed. */ - enum { - LOG_AVAILABLE_NOT_INITIALIZED = 0, - LOG_AVAILABLE_YES, - LOG_AVAILABLE_NO, - } log_available : 3; - - GDBusProxy * proxy; - GCancellable *proxy_cancellable; - guint proxy_ref_count; - char * proxy_name_owner; - } modm; - -#if WITH_OFONO - struct { - GDBusProxy * proxy; - GCancellable *cancellable; - } ofono; -#endif - - GHashTable *modems; -} NMModemManagerPrivate; - -struct _NMModemManager { - GObject parent; - NMModemManagerPrivate _priv; -}; - -struct _NMModemManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE(NMModemManager, nm_modem_manager, G_TYPE_OBJECT) - -#define NM_MODEM_MANAGER_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMModemManager, NM_IS_MODEM_MANAGER) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_MB -#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "modem-manager", __VA_ARGS__) - -/*****************************************************************************/ - -NM_DEFINE_SINGLETON_GETTER(NMModemManager, nm_modem_manager_get, NM_TYPE_MODEM_MANAGER); - -/*****************************************************************************/ - -static void modm_schedule_manager_relaunch(NMModemManager *self, guint n_seconds); -static void modm_ensure_manager(NMModemManager *self); - -/*****************************************************************************/ - -static void -handle_new_modem(NMModemManager *self, NMModem *modem) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - const char * path; - - path = nm_modem_get_path(modem); - if (g_hash_table_lookup(priv->modems, path)) { - g_warn_if_reached(); - return; - } - - /* Track the new modem */ - g_hash_table_insert(priv->modems, g_strdup(path), modem); - g_signal_emit(self, signals[MODEM_ADDED], 0, modem); -} - -static gboolean -remove_one_modem(gpointer key, gpointer value, gpointer user_data) -{ - nm_modem_emit_removed(NM_MODEM(value)); - return TRUE; -} - -/*****************************************************************************/ - -NMModem ** -nm_modem_manager_get_modems(NMModemManager *self, guint *out_len) -{ - g_return_val_if_fail(NM_IS_MODEM_MANAGER(self), NULL); - - return (NMModem **) nm_utils_hash_values_to_array(NM_MODEM_MANAGER_GET_PRIVATE(self)->modems, - NULL, - NULL, - out_len); -} - -/*****************************************************************************/ - -static void -modm_clear_manager(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - if (!priv->modm.manager) - return; - nm_clear_g_signal_handler(priv->modm.manager, &priv->modm.handle_name_owner_changed_id); - nm_clear_g_signal_handler(priv->modm.manager, &priv->modm.handle_object_added_id); - nm_clear_g_signal_handler(priv->modm.manager, &priv->modm.handle_object_removed_id); - g_clear_object(&priv->modm.manager); -} - -static void -modm_handle_object_added(MMManager *modem_manager, MMObject *modem_object, NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - const char * path; - MMModem * modem_iface; - NMModem * modem; - GError * error = NULL; - - /* Ensure we don't have the same modem already */ - path = mm_object_get_path(modem_object); - if (g_hash_table_lookup(priv->modems, path)) { - _LOGW("modem with path %s already exists, ignoring", path); - return; - } - - /* Ensure we have the 'Modem' interface at least */ - modem_iface = mm_object_peek_modem(modem_object); - if (!modem_iface) { - _LOGW("modem with path %s doesn't have the Modem interface, ignoring", path); - return; - } - - /* Ensure we have a primary port reported */ - if (!mm_modem_get_primary_port(modem_iface)) { - _LOGW("modem with path %s has unknown primary port, ignoring", path); - return; - } - - /* Create a new modem object */ - modem = nm_modem_broadband_new(G_OBJECT(modem_object), &error); - if (modem) - handle_new_modem(self, modem); - else - _LOGW("failed to create modem: %s", error->message); - g_clear_error(&error); -} - -static void -modm_handle_object_removed(MMManager *manager, MMObject *modem_object, NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - NMModem * modem; - const char * path; - - path = mm_object_get_path(modem_object); - modem = (NMModem *) g_hash_table_lookup(priv->modems, path); - if (!modem) - return; - - nm_modem_emit_removed(modem); - g_hash_table_remove(priv->modems, path); -} - -static void -modm_manager_available(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - GList * modems, *l; - - if (priv->modm.log_available != LOG_AVAILABLE_YES) { - _LOGI("ModemManager %savailable", priv->modm.log_available ? "now " : ""); - priv->modm.log_available = LOG_AVAILABLE_YES; - } - - /* Update initial modems list */ - modems = g_dbus_object_manager_get_objects(G_DBUS_OBJECT_MANAGER(priv->modm.manager)); - for (l = modems; l; l = g_list_next(l)) - modm_handle_object_added(priv->modm.manager, MM_OBJECT(l->data), self); - g_list_free_full(modems, (GDestroyNotify) g_object_unref); -} - -static void -modm_handle_name_owner_changed(MMManager *modem_manager, GParamSpec *pspec, NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - char * name_owner; - - /* Quit poking, if any */ - nm_clear_g_source(&priv->modm.relaunch_id); - - name_owner = - g_dbus_object_manager_client_get_name_owner(G_DBUS_OBJECT_MANAGER_CLIENT(modem_manager)); - if (!name_owner) { - if (priv->modm.log_available != LOG_AVAILABLE_NO) { - _LOGI("ModemManager %savailable", priv->modm.log_available ? "no longer " : "not "); - priv->modm.log_available = LOG_AVAILABLE_NO; - } - - /* If not managed by systemd, schedule relaunch */ - if (!sd_booted()) - modm_schedule_manager_relaunch(self, 0); - - return; - } - - /* Available! */ - g_free(name_owner); - - /* Hack alert: GDBusObjectManagerClient won't signal neither 'object-added' - * nor 'object-removed' if it was created while there was no ModemManager in - * the bus. This hack avoids this issue until we get a GIO with the fix - * included... */ - modm_clear_manager(self); - modm_ensure_manager(self); - - /* Whenever GDBusObjectManagerClient is fixed, we can just do the following: - * modm_manager_available (self); - */ -} - -static void -modm_manager_poke_cb(GObject *connection, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *result = NULL; - - result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(connection), res, &error); - - if (!result && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->modm.poke_cancellable); - - if (error) { - _LOGW("error poking ModemManager: %s", error->message); - - /* Don't reschedule poke is MM service doesn't exist. */ - if (!g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) - && !g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND)) { - /* Setup timeout to relaunch */ - modm_schedule_manager_relaunch(self, MODEM_POKE_INTERVAL); - } - } -} - -static void -modm_manager_poke(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - nm_clear_g_cancellable(&priv->modm.poke_cancellable); - priv->modm.poke_cancellable = g_cancellable_new(); - - /* If there is no current owner right away, ensure we poke to get one */ - g_dbus_connection_call(priv->dbus_connection, - NM_MODEM_MANAGER_MM_DBUS_SERVICE, - NM_MODEM_MANAGER_MM_DBUS_PATH, - DBUS_INTERFACE_PEER, - "Ping", - NULL, - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->modm.poke_cancellable, - modm_manager_poke_cb, - self); -} - -static void -modm_manager_check_name_owner(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - gs_free char * name_owner = NULL; - - name_owner = g_dbus_object_manager_client_get_name_owner( - G_DBUS_OBJECT_MANAGER_CLIENT(priv->modm.manager)); - if (name_owner) { - modm_manager_available(self); - return; - } - - /* If the lifecycle is not managed by systemd, poke */ - if (!sd_booted()) - modm_manager_poke(self); -} - -static void -modm_manager_new_cb(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - MMManager * modem_manager; - - modem_manager = mm_manager_new_finish(res, &error); - if (!modem_manager && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - nm_assert(!priv->modm.manager); - - g_clear_object(&priv->main_cancellable); - - if (!modem_manager) { - /* We're not really supposed to get any error here. If we do get one, - * though, just re-schedule the MMManager creation after some time. - * During this period, name-owner changes won't be followed. */ - _LOGW("error creating ModemManager client: %s", error->message); - /* Setup timeout to relaunch */ - modm_schedule_manager_relaunch(self, MODEM_POKE_INTERVAL); - return; - } - - priv->modm.manager = modem_manager; - - /* Setup signals in the GDBusObjectManagerClient */ - priv->modm.handle_name_owner_changed_id = - g_signal_connect(priv->modm.manager, - "notify::name-owner", - G_CALLBACK(modm_handle_name_owner_changed), - self); - priv->modm.handle_object_added_id = g_signal_connect(priv->modm.manager, - "object-added", - G_CALLBACK(modm_handle_object_added), - self); - priv->modm.handle_object_removed_id = g_signal_connect(priv->modm.manager, - "object-removed", - G_CALLBACK(modm_handle_object_removed), - self); - - modm_manager_check_name_owner(self); -} - -static void -modm_ensure_manager(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_assert(priv->dbus_connection); - - /* Create the GDBusObjectManagerClient. We do not request to autostart, as - * we don't really want the MMManager creation to fail. We can always poke - * later on if we want to request the autostart */ - if (!priv->modm.manager) { - if (!priv->main_cancellable) - priv->main_cancellable = g_cancellable_new(); - mm_manager_new(priv->dbus_connection, - G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, - priv->main_cancellable, - modm_manager_new_cb, - self); - return; - } - - /* If already available, recheck name owner! */ - modm_manager_check_name_owner(self); -} - -static gboolean -modm_schedule_manager_relaunch_cb(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - priv->modm.relaunch_id = 0; - modm_ensure_manager(self); - return G_SOURCE_REMOVE; -} - -static void -modm_schedule_manager_relaunch(NMModemManager *self, guint n_seconds) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - /* No need to pass an extra reference to self; timeout/idle will be - * cancelled if the object gets disposed. */ - if (n_seconds) - priv->modm.relaunch_id = - g_timeout_add_seconds(n_seconds, (GSourceFunc) modm_schedule_manager_relaunch_cb, self); - else - priv->modm.relaunch_id = g_idle_add((GSourceFunc) modm_schedule_manager_relaunch_cb, self); -} - -/*****************************************************************************/ - -static void -modm_proxy_name_owner_reset(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - char * name = NULL; - - if (priv->modm.proxy) - name = g_dbus_proxy_get_name_owner(priv->modm.proxy); - - if (nm_streq0(priv->modm.proxy_name_owner, name)) { - g_free(name); - return; - } - g_free(priv->modm.proxy_name_owner); - priv->modm.proxy_name_owner = name; - - _notify(self, PROP_NAME_OWNER); -} - -static void -modm_proxy_name_owner_changed_cb(GObject *object, GParamSpec *pspec, gpointer user_data) -{ - modm_proxy_name_owner_reset(user_data); -} - -static void -modm_proxy_new_cb(GObject *source_object, GAsyncResult *result, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - GDBusProxy * proxy; - gs_free_error GError *error = NULL; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->modm.proxy_cancellable); - - if (!proxy) { - _LOGW("could not obtain D-Bus proxy for ModemManager: %s", error->message); - return; - } - - priv->modm.proxy = proxy; - g_signal_connect(priv->modm.proxy, - "notify::g-name-owner", - G_CALLBACK(modm_proxy_name_owner_changed_cb), - self); - - modm_proxy_name_owner_reset(self); -} - -void -nm_modem_manager_name_owner_ref(NMModemManager *self) -{ - NMModemManagerPrivate *priv; - - g_return_if_fail(NM_IS_MODEM_MANAGER(self)); - - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - if (priv->modm.proxy_ref_count++ > 0) { - /* only try once to create the proxy. If proxy creation - * for the first "ref" failed, it's unclear what to do. - * The proxy is hosed. */ - return; - } - - nm_assert(!priv->modm.proxy && !priv->modm.proxy_cancellable); - - priv->modm.proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - NM_MODEM_MANAGER_MM_DBUS_SERVICE, - NM_MODEM_MANAGER_MM_DBUS_PATH, - NM_MODEM_MANAGER_MM_DBUS_INTERFACE, - priv->modm.proxy_cancellable, - modm_proxy_new_cb, - self); -} - -void -nm_modem_manager_name_owner_unref(NMModemManager *self) -{ - NMModemManagerPrivate *priv; - - g_return_if_fail(NM_IS_MODEM_MANAGER(self)); - - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_return_if_fail(priv->modm.proxy_ref_count > 0); - - if (--priv->modm.proxy_ref_count > 0) - return; - - nm_clear_g_cancellable(&priv->modm.proxy_cancellable); - g_clear_object(&priv->modm.proxy); - - modm_proxy_name_owner_reset(self); -} - -const char * -nm_modem_manager_name_owner_get(NMModemManager *self) -{ - g_return_val_if_fail(NM_IS_MODEM_MANAGER(self), NULL); - nm_assert(NM_MODEM_MANAGER_GET_PRIVATE(self)->modm.proxy_ref_count > 0); - - return NM_MODEM_MANAGER_GET_PRIVATE(self)->modm.proxy_name_owner; -} - -/*****************************************************************************/ - -#if WITH_OFONO - -static void -ofono_create_modem(NMModemManager *self, const char *path) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - NMModem * modem = NULL; - - /* Ensure duplicate modems aren't created. Because we're not using the - * ObjectManager interface there's a race during oFono startup where we - * receive ModemAdded signals before GetModems() returns, so some of the - * modems returned from GetModems() may already have been created. - */ - if (!g_hash_table_lookup(priv->modems, path)) { - modem = nm_modem_ofono_new(path); - if (modem) - handle_new_modem(self, modem); - else - _LOGW("Failed to create oFono modem for %s", path); - } -} - -static void -ofono_signal_cb(GDBusProxy *proxy, - char * sender_name, - char * signal_name, - GVariant * parameters, - gpointer user_data) -{ - NMModemManager * self = NM_MODEM_MANAGER(user_data); - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - char * object_path; - NMModem * modem; - - if (g_strcmp0(signal_name, "ModemAdded") == 0) { - g_variant_get(parameters, "(oa{sv})", &object_path, NULL); - _LOGI("oFono modem appeared: %s", object_path); - - ofono_create_modem(NM_MODEM_MANAGER(user_data), object_path); - g_free(object_path); - } else if (g_strcmp0(signal_name, "ModemRemoved") == 0) { - g_variant_get(parameters, "(o)", &object_path); - _LOGI("oFono modem removed: %s", object_path); - - modem = (NMModem *) g_hash_table_lookup(priv->modems, object_path); - if (modem) { - nm_modem_emit_removed(modem); - g_hash_table_remove(priv->modems, object_path); - } else { - _LOGW("could not remove modem %s, not found in table", object_path); - } - g_free(object_path); - } -} - -static void -ofono_enumerate_devices_done(GObject *proxy, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - GVariant * results; - GVariantIter * iter; - const char * path; - - results = g_dbus_proxy_call_finish(G_DBUS_PROXY(proxy), res, &error); - if (!results && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_MANAGER(user_data); - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->ofono.cancellable); - - if (!results) { - _LOGW("failed to enumerate oFono devices: %s", error->message); - return; - } - - g_variant_get(results, "(a(oa{sv}))", &iter); - while (g_variant_iter_loop(iter, "(&oa{sv})", &path, NULL)) - ofono_create_modem(self, path); - g_variant_iter_free(iter); - g_variant_unref(results); -} - -static void -ofono_check_name_owner(NMModemManager *self, gboolean first_invocation) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - gs_free char * name_owner = NULL; - - name_owner = g_dbus_proxy_get_name_owner(G_DBUS_PROXY(priv->ofono.proxy)); - if (name_owner) { - _LOGI("oFono is %savailable", first_invocation ? "" : "now "); - - nm_clear_g_cancellable(&priv->ofono.cancellable); - priv->ofono.cancellable = g_cancellable_new(); - - g_dbus_proxy_call(priv->ofono.proxy, - "GetModems", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->ofono.cancellable, - ofono_enumerate_devices_done, - self); - } else { - GHashTableIter iter; - NMModem * modem; - - _LOGI("oFono is %savailable", first_invocation ? "not " : "no longer "); - - /* Remove any oFono modems that might be left around */ - g_hash_table_iter_init(&iter, priv->modems); - while (g_hash_table_iter_next(&iter, NULL, (gpointer) &modem)) { - if (NM_IS_MODEM_OFONO(modem)) { - nm_modem_emit_removed(modem); - g_hash_table_iter_remove(&iter); - } - } - } -} - -static void -ofono_name_owner_changed(GDBusProxy *ofono_proxy, GParamSpec *pspec, NMModemManager *self) -{ - ofono_check_name_owner(self, FALSE); -} - -static void -ofono_proxy_new_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_finish(res, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_MANAGER(user_data); - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - g_clear_object(&priv->ofono.cancellable); - - if (!proxy) { - _LOGW("error getting oFono bus proxy: %s", error->message); - return; - } - - priv->ofono.proxy = proxy; - - g_signal_connect(priv->ofono.proxy, - "notify::g-name-owner", - G_CALLBACK(ofono_name_owner_changed), - self); - - g_signal_connect(priv->ofono.proxy, "g-signal", G_CALLBACK(ofono_signal_cb), self); - - ofono_check_name_owner(self, TRUE); -} - -static void -ofono_init_proxy(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - nm_assert(priv->dbus_connection); - nm_assert(!priv->ofono.cancellable); - - priv->ofono.cancellable = g_cancellable_new(); - - g_dbus_proxy_new(priv->dbus_connection, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - OFONO_DBUS_PATH, - OFONO_DBUS_INTERFACE, - priv->ofono.cancellable, - ofono_proxy_new_cb, - self); -} -#endif - -/*****************************************************************************/ - -static void -bus_get_ready(GObject *source, GAsyncResult *res, gpointer user_data) -{ - NMModemManager * self; - NMModemManagerPrivate *priv; - gs_free_error GError *error = NULL; - GDBusConnection * connection; - - connection = g_bus_get_finish(res, &error); - if (!connection && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_MANAGER(user_data); - priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - if (!connection) { - _LOGW("error getting bus connection: %s", error->message); - return; - } - - priv->dbus_connection = connection; - - modm_ensure_manager(self); -#if WITH_OFONO - ofono_init_proxy(self); -#endif -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMModemManager * self = NM_MODEM_MANAGER(object); - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_NAME_OWNER: - g_value_set_string(value, priv->modm.proxy_name_owner); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_modem_manager_init(NMModemManager *self) -{ - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - priv->modems = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_object_unref); - - priv->main_cancellable = g_cancellable_new(); - - g_bus_get(G_BUS_TYPE_SYSTEM, priv->main_cancellable, bus_get_ready, self); -} - -static void -dispose(GObject *object) -{ - NMModemManager * self = NM_MODEM_MANAGER(object); - NMModemManagerPrivate *priv = NM_MODEM_MANAGER_GET_PRIVATE(self); - - nm_clear_g_cancellable(&priv->main_cancellable); - nm_clear_g_cancellable(&priv->modm.poke_cancellable); - - nm_clear_g_source(&priv->modm.relaunch_id); - - nm_clear_g_cancellable(&priv->modm.proxy_cancellable); - g_clear_object(&priv->modm.proxy); - nm_clear_g_free(&priv->modm.proxy_name_owner); - - modm_clear_manager(self); - -#if WITH_OFONO - if (priv->ofono.proxy) { - g_signal_handlers_disconnect_by_func(priv->ofono.proxy, ofono_name_owner_changed, self); - g_signal_handlers_disconnect_by_func(priv->ofono.proxy, ofono_signal_cb, self); - g_clear_object(&priv->ofono.proxy); - } - nm_clear_g_cancellable(&priv->ofono.cancellable); -#endif - - g_clear_object(&priv->dbus_connection); - - if (priv->modems) { - g_hash_table_foreach_remove(priv->modems, remove_one_modem, object); - g_hash_table_destroy(priv->modems); - priv->modems = NULL; - } - - G_OBJECT_CLASS(nm_modem_manager_parent_class)->dispose(object); -} - -static void -nm_modem_manager_class_init(NMModemManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - - object_class->dispose = dispose; - object_class->get_property = get_property; - - obj_properties[PROP_NAME_OWNER] = - g_param_spec_string(NM_MODEM_MANAGER_NAME_OWNER, - "", - "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[MODEM_ADDED] = g_signal_new(NM_MODEM_MANAGER_MODEM_ADDED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - NM_TYPE_MODEM); -} diff --git a/src/devices/wwan/nm-modem-manager.h b/src/devices/wwan/nm-modem-manager.h deleted file mode 100644 index 895d4ced..00000000 --- a/src/devices/wwan/nm-modem-manager.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2014 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - * Copyright (C) 2009 Canonical Ltd. - */ - -#ifndef __NETWORKMANAGER_MODEM_MANAGER_H__ -#define __NETWORKMANAGER_MODEM_MANAGER_H__ - -#include "nm-modem.h" - -#define NM_TYPE_MODEM_MANAGER (nm_modem_manager_get_type()) -#define NM_MODEM_MANAGER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_MANAGER, NMModemManager)) -#define NM_MODEM_MANAGER_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) -#define NM_IS_MODEM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_MANAGER)) -#define NM_IS_MODEM_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM_MANAGER)) -#define NM_MODEM_MANAGER_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MODEM_MANAGER, NMModemManagerClass)) - -#define NM_MODEM_MANAGER_MODEM_ADDED "modem-added" - -#define NM_MODEM_MANAGER_NAME_OWNER "name-owner" - -#define NM_MODEM_MANAGER_MM_DBUS_SERVICE "org.freedesktop.ModemManager1" -#define NM_MODEM_MANAGER_MM_DBUS_PATH "/org/freedesktop/ModemManager1" -#define NM_MODEM_MANAGER_MM_DBUS_INTERFACE "org.freedesktop.ModemManager1" - -typedef struct _NMModemManager NMModemManager; -typedef struct _NMModemManagerClass NMModemManagerClass; - -GType nm_modem_manager_get_type(void); - -NMModemManager *nm_modem_manager_get(void); - -void nm_modem_manager_name_owner_ref(NMModemManager *self); -void nm_modem_manager_name_owner_unref(NMModemManager *self); - -const char *nm_modem_manager_name_owner_get(NMModemManager *self); - -NMModem **nm_modem_manager_get_modems(NMModemManager *self, guint *out_len); - -#endif /* __NETWORKMANAGER_MODEM_MANAGER_H__ */ diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c deleted file mode 100644 index d8d0893b..00000000 --- a/src/devices/wwan/nm-modem-ofono.c +++ /dev/null @@ -1,1239 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - 2016 Canonical Ltd. - */ - -#include "nm-default.h" - -#include "nm-modem-ofono.h" - -#include "nm-core-internal.h" -#include "devices/nm-device-private.h" -#include "nm-modem.h" -#include "platform/nm-platform.h" -#include "nm-ip4-config.h" - -#define VARIANT_IS_OF_TYPE_BOOLEAN(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_BOOLEAN))) -#define VARIANT_IS_OF_TYPE_STRING(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_STRING))) -#define VARIANT_IS_OF_TYPE_OBJECT_PATH(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_OBJECT_PATH))) -#define VARIANT_IS_OF_TYPE_STRING_ARRAY(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_STRING_ARRAY))) -#define VARIANT_IS_OF_TYPE_DICTIONARY(v) \ - ((v) != NULL && (g_variant_is_of_type((v), G_VARIANT_TYPE_DICTIONARY))) - -/*****************************************************************************/ - -typedef struct { - GHashTable *connect_properties; - - GDBusProxy *modem_proxy; - GDBusProxy *connman_proxy; - GDBusProxy *context_proxy; - GDBusProxy *sim_proxy; - - GCancellable *modem_proxy_cancellable; - GCancellable *connman_proxy_cancellable; - GCancellable *context_proxy_cancellable; - GCancellable *sim_proxy_cancellable; - - GError *property_error; - - char *context_path; - char *imsi; - - gboolean modem_online; - gboolean gprs_attached; - - NMIP4Config *ip4_config; -} NMModemOfonoPrivate; - -struct _NMModemOfono { - NMModem parent; - NMModemOfonoPrivate _priv; -}; - -struct _NMModemOfonoClass { - NMModemClass parent; -}; - -G_DEFINE_TYPE(NMModemOfono, nm_modem_ofono, NM_TYPE_MODEM) - -#define NM_MODEM_OFONO_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMModemOfono, NM_IS_MODEM_OFONO) - -/*****************************************************************************/ - -#define _NMLOG_DOMAIN LOGD_MB -#define _NMLOG_PREFIX_NAME "modem-ofono" -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel _level = (level); \ - \ - if (nm_logging_enabled(_level, (_NMLOG_DOMAIN))) { \ - NMModemOfono *const __self = (self); \ - char __prefix_name[128]; \ - const char * __uid; \ - \ - _nm_log(_level, \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - (__self ? ({ \ - ((__uid = nm_modem_get_uid((NMModem *) __self)) \ - ? nm_sprintf_buf(__prefix_name, "[%s]", __uid) \ - : "(null)"); \ - }) \ - : "") _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static void -get_capabilities(NMModem * _self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps) -{ - /* FIXME: auto-detect capabilities to allow LTE */ - *modem_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; - *current_caps = NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS; -} - -static void -update_modem_state(NMModemOfono *self) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - NMModemState state = nm_modem_get_state(NM_MODEM(self)); - NMModemState new_state = NM_MODEM_STATE_DISABLED; - const char * reason = NULL; - - _LOGI("'Attached': %s 'Online': %s 'IMSI': %s", - priv->gprs_attached ? "true" : "false", - priv->modem_online ? "true" : "false", - priv->imsi); - - if (priv->modem_online == FALSE) { - reason = "modem 'Online=false'"; - } else if (priv->imsi == NULL && state != NM_MODEM_STATE_ENABLING) { - reason = "modem not ready"; - } else if (priv->gprs_attached == FALSE) { - new_state = NM_MODEM_STATE_SEARCHING; - reason = "modem searching"; - } else { - new_state = NM_MODEM_STATE_REGISTERED; - reason = "modem ready"; - } - - if (state != new_state) - nm_modem_set_state(NM_MODEM(self), new_state, reason); -} - -/* Disconnect */ -typedef struct { - NMModemOfono * self; - _NMModemDisconnectCallback callback; - gpointer callback_user_data; - GCancellable * cancellable; - gboolean warn; -} DisconnectContext; - -static void -disconnect_context_complete(DisconnectContext *ctx, GError *error) -{ - if (ctx->callback) - ctx->callback(NM_MODEM(ctx->self), error, ctx->callback_user_data); - nm_g_object_unref(ctx->cancellable); - g_object_unref(ctx->self); - g_slice_free(DisconnectContext, ctx); -} - -static void -disconnect_context_complete_on_idle(gpointer user_data, GCancellable *cancellable) -{ - DisconnectContext *ctx = user_data; - gs_free_error GError *error = NULL; - - if (!g_cancellable_set_error_if_cancelled(cancellable, &error)) { - g_set_error_literal(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - ("modem is currently not connected")); - } - disconnect_context_complete(ctx, error); -} - -static void -disconnect_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - DisconnectContext *ctx = user_data; - NMModemOfono * self = ctx->self; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v = NULL; - - v = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, &error); - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { - disconnect_context_complete(ctx, error); - return; - } - - if (error && ctx->warn) - _LOGW("failed to disconnect modem: %s", error->message); - - _LOGD("modem disconnected"); - - update_modem_state(self); - disconnect_context_complete(ctx, error); -} - -static void -disconnect(NMModem * modem, - gboolean warn, - GCancellable * cancellable, - _NMModemDisconnectCallback callback, - gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - DisconnectContext * ctx; - NMModemState state = nm_modem_get_state(NM_MODEM(self)); - - _LOGD("warn: %s modem_state: %s", warn ? "TRUE" : "FALSE", nm_modem_state_to_string(state)); - - ctx = g_slice_new0(DisconnectContext); - ctx->self = g_object_ref(self); - ctx->cancellable = nm_g_object_ref(cancellable); - ctx->warn = warn; - ctx->callback = callback; - ctx->callback_user_data = user_data; - - if (state != NM_MODEM_STATE_CONNECTED || g_cancellable_is_cancelled(cancellable)) { - nm_utils_invoke_on_idle(cancellable, disconnect_context_complete_on_idle, ctx); - return; - } - - nm_modem_set_state(NM_MODEM(self), - NM_MODEM_STATE_DISCONNECTING, - nm_modem_state_to_string(NM_MODEM_STATE_DISCONNECTING)); - - g_dbus_proxy_call(priv->context_proxy, - "SetProperty", - g_variant_new("(sv)", "Active", g_variant_new("b", warn)), - G_DBUS_CALL_FLAGS_NONE, - 20000, - ctx->cancellable, - disconnect_done, - ctx); -} - -static void -deactivate_cleanup(NMModem *modem, NMDevice *device, gboolean stop_ppp_manager) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - /* TODO: cancel SimpleConnect() if any */ - - g_clear_object(&priv->ip4_config); - - NM_MODEM_CLASS(nm_modem_ofono_parent_class) - ->deactivate_cleanup(modem, device, stop_ppp_manager); -} - -static gboolean -check_connection_compatible_with_modem(NMModem *modem, NMConnection *connection, GError **error) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char * id; - - if (!_nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, NULL)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_INCOMPATIBLE, - "connection type %s is not supported by ofono modem", - nm_connection_get_connection_type(connection)); - return FALSE; - } - - if (!priv->imsi) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "modem has no IMSI"); - return FALSE; - } - - id = nm_connection_get_id(connection); - - if (!strstr(id, "/context")) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID has no context"); - return FALSE; - } - - if (!strstr(id, priv->imsi)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "the connection ID does not contain the IMSI"); - return FALSE; - } - - return TRUE; -} - -static void -handle_sim_property(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (g_strcmp0(property, "SubscriberIdentity") == 0 && VARIANT_IS_OF_TYPE_STRING(v)) { - gsize length; - const char *value_str = g_variant_get_string(v, &length); - - _LOGD("SubscriberIdentify found"); - - /* Check for empty DBus string value */ - if (length && g_strcmp0(value_str, "(null)") != 0 - && g_strcmp0(value_str, priv->imsi) != 0) { - if (priv->imsi != NULL) { - _LOGW("SimManager:'SubscriberIdentity' changed: %s", priv->imsi); - g_free(priv->imsi); - } - - priv->imsi = g_strdup(value_str); - update_modem_state(self); - } - } -} - -static void -sim_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - GVariant *v_child = g_variant_get_child_value(v, 0); - - handle_sim_property(proxy, property, v_child, user_data); - g_variant_unref(v_child); -} - -static void -sim_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v_properties = NULL; - gs_unref_variant GVariant *v_dict = NULL; - GVariant * v; - GVariantIter i; - const char * property; - - v_properties = - _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, G_VARIANT_TYPE("(a{sv})"), &error); - if (!v_properties && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->sim_proxy_cancellable); - - if (!v_properties) { - g_dbus_error_strip_remote_error(error); - _LOGW("error getting sim properties: %s", error->message); - return; - } - - _LOGD("sim v_properties is type: %s", g_variant_get_type_string(v_properties)); - - v_dict = g_variant_get_child_value(v_properties, 0); - if (!v_dict) { - _LOGW("error getting sim properties: no v_dict"); - return; - } - - _LOGD("sim v_dict is type: %s", g_variant_get_type_string(v_dict)); - - /* - * TODO: - * 1) optimize by looking up properties ( Online, Interfaces ), instead - * of iterating - * - * 2) reduce code duplication between all of the get_properties_done - * functions in this class. - */ - - g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { - handle_sim_property(NULL, property, v, self); - g_variant_unref(v); - } -} - -static void -_sim_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (!proxy) { - _LOGW("failed to create SimManager proxy: %s", error->message); - g_clear_object(&priv->sim_proxy_cancellable); - return; - } - - priv->sim_proxy = proxy; - - /* Watch for custom ofono PropertyChanged signals */ - _nm_dbus_signal_connect(priv->sim_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(sim_property_changed), - self); - - g_dbus_proxy_call(priv->sim_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - priv->sim_proxy_cancellable, - sim_get_properties_done, - self); -} - -static void -handle_sim_iface(NMModemOfono *self, gboolean found) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - _LOGD("SimManager interface %sfound", found ? "" : "not "); - - if (!found && (priv->sim_proxy || priv->sim_proxy_cancellable)) { - _LOGI("SimManager interface disappeared"); - nm_clear_g_cancellable(&priv->sim_proxy_cancellable); - if (priv->sim_proxy) { - g_signal_handlers_disconnect_by_data(priv->sim_proxy, self); - g_clear_object(&priv->sim_proxy); - } - nm_clear_g_free(&priv->imsi); - update_modem_state(self); - } else if (found && (!priv->sim_proxy && !priv->sim_proxy_cancellable)) { - _LOGI("found new SimManager interface"); - - priv->sim_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* GDBusInterfaceInfo */ - OFONO_DBUS_SERVICE, - nm_modem_get_path(NM_MODEM(self)), - OFONO_DBUS_INTERFACE_SIM_MANAGER, - priv->sim_proxy_cancellable, /* GCancellable */ - _sim_proxy_new_cb, - self); - } -} - -static void -handle_connman_property(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (g_strcmp0(property, "Attached") == 0 && VARIANT_IS_OF_TYPE_BOOLEAN(v)) { - gboolean attached = g_variant_get_boolean(v); - gboolean old_attached = priv->gprs_attached; - - _LOGD("Attached: %s", attached ? "True" : "False"); - - if (priv->gprs_attached != attached) { - priv->gprs_attached = attached; - - _LOGI("Attached %s -> %s", - old_attached ? "true" : "false", - attached ? "true" : "false"); - - update_modem_state(self); - } - } -} - -static void -connman_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - GVariant *v_child = g_variant_get_child_value(v, 0); - - handle_connman_property(proxy, property, v_child, user_data); - g_variant_unref(v_child); -} - -static void -connman_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v_properties = NULL; - gs_unref_variant GVariant *v_dict = NULL; - GVariant * v; - GVariantIter i; - const char * property; - - v_properties = - _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, G_VARIANT_TYPE("(a{sv})"), &error); - if (!v_properties && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->connman_proxy_cancellable); - - if (!v_properties) { - g_dbus_error_strip_remote_error(error); - _LOGW("error getting connman properties: %s", error->message); - return; - } - - v_dict = g_variant_get_child_value(v_properties, 0); - - /* - * TODO: - * 1) optimize by looking up properties ( Online, Interfaces ), instead - * of iterating - * - * 2) reduce code duplication between all of the get_properties_done - * functions in this class. - */ - - g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { - handle_connman_property(NULL, property, v, self); - g_variant_unref(v); - } -} - -static void -_connman_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = user_data; - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (!proxy) { - _LOGW("failed to create ConnectionManager proxy: %s", error->message); - g_clear_object(&priv->connman_proxy_cancellable); - return; - } - - priv->connman_proxy = proxy; - - _nm_dbus_signal_connect(priv->connman_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(connman_property_changed), - self); - - g_dbus_proxy_call(priv->connman_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - priv->connman_proxy_cancellable, - connman_get_properties_done, - self); -} - -static void -handle_connman_iface(NMModemOfono *self, gboolean found) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - _LOGD("ConnectionManager interface %sfound", found ? "" : "not "); - - if (!found && (priv->connman_proxy || priv->connman_proxy_cancellable)) { - _LOGI("ConnectionManager interface disappeared"); - nm_clear_g_cancellable(&priv->connman_proxy_cancellable); - if (priv->connman_proxy) { - g_signal_handlers_disconnect_by_data(priv->connman_proxy, self); - g_clear_object(&priv->connman_proxy); - } - - /* The connection manager proxy disappeared, we should - * consider the modem disabled. - */ - priv->gprs_attached = FALSE; - - update_modem_state(self); - } else if (found && (!priv->connman_proxy && !priv->connman_proxy_cancellable)) { - _LOGI("found new ConnectionManager interface"); - - priv->connman_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, /* GDBusInterfaceInfo */ - OFONO_DBUS_SERVICE, - nm_modem_get_path(NM_MODEM(self)), - OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, - priv->connman_proxy_cancellable, - _connman_proxy_new_cb, - self); - } -} - -static void -handle_modem_property(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if ((g_strcmp0(property, "Online") == 0) && VARIANT_IS_OF_TYPE_BOOLEAN(v)) { - gboolean online = g_variant_get_boolean(v); - - _LOGD("Online: %s", online ? "True" : "False"); - - if (online != priv->modem_online) { - priv->modem_online = online; - _LOGI("modem is now %s", online ? "Online" : "Offline"); - update_modem_state(self); - } - - } else if ((g_strcmp0(property, "Interfaces") == 0) && VARIANT_IS_OF_TYPE_STRING_ARRAY(v)) { - const char **array, **iter; - gboolean found_connman = FALSE; - gboolean found_sim = FALSE; - - _LOGD("Interfaces found"); - - array = g_variant_get_strv(v, NULL); - if (array) { - for (iter = array; *iter; iter++) { - if (g_strcmp0(OFONO_DBUS_INTERFACE_SIM_MANAGER, *iter) == 0) - found_sim = TRUE; - else if (g_strcmp0(OFONO_DBUS_INTERFACE_CONNECTION_MANAGER, *iter) == 0) - found_connman = TRUE; - } - g_free(array); - } - - handle_sim_iface(self, found_sim); - handle_connman_iface(self, found_connman); - } -} - -static void -modem_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - GVariant *v_child = g_variant_get_child_value(v, 0); - - handle_modem_property(proxy, property, v_child, user_data); - g_variant_unref(v_child); -} - -static void -modem_get_properties_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v_properties = NULL; - gs_unref_variant GVariant *v_dict = NULL; - GVariant * v; - GVariantIter i; - const char * property; - - v_properties = - _nm_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, G_VARIANT_TYPE("(a{sv})"), &error); - if (!v_properties && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->modem_proxy_cancellable); - - if (!v_properties) { - g_dbus_error_strip_remote_error(error); - _LOGW("error getting modem properties: %s", error->message); - return; - } - - v_dict = g_variant_get_child_value(v_properties, 0); - if (!v_dict) { - _LOGW("error getting modem properties: no v_dict"); - return; - } - - /* - * TODO: - * 1) optimize by looking up properties ( Online, Interfaces ), instead - * of iterating - * - * 2) reduce code duplication between all of the get_properties_done - * functions in this class. - */ - - g_variant_iter_init(&i, v_dict); - while (g_variant_iter_next(&i, "{&sv}", &property, &v)) { - handle_modem_property(NULL, property, v, self); - g_variant_unref(v); - } -} - -static void -stage1_prepare_done(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *v = NULL; - - v = g_dbus_proxy_call_finish(G_DBUS_PROXY(source), result, &error); - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_clear_object(&priv->context_proxy_cancellable); - - nm_clear_pointer(&priv->connect_properties, g_hash_table_destroy); - - if (error) { - _LOGW("connection failed: %s", error->message); - - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); - /* - * FIXME: add code to check for InProgress so that the - * connection doesn't continue to try and activate, - * leading to the connection being disabled, and a 5m - * timeout... - */ - } -} - -static void -context_property_changed(GDBusProxy *proxy, const char *property, GVariant *v, gpointer user_data) -{ - NMModemOfono * self = NM_MODEM_OFONO(user_data); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - NMPlatformIP4Address addr; - gboolean ret = FALSE; - gs_unref_variant GVariant *v_dict = NULL; - const char * interface; - const char * s; - const char ** array, **iter; - guint32 address_network, gateway_network; - guint32 ip4_route_table, ip4_route_metric; - int ifindex; - GError * error = NULL; - - _LOGD("PropertyChanged: %s", property); - - /* - * TODO: might be a good idea and re-factor this to mimic bluez-device, - * ie. have this function just check the key, and call a sub-func to - * handle the action. - */ - - if (g_strcmp0(property, "Settings") != 0) - return; - - v_dict = g_variant_get_child_value(v, 0); - if (!v_dict) { - _LOGW("error getting IPv4 Settings: no v_dict"); - goto out; - } - - _LOGI("IPv4 static Settings:"); - - if (!g_variant_lookup(v_dict, "Interface", "&s", &interface)) { - _LOGW("Settings 'Interface' missing"); - goto out; - } - - _LOGD("Interface: %s", interface); - if (!nm_modem_set_data_port(NM_MODEM(self), - NM_PLATFORM_GET, - interface, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_UNKNOWN, - 0, - &error)) { - _LOGW("failed to connect to modem: %s", error->message); - g_clear_error(&error); - goto out; - } - - ifindex = nm_modem_get_ip_ifindex(NM_MODEM(self)); - nm_assert(ifindex > 0); - - /* TODO: verify handling of ip4_config; check other places it's used... */ - g_clear_object(&priv->ip4_config); - - priv->ip4_config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), ifindex); - - if (!g_variant_lookup(v_dict, "Address", "&s", &s)) { - _LOGW("Settings 'Address' missing"); - goto out; - } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { - _LOGW("can't convert 'Address' %s to addr", s ?: ""); - goto out; - } - memset(&addr, 0, sizeof(addr)); - addr.ifindex = ifindex; - addr.address = address_network; - addr.addr_source = NM_IP_CONFIG_SOURCE_WWAN; - - if (!g_variant_lookup(v_dict, "Netmask", "&s", &s)) { - _LOGW("Settings 'Netmask' missing"); - goto out; - } - if (!s || !nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { - _LOGW("invalid 'Netmask': %s", s ?: ""); - goto out; - } - addr.plen = nm_utils_ip4_netmask_to_prefix(address_network); - - _LOGI("Address: %s", nm_platform_ip4_address_to_string(&addr, NULL, 0)); - nm_ip4_config_add_address(priv->ip4_config, &addr); - - if (!g_variant_lookup(v_dict, "Gateway", "&s", &s) || !s) { - _LOGW("Settings 'Gateway' missing"); - goto out; - } - if (!nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &gateway_network)) { - _LOGW("invalid 'Gateway': %s", s); - goto out; - } - nm_modem_get_route_parameters(NM_MODEM(self), &ip4_route_table, &ip4_route_metric, NULL, NULL); - { - const NMPlatformIP4Route r = { - .rt_source = NM_IP_CONFIG_SOURCE_WWAN, - .gateway = gateway_network, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, - }; - - _LOGI("Gateway: %s", s); - nm_ip4_config_add_route(priv->ip4_config, &r, NULL); - } - - if (!g_variant_lookup(v_dict, "DomainNameServers", "^a&s", &array)) { - _LOGW("Settings 'DomainNameServers' missing"); - goto out; - } - if (array) { - for (iter = array; *iter; iter++) { - if (nm_utils_parse_inaddr_bin(AF_INET, *iter, NULL, &address_network) - && address_network) { - _LOGI("DNS: %s", *iter); - nm_ip4_config_add_nameserver(priv->ip4_config, address_network); - } else { - _LOGW("invalid NameServer: %s", *iter); - } - } - - if (iter == array) { - _LOGW("Settings: 'DomainNameServers': none specified"); - g_free(array); - goto out; - } - g_free(array); - } - - if (g_variant_lookup(v_dict, "MessageProxy", "&s", &s)) { - _LOGI("MessageProxy: %s", s); - if (s && nm_utils_parse_inaddr_bin(AF_INET, s, NULL, &address_network)) { - nm_modem_get_route_parameters(NM_MODEM(self), - &ip4_route_table, - &ip4_route_metric, - NULL, - NULL); - - { - const NMPlatformIP4Route mms_route = { - .network = address_network, - .plen = 32, - .gateway = gateway_network, - .table_coerced = nm_platform_route_table_coerce(ip4_route_table), - .metric = ip4_route_metric, - }; - - nm_ip4_config_add_route(priv->ip4_config, &mms_route, NULL); - } - } else { - _LOGW("invalid MessageProxy: %s", s); - } - } - - ret = TRUE; - -out: - if (nm_modem_get_state(NM_MODEM(self)) != NM_MODEM_STATE_CONNECTED) { - _LOGI("emitting PREPARE_RESULT: %s", ret ? "TRUE" : "FALSE"); - nm_modem_emit_prepare_result(NM_MODEM(self), - ret, - ret ? NM_DEVICE_STATE_REASON_NONE - : NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - } else { - _LOGW("MODEM_PPP_FAILED"); - nm_modem_emit_ppp_failed(NM_MODEM(self), NM_DEVICE_STATE_REASON_PPP_FAILED); - } -} - -static NMActStageReturn -static_stage3_ip4_config_start(NMModem * modem, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - GError * error = NULL; - - if (!priv->ip4_config) { - _LOGD("IP4 config not ready(?)"); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - _LOGD("IP4 config is done; setting modem_state -> CONNECTED"); - g_signal_emit_by_name(self, NM_MODEM_IP4_CONFIG_RESULT, priv->ip4_config, error); - - /* Signal listener takes ownership of the IP4Config */ - priv->ip4_config = NULL; - - nm_modem_set_state(NM_MODEM(self), - NM_MODEM_STATE_CONNECTED, - nm_modem_state_to_string(NM_MODEM_STATE_CONNECTED)); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -context_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy || g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (!proxy) { - _LOGE("failed to create ofono ConnectionContext DBus proxy: %s", error->message); - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), FALSE, NM_DEVICE_STATE_REASON_MODEM_BUSY); - return; - } - - priv->context_proxy = proxy; - - if (!priv->gprs_attached) { - g_clear_object(&priv->context_proxy_cancellable); - nm_modem_emit_prepare_result(NM_MODEM(self), - FALSE, - NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return; - } - - /* We have an old copy of the settings from a previous activation, - * clear it so that we can gate getting the IP config from oFono - * on whether or not we have already received them - */ - g_clear_object(&priv->ip4_config); - - _nm_dbus_signal_connect(priv->context_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(context_property_changed), - self); - - g_dbus_proxy_call(priv->context_proxy, - "SetProperty", - g_variant_new("(sv)", "Active", g_variant_new("b", TRUE)), - G_DBUS_CALL_FLAGS_NONE, - 20000, - priv->context_proxy_cancellable, - stage1_prepare_done, - self); -} - -static void -do_context_activate(NMModemOfono *self) -{ - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - g_return_if_fail(NM_IS_MODEM_OFONO(self)); - - nm_clear_g_cancellable(&priv->context_proxy_cancellable); - g_clear_object(&priv->context_proxy); - - priv->context_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - priv->context_path, - OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT, - priv->context_proxy_cancellable, - context_proxy_new_cb, - self); -} - -static GHashTable * -create_connect_properties(NMConnection *connection) -{ - NMSettingGsm *setting; - GHashTable * properties; - const char * str; - - setting = nm_connection_get_setting_gsm(connection); - properties = g_hash_table_new(nm_str_hash, g_str_equal); - - str = nm_setting_gsm_get_apn(setting); - if (str) - g_hash_table_insert(properties, "AccessPointName", g_strdup(str)); - - str = nm_setting_gsm_get_username(setting); - if (str) - g_hash_table_insert(properties, "Username", g_strdup(str)); - - str = nm_setting_gsm_get_password(setting); - if (str) - g_hash_table_insert(properties, "Password", g_strdup(str)); - - return properties; -} - -static NMActStageReturn -modem_act_stage1_prepare(NMModem * modem, - NMConnection * connection, - NMDeviceStateReason *out_failure_reason) -{ - NMModemOfono * self = NM_MODEM_OFONO(modem); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - const char * context_id; - char ** id = NULL; - - context_id = nm_connection_get_id(connection); - id = g_strsplit(context_id, "/", 0); - g_return_val_if_fail(id[2], NM_ACT_STAGE_RETURN_FAILURE); - - _LOGD("trying %s %s", id[1], id[2]); - - g_free(priv->context_path); - priv->context_path = g_strdup_printf("%s/%s", nm_modem_get_path(modem), id[2]); - g_strfreev(id); - - if (!priv->context_path) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_GSM_APN_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (priv->connect_properties) - g_hash_table_destroy(priv->connect_properties); - - priv->connect_properties = create_connect_properties(connection); - - _LOGI("activating context %s", priv->context_path); - - if (nm_modem_get_state(modem) == NM_MODEM_STATE_REGISTERED) { - do_context_activate(self); - } else { - _LOGW("could not activate context: modem is not registered."); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_MODEM_NO_CARRIER); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -modem_proxy_new_cb(GObject *source, GAsyncResult *result, gpointer user_data) -{ - NMModemOfono * self; - NMModemOfonoPrivate *priv; - gs_free_error GError *error = NULL; - GDBusProxy * proxy; - - proxy = g_dbus_proxy_new_for_bus_finish(result, &error); - if (!proxy && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - - self = NM_MODEM_OFONO(user_data); - priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - if (!proxy) { - _LOGE("failed to create ofono modem DBus proxy: %s", error->message); - g_clear_object(&priv->modem_proxy_cancellable); - return; - } - - priv->modem_proxy = proxy; - - _nm_dbus_signal_connect(priv->modem_proxy, - "PropertyChanged", - G_VARIANT_TYPE("(sv)"), - G_CALLBACK(modem_property_changed), - self); - - g_dbus_proxy_call(priv->modem_proxy, - "GetProperties", - NULL, - G_DBUS_CALL_FLAGS_NONE, - 20000, - priv->modem_proxy_cancellable, - modem_get_properties_done, - self); -} - -/*****************************************************************************/ - -static void -nm_modem_ofono_init(NMModemOfono *self) -{} - -static void -constructed(GObject *object) -{ - NMModemOfono * self = NM_MODEM_OFONO(object); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - priv->modem_proxy_cancellable = g_cancellable_new(); - - g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, - NULL, - OFONO_DBUS_SERVICE, - nm_modem_get_path(NM_MODEM(self)), - OFONO_DBUS_INTERFACE_MODEM, - priv->modem_proxy_cancellable, - modem_proxy_new_cb, - self); - - G_OBJECT_CLASS(nm_modem_ofono_parent_class)->constructed(object); -} - -NMModem * -nm_modem_ofono_new(const char *path) -{ - gs_free char *basename = NULL; - - g_return_val_if_fail(path != NULL, NULL); - - nm_log_info(LOGD_MB, "ofono: creating new Ofono modem path %s", path); - - /* Use short modem name (not its object path) as the NM device name (which - * comes from NM_MODEM_UID)and the device ID. - */ - basename = g_path_get_basename(path); - - return (NMModem *) g_object_new(NM_TYPE_MODEM_OFONO, - NM_MODEM_PATH, - path, - NM_MODEM_UID, - basename, - NM_MODEM_DEVICE_ID, - basename, - NM_MODEM_CONTROL_PORT, - "ofono", /* mandatory */ - NM_MODEM_DRIVER, - "ofono", - NM_MODEM_STATE, - (int) NM_MODEM_STATE_INITIALIZING, - NULL); -} - -static void -dispose(GObject *object) -{ - NMModemOfono * self = NM_MODEM_OFONO(object); - NMModemOfonoPrivate *priv = NM_MODEM_OFONO_GET_PRIVATE(self); - - nm_clear_g_cancellable(&priv->modem_proxy_cancellable); - nm_clear_g_cancellable(&priv->connman_proxy_cancellable); - nm_clear_g_cancellable(&priv->context_proxy_cancellable); - nm_clear_g_cancellable(&priv->sim_proxy_cancellable); - - if (priv->connect_properties) { - g_hash_table_destroy(priv->connect_properties); - priv->connect_properties = NULL; - } - - g_clear_object(&priv->ip4_config); - - if (priv->modem_proxy) { - g_signal_handlers_disconnect_by_data(priv->modem_proxy, self); - g_clear_object(&priv->modem_proxy); - } - - if (priv->connman_proxy) { - g_signal_handlers_disconnect_by_data(priv->connman_proxy, self); - g_clear_object(&priv->connman_proxy); - } - - if (priv->context_proxy) { - g_signal_handlers_disconnect_by_data(priv->context_proxy, self); - g_clear_object(&priv->context_proxy); - } - - if (priv->sim_proxy) { - g_signal_handlers_disconnect_by_data(priv->sim_proxy, self); - g_clear_object(&priv->sim_proxy); - } - - g_free(priv->imsi); - priv->imsi = NULL; - - G_OBJECT_CLASS(nm_modem_ofono_parent_class)->dispose(object); -} - -static void -nm_modem_ofono_class_init(NMModemOfonoClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS(klass); - NMModemClass *modem_class = NM_MODEM_CLASS(klass); - - object_class->constructed = constructed; - object_class->dispose = dispose; - - modem_class->get_capabilities = get_capabilities; - modem_class->disconnect = disconnect; - modem_class->deactivate_cleanup = deactivate_cleanup; - modem_class->check_connection_compatible_with_modem = check_connection_compatible_with_modem; - - modem_class->modem_act_stage1_prepare = modem_act_stage1_prepare; - modem_class->static_stage3_ip4_config_start = static_stage3_ip4_config_start; -} diff --git a/src/devices/wwan/nm-modem-ofono.h b/src/devices/wwan/nm-modem-ofono.h deleted file mode 100644 index 10b4a385..00000000 --- a/src/devices/wwan/nm-modem-ofono.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2013 - Canonical Ltd. - */ - -#ifndef NM_MODEM_OFONO_H -#define NM_MODEM_OFONO_H - -#include "nm-modem.h" - -#define NM_TYPE_MODEM_OFONO (nm_modem_ofono_get_type()) -#define NM_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM_OFONO, NMModemOfono)) -#define NM_IS_MODEM_OFONO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM_OFONO)) -#define NM_MODEM_OFONO_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM_OFONO, NMModemOfonoClass)) -#define NM_IS_MODEM_OFONO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM_OFONO)) -#define NM_MODEM_OFONO_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MODEM_OFONO, NMModemOfonoClass)) - -#define OFONO_DBUS_SERVICE "org.ofono" -#define OFONO_DBUS_PATH "/" -#define OFONO_DBUS_INTERFACE "org.ofono.Manager" -#define OFONO_DBUS_INTERFACE_MODEM "org.ofono.Modem" -#define OFONO_DBUS_INTERFACE_CONNECTION_MANAGER "org.ofono.ConnectionManager" -#define OFONO_DBUS_INTERFACE_CONNECTION_CONTEXT "org.ofono.ConnectionContext" -#define OFONO_DBUS_INTERFACE_SIM_MANAGER "org.ofono.SimManager" - -typedef struct _NMModemOfono NMModemOfono; -typedef struct _NMModemOfonoClass NMModemOfonoClass; - -GType nm_modem_ofono_get_type(void); - -NMModem *nm_modem_ofono_new(const char *path); - -#endif /* NM_MODEM_OFONO_H */ diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c deleted file mode 100644 index 9e16420e..00000000 --- a/src/devices/wwan/nm-modem.c +++ /dev/null @@ -1,2037 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2014 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#include "nm-default.h" - -#include "nm-modem.h" - -#include <fcntl.h> -#include <termios.h> -#include <linux/rtnetlink.h> - -#include "nm-core-internal.h" -#include "platform/nm-platform.h" -#include "nm-setting-connection.h" -#include "NetworkManagerUtils.h" -#include "devices/nm-device-private.h" -#include "nm-netns.h" -#include "nm-act-request.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" -#include "ppp/nm-ppp-manager-call.h" -#include "ppp/nm-ppp-status.h" - -/*****************************************************************************/ - -NM_GOBJECT_PROPERTIES_DEFINE(NMModem, - PROP_CONTROL_PORT, - PROP_IP_IFINDEX, - PROP_PATH, - PROP_UID, - PROP_DRIVER, - PROP_STATE, - PROP_DEVICE_ID, - PROP_SIM_ID, - PROP_IP_TYPES, - PROP_SIM_OPERATOR_ID, - PROP_OPERATOR_CODE, - PROP_APN, ); - -enum { - PPP_STATS, - PPP_FAILED, - PREPARE_RESULT, - IP4_CONFIG_RESULT, - IP6_CONFIG_RESULT, - AUTH_REQUESTED, - AUTH_RESULT, - REMOVED, - STATE_CHANGED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = {0}; - -typedef struct _NMModemPrivate { - char *uid; - char *path; - char *driver; - char *control_port; - char *data_port; - - /* TODO: ip_iface is solely used for nm_modem_owns_port(). - * We should rework the code that it's not necessary */ - char *ip_iface; - - int ip_ifindex; - NMModemIPMethod ip4_method; - NMModemIPMethod ip6_method; - NMUtilsIPv6IfaceId iid; - NMModemState state; - NMModemState prev_state; /* revert to this state if enable/disable fails */ - char * device_id; - char * sim_id; - NMModemIPType ip_types; - char * sim_operator_id; - char * operator_code; - char * apn; - - NMPPPManager *ppp_manager; - - NMActRequest * act_request; - guint32 secrets_tries; - NMActRequestGetSecretsCallId *secrets_id; - - guint mm_ip_timeout; - - guint32 ip4_route_table; - guint32 ip4_route_metric; - guint32 ip6_route_table; - guint32 ip6_route_metric; - - /* PPP stats */ - guint32 in_bytes; - guint32 out_bytes; - - bool claimed : 1; -} NMModemPrivate; - -G_DEFINE_TYPE(NMModem, nm_modem, G_TYPE_OBJECT) - -#define NM_MODEM_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMModem, NM_IS_MODEM) - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_BUFLEN 64 -#define _NMLOG_PREFIX_NAME "modem" -#define _NMLOG_DOMAIN LOGD_MB - -static const char * -_nmlog_prefix(char *prefix, NMModem *self) -{ - const char *uuid; - int c; - - if (!self) - return ""; - - uuid = nm_modem_get_uid(self); - - if (uuid) { - char pp[_NMLOG_PREFIX_BUFLEN - 5]; - - c = g_snprintf(prefix, _NMLOG_PREFIX_BUFLEN, "[%s]", nm_strquote(pp, sizeof(pp), uuid)); - } else - c = g_snprintf(prefix, _NMLOG_PREFIX_BUFLEN, "[%p]", self); - nm_assert(c < _NMLOG_PREFIX_BUFLEN); - - return prefix; -} - -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - char _prefix[_NMLOG_PREFIX_BUFLEN]; \ - \ - nm_log((level), \ - _NMLOG_DOMAIN, \ - NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - _nmlog_prefix(_prefix, (self)) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - G_STMT_END - -/*****************************************************************************/ - -static void _set_ip_ifindex(NMModem *self, int ifindex, const char *ifname); - -/*****************************************************************************/ -/* State/enabled/connected */ - -static const char *state_table[] = { - [NM_MODEM_STATE_UNKNOWN] = "unknown", - [NM_MODEM_STATE_FAILED] = "failed", - [NM_MODEM_STATE_INITIALIZING] = "initializing", - [NM_MODEM_STATE_LOCKED] = "locked", - [NM_MODEM_STATE_DISABLED] = "disabled", - [NM_MODEM_STATE_DISABLING] = "disabling", - [NM_MODEM_STATE_ENABLING] = "enabling", - [NM_MODEM_STATE_ENABLED] = "enabled", - [NM_MODEM_STATE_SEARCHING] = "searching", - [NM_MODEM_STATE_REGISTERED] = "registered", - [NM_MODEM_STATE_DISCONNECTING] = "disconnecting", - [NM_MODEM_STATE_CONNECTING] = "connecting", - [NM_MODEM_STATE_CONNECTED] = "connected", -}; - -const char * -nm_modem_state_to_string(NMModemState state) -{ - if ((gsize) state < G_N_ELEMENTS(state_table)) - return state_table[state]; - return NULL; -} - -/*****************************************************************************/ - -gboolean -nm_modem_is_claimed(NMModem *self) -{ - g_return_val_if_fail(NM_IS_MODEM(self), FALSE); - - return NM_MODEM_GET_PRIVATE(self)->claimed; -} - -NMModem * -nm_modem_claim(NMModem *self) -{ - NMModemPrivate *priv; - - g_return_val_if_fail(NM_IS_MODEM(self), NULL); - - priv = NM_MODEM_GET_PRIVATE(self); - - g_return_val_if_fail(!priv->claimed, NULL); - - priv->claimed = TRUE; - return g_object_ref(self); -} - -void -nm_modem_unclaim(NMModem *self) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - - g_return_if_fail(priv->claimed); - - /* we don't actually unclaim the instance. This instance should not be re-used - * by another owner, that is because we only claim modems as we receive them. - * There is no mechanism that somebody else would later re-use them again. - * - * // priv->claimed = FALSE; */ - - g_object_unref(self); -} - -/*****************************************************************************/ - -NMModemState -nm_modem_get_state(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->state; -} - -void -nm_modem_set_state(NMModem *self, NMModemState new_state, const char *reason) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - NMModemState old_state = priv->state; - - priv->prev_state = NM_MODEM_STATE_UNKNOWN; - - if (new_state != old_state) { - _LOGI("modem state changed, '%s' --> '%s' (reason: %s)", - nm_modem_state_to_string(old_state), - nm_modem_state_to_string(new_state), - reason ?: "none"); - - priv->state = new_state; - _notify(self, PROP_STATE); - g_signal_emit(self, signals[STATE_CHANGED], 0, (int) new_state, (int) old_state); - } -} - -void -nm_modem_set_prev_state(NMModem *self, const char *reason) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - /* Reset modem to previous state if the state hasn't already changed */ - if (priv->prev_state != NM_MODEM_STATE_UNKNOWN) - nm_modem_set_state(self, priv->prev_state, reason); -} - -void -nm_modem_set_mm_enabled(NMModem *self, gboolean enabled) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - NMModemState prev_state = priv->state; - - if (enabled && priv->state >= NM_MODEM_STATE_ENABLING) { - _LOGD("cannot enable modem: already enabled"); - return; - } - if (!enabled && priv->state <= NM_MODEM_STATE_DISABLING) { - _LOGD("cannot disable modem: already disabled"); - return; - } - - if (priv->state <= NM_MODEM_STATE_INITIALIZING) { - _LOGD("cannot enable/disable modem: initializing or failed"); - return; - } else if (priv->state == NM_MODEM_STATE_LOCKED) { - /* Don't try to enable if the modem is locked since that will fail */ - _LOGW("cannot enable/disable modem: locked"); - - /* Try to unlock the modem if it's being enabled */ - if (enabled) - g_signal_emit(self, signals[AUTH_REQUESTED], 0); - return; - } - - /* Not all modem classes support set_mm_enabled */ - if (NM_MODEM_GET_CLASS(self)->set_mm_enabled) - NM_MODEM_GET_CLASS(self)->set_mm_enabled(self, enabled); - - /* Pre-empt the state change signal */ - nm_modem_set_state(self, - enabled ? NM_MODEM_STATE_ENABLING : NM_MODEM_STATE_DISABLING, - "user preference"); - priv->prev_state = prev_state; -} - -void -nm_modem_emit_removed(NMModem *self) -{ - g_signal_emit(self, signals[REMOVED], 0); -} - -void -nm_modem_emit_prepare_result(NMModem *self, gboolean success, NMDeviceStateReason reason) -{ - nm_assert(NM_IS_MODEM(self)); - - g_signal_emit(self, signals[PREPARE_RESULT], 0, success, (guint) reason); -} - -void -nm_modem_emit_ppp_failed(NMModem *self, NMDeviceStateReason reason) -{ - nm_assert(NM_IS_MODEM(self)); - - g_signal_emit(self, signals[PPP_FAILED], 0, (guint) reason); -} - -NMModemIPType -nm_modem_get_supported_ip_types(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->ip_types; -} - -const char * -nm_modem_ip_type_to_string(NMModemIPType ip_type) -{ - switch (ip_type) { - case NM_MODEM_IP_TYPE_IPV4: - return "ipv4"; - case NM_MODEM_IP_TYPE_IPV6: - return "ipv6"; - case NM_MODEM_IP_TYPE_IPV4V6: - return "ipv4v6"; - default: - g_return_val_if_reached("unknown"); - } -} - -static GArray * -build_single_ip_type_array(NMModemIPType type) -{ - return g_array_append_val(g_array_sized_new(FALSE, FALSE, sizeof(NMModemIPType), 1), type); -} - -/** - * nm_modem_get_connection_ip_type: - * @self: the #NMModem - * @connection: the #NMConnection to determine IP type to use - * - * Given a modem and a connection, determine which #NMModemIPTypes to use - * when connecting. - * - * Returns: an array of #NMModemIpType values, in the order in which they - * should be tried. - */ -GArray * -nm_modem_get_connection_ip_type(NMModem *self, NMConnection *connection, GError **error) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - NMSettingIPConfig *s_ip4, *s_ip6; - const char * method; - gboolean ip4 = TRUE, ip6 = TRUE; - gboolean ip4_may_fail = TRUE, ip6_may_fail = TRUE; - - s_ip4 = nm_connection_get_setting_ip4_config(connection); - if (s_ip4) { - method = nm_setting_ip_config_get_method(s_ip4); - if (g_strcmp0(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) - ip4 = FALSE; - ip4_may_fail = nm_setting_ip_config_get_may_fail(s_ip4); - } - - s_ip6 = nm_connection_get_setting_ip6_config(connection); - if (s_ip6) { - method = nm_setting_ip_config_get_method(s_ip6); - if (NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) - ip6 = FALSE; - ip6_may_fail = nm_setting_ip_config_get_may_fail(s_ip6); - } - - if (ip4 && !ip6) { - if (!(priv->ip_types & NM_MODEM_IP_TYPE_IPV4)) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Connection requested IPv4 but IPv4 is " - "unsupported by the modem."); - return NULL; - } - return build_single_ip_type_array(NM_MODEM_IP_TYPE_IPV4); - } - - if (ip6 && !ip4) { - if (!(priv->ip_types & NM_MODEM_IP_TYPE_IPV6)) { - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Connection requested IPv6 but IPv6 is " - "unsupported by the modem."); - return NULL; - } - return build_single_ip_type_array(NM_MODEM_IP_TYPE_IPV6); - } - - if (ip4 && ip6) { - NMModemIPType type; - GArray * out; - - out = g_array_sized_new(FALSE, FALSE, sizeof(NMModemIPType), 3); - - /* Modem supports dual-stack? */ - if (priv->ip_types & NM_MODEM_IP_TYPE_IPV4V6) { - type = NM_MODEM_IP_TYPE_IPV4V6; - g_array_append_val(out, type); - } - - /* If IPv6 may-fail=false, we should NOT try IPv4 as fallback */ - if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV4) && ip6_may_fail) { - type = NM_MODEM_IP_TYPE_IPV4; - g_array_append_val(out, type); - } - - /* If IPv4 may-fail=false, we should NOT try IPv6 as fallback */ - if ((priv->ip_types & NM_MODEM_IP_TYPE_IPV6) && ip4_may_fail) { - type = NM_MODEM_IP_TYPE_IPV6; - g_array_append_val(out, type); - } - - if (out->len > 0) - return out; - - /* Error... */ - g_array_unref(out); - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Connection requested both IPv4 and IPv6 " - "but dual-stack addressing is unsupported " - "by the modem."); - return NULL; - } - - g_set_error_literal(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Connection specified no IP configuration!"); - return NULL; -} - -const char * -nm_modem_get_device_id(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->device_id; -} - -const char * -nm_modem_get_sim_id(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->sim_id; -} - -const char * -nm_modem_get_sim_operator_id(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->sim_operator_id; -} - -const char * -nm_modem_get_operator_code(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->operator_code; -} - -const char * -nm_modem_get_apn(NMModem *self) -{ - return NM_MODEM_GET_PRIVATE(self)->apn; -} - -/*****************************************************************************/ -/* IP method PPP */ - -static void -ppp_state_changed(NMPPPManager *ppp_manager, NMPPPStatus status, gpointer user_data) -{ - switch (status) { - case NM_PPP_STATUS_DISCONNECT: - nm_modem_emit_ppp_failed(user_data, NM_DEVICE_STATE_REASON_PPP_DISCONNECT); - break; - case NM_PPP_STATUS_DEAD: - nm_modem_emit_ppp_failed(user_data, NM_DEVICE_STATE_REASON_PPP_FAILED); - break; - default: - break; - } -} - -static void -ppp_ifindex_set(NMPPPManager *ppp_manager, int ifindex, const char *iface, gpointer user_data) -{ - NMModem *self = NM_MODEM(user_data); - - nm_assert(ifindex >= 0); - nm_assert(NM_MODEM_GET_PRIVATE(self)->ppp_manager == ppp_manager); - - if (ifindex <= 0 && iface) { - /* this might happen, if the ifname was already deleted - * and we failed to resolve ifindex. - * - * Forget about the name. */ - iface = NULL; - } - _set_ip_ifindex(self, ifindex, iface); -} - -static void -ppp_ip4_config(NMPPPManager *ppp_manager, NMIP4Config *config, gpointer user_data) -{ - NMModem *self = NM_MODEM(user_data); - 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; - - /* 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) { - _LOGW("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_ip6_config(NMPPPManager * ppp_manager, - const NMUtilsIPv6IfaceId *iid, - NMIP6Config * config, - gpointer user_data) -{ - NMModem *self = NM_MODEM(user_data); - - NM_MODEM_GET_PRIVATE(self)->iid = *iid; - - nm_modem_emit_ip6_config_result(self, config, NULL); -} - -static void -ppp_stats(NMPPPManager *ppp_manager, guint i_in_bytes, guint i_out_bytes, gpointer user_data) -{ - NMModem * self = NM_MODEM(user_data); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - guint32 in_bytes = i_in_bytes; - guint32 out_bytes = i_out_bytes; - - 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, (guint) in_bytes, (guint) out_bytes); - } -} - -static gboolean -port_speed_is_zero(const char *port) -{ - struct termios options; - nm_auto_close int fd = -1; - gs_free char * path = NULL; - - nm_assert(port); - - if (port[0] != '/') { - if (!port[0] || strchr(port, '/') || NM_IN_STRSET(port, ".", "..")) - return FALSE; - path = g_build_path("/sys/class/tty", port, NULL); - port = path; - } - - fd = open(port, O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC); - if (fd < 0) - return FALSE; - - memset(&options, 0, sizeof(struct termios)); - if (tcgetattr(fd, &options) != 0) - return FALSE; - - return cfgetospeed(&options) == B0; -} - -static NMActStageReturn -ppp_stage3_ip_config_start(NMModem * self, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - const char * ppp_name = NULL; - GError * error = NULL; - guint ip_timeout = 30; - guint baud_override = 0; - - 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); - - /* If we're already running PPP don't restart it; for example, if both - * IPv4 and IPv6 are requested, IPv4 gets started first, but we use the - * same pppd for both v4 and v6. - */ - if (priv->ppp_manager) - return NM_ACT_STAGE_RETURN_POSTPONE; - - if (NM_MODEM_GET_CLASS(self)->get_user_pass) { - NMConnection *connection = nm_act_request_get_applied_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; - } - - if (!priv->data_port) { - _LOGE("error starting PPP (no data port)"); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - /* Check if ModemManager requested a specific IP timeout to be used. If 0 reported, - * use the default one (30s) */ - if (priv->mm_ip_timeout > 0) { - _LOGI("using modem-specified IP timeout: %u seconds", priv->mm_ip_timeout); - ip_timeout = priv->mm_ip_timeout; - } - - /* Some tty drivers and modems ignore port speed, but pppd requires the - * port speed to be > 0 or it exits. If the port speed is 0 pass an - * explicit speed to pppd to prevent the exit. - * https://bugzilla.redhat.com/show_bug.cgi?id=1281731 - */ - if (port_speed_is_zero(priv->data_port)) - baud_override = 57600; - - priv->ppp_manager = nm_ppp_manager_create(priv->data_port, &error); - - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } - - if (!priv->ppp_manager - || !nm_ppp_manager_start(priv->ppp_manager, - req, - ppp_name, - ip_timeout, - baud_override, - &error)) { - _LOGE("error starting PPP: %s", error->message); - g_error_free(error); - g_clear_object(&priv->ppp_manager); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_PPP_START_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, - G_CALLBACK(ppp_state_changed), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, - G_CALLBACK(ppp_ifindex_set), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_CALLBACK(ppp_ip4_config), - self); - g_signal_connect(priv->ppp_manager, - NM_PPP_MANAGER_SIGNAL_IP6_CONFIG, - G_CALLBACK(ppp_ip6_config), - self); - g_signal_connect(priv->ppp_manager, NM_PPP_MANAGER_SIGNAL_STATS, G_CALLBACK(ppp_stats), self); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -NMActStageReturn -nm_modem_stage3_ip4_config_start(NMModem * self, - NMDevice * device, - NMDeviceClass * device_class, - NMDeviceStateReason *out_failure_reason) -{ - NMModemPrivate * priv; - NMActRequest * req; - NMConnection * connection; - const char * method; - NMActStageReturn ret; - - _LOGD("ip4_config_start"); - - 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); - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - connection = nm_act_request_get_applied_connection(req); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - nm_modem_set_route_parameters_from_device(self, device); - - method = nm_utils_get_ip_config_method(connection, AF_INET); - - /* Only Disabled and Auto methods make sense for WWAN */ - if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) - return NM_ACT_STAGE_RETURN_SUCCESS; - - if (!nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - _LOGE("unhandled WWAN IPv4 method '%s'; will fail", method); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_METHOD_UNSUPPORTED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - priv = NM_MODEM_GET_PRIVATE(self); - switch (priv->ip4_method) { - case NM_MODEM_IP_METHOD_PPP: - ret = ppp_stage3_ip_config_start(self, req, out_failure_reason); - break; - case NM_MODEM_IP_METHOD_STATIC: - _LOGD("MODEM_IP_METHOD_STATIC"); - ret = - NM_MODEM_GET_CLASS(self)->static_stage3_ip4_config_start(self, req, out_failure_reason); - break; - case NM_MODEM_IP_METHOD_AUTO: - _LOGD("MODEM_IP_METHOD_AUTO"); - ret = device_class->act_stage3_ip_config_start(device, AF_INET, NULL, out_failure_reason); - break; - default: - _LOGI("IPv4 configuration disabled"); - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - 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->ip4_method == NM_MODEM_IP_METHOD_STATIC - || priv->ip4_method == NM_MODEM_IP_METHOD_AUTO) { - const NMPlatformIP4Address *address = nm_ip4_config_get_first_address(config); - - g_assert(address); - if (address->plen == 32) - nm_platform_link_set_noarp(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device)); - } -} - -/*****************************************************************************/ - -void -nm_modem_emit_ip6_config_result(NMModem *self, NMIP6Config *config, GError *error) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - NMDedupMultiIter ipconf_iter; - const NMPlatformIP6Address *addr; - gboolean do_slaac = TRUE; - - if (error) { - g_signal_emit(self, signals[IP6_CONFIG_RESULT], 0, NULL, FALSE, error); - return; - } - - if (config) { - /* If the IPv6 configuration only included a Link-Local address, then - * we have to run SLAAC to get the full IPv6 configuration. - */ - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, config, &addr) { - if (IN6_IS_ADDR_LINKLOCAL(&addr->address)) { - if (!priv->iid.id) - priv->iid.id = ((guint64 *) (&addr->address.s6_addr))[1]; - } else - do_slaac = FALSE; - } - } - g_assert(config || do_slaac); - - g_signal_emit(self, signals[IP6_CONFIG_RESULT], 0, config, do_slaac, NULL); -} - -static NMActStageReturn -stage3_ip6_config_request(NMModem *self, NMDeviceStateReason *out_failure_reason) -{ - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return NM_ACT_STAGE_RETURN_FAILURE; -} - -NMActStageReturn -nm_modem_stage3_ip6_config_start(NMModem * self, - NMDevice * device, - NMDeviceStateReason *out_failure_reason) -{ - NMModemPrivate * priv; - NMActRequest * req; - NMActStageReturn ret; - NMConnection * connection; - const char * method; - - g_return_val_if_fail(NM_IS_MODEM(self), NM_ACT_STAGE_RETURN_FAILURE); - - req = nm_device_get_act_request(device); - g_return_val_if_fail(req, NM_ACT_STAGE_RETURN_FAILURE); - - connection = nm_act_request_get_applied_connection(req); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - nm_modem_set_route_parameters_from_device(self, device); - - method = nm_utils_get_ip_config_method(connection, AF_INET6); - - /* Only Ignore, Disabled and Auto methods make sense for WWAN */ - if (NM_IN_STRSET(method, - NM_SETTING_IP6_CONFIG_METHOD_IGNORE, - NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) - return NM_ACT_STAGE_RETURN_IP_DONE; - - if (!nm_streq(method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)) { - _LOGW("unhandled WWAN IPv6 method '%s'; will fail", method); - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - priv = NM_MODEM_GET_PRIVATE(self); - switch (priv->ip6_method) { - case NM_MODEM_IP_METHOD_PPP: - ret = ppp_stage3_ip_config_start(self, req, out_failure_reason); - break; - case NM_MODEM_IP_METHOD_STATIC: - case NM_MODEM_IP_METHOD_AUTO: - /* Both static and DHCP/Auto retrieve a base IP config from the modem - * which in the static case is the full config, and the DHCP/Auto case - * is just the IPv6LL address to use for SLAAC. - */ - ret = NM_MODEM_GET_CLASS(self)->stage3_ip6_config_request(self, out_failure_reason); - break; - default: - _LOGI("IPv6 configuration disabled"); - ret = NM_ACT_STAGE_RETURN_IP_FAIL; - break; - } - - return ret; -} - -guint32 -nm_modem_get_configured_mtu(NMDevice *self, NMDeviceMtuSource *out_source, gboolean *out_force) -{ - NMConnection *connection; - NMSetting * setting; - gint64 mtu_default; - guint mtu = 0; - const char * property_name; - - nm_assert(NM_IS_DEVICE(self)); - nm_assert(out_source); - - connection = nm_device_get_applied_connection(self); - if (!connection) - g_return_val_if_reached(0); - - setting = (NMSetting *) nm_connection_get_setting_gsm(connection); - if (!setting) - setting = (NMSetting *) nm_connection_get_setting_cdma(connection); - - if (setting) { - g_object_get(setting, "mtu", &mtu, NULL); - if (mtu) { - *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; - return mtu; - } - - property_name = NM_IS_SETTING_GSM(setting) ? "gsm.mtu" : "cdma.mtu"; - mtu_default = - nm_device_get_configured_mtu_from_connection_default(self, property_name, G_MAXUINT32); - if (mtu_default >= 0) { - *out_source = NM_DEVICE_MTU_SOURCE_CONNECTION; - return (guint32) mtu_default; - } - } - - *out_source = NM_DEVICE_MTU_SOURCE_NONE; - return 0; -} - -/*****************************************************************************/ - -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); -} - -static void -modem_secrets_cb(NMActRequest * req, - NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * 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 = NULL; - - if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED) - || g_error_matches(error, NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_NO_SECRETS)) - return; - - if (error) - _LOGW("modem-secrets: %s", error->message); - - g_signal_emit(self, signals[AUTH_RESULT], 0, error); -} - -void -nm_modem_get_secrets(NMModem * self, - const char *setting_name, - gboolean request_new, - const char *hint) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - - cancel_get_secrets(self); - - if (request_new) - flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - priv->secrets_id = nm_act_request_get_secrets(priv->act_request, - FALSE, - setting_name, - flags, - NM_MAKE_STRV(hint), - modem_secrets_cb, - self); - g_return_if_fail(priv->secrets_id); - g_signal_emit(self, signals[AUTH_REQUESTED], 0); -} - -/*****************************************************************************/ - -static NMActStageReturn -modem_act_stage1_prepare(NMModem * modem, - NMConnection * connection, - NMDeviceStateReason *out_failure_reason) -{ - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_UNKNOWN); - return NM_ACT_STAGE_RETURN_FAILURE; -} - -NMActStageReturn -nm_modem_act_stage1_prepare(NMModem * self, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - gs_unref_ptrarray GPtrArray *hints = NULL; - const char * setting_name = NULL; - NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - NMConnection * connection; - - g_return_val_if_fail(NM_IS_ACT_REQUEST(req), NM_ACT_STAGE_RETURN_FAILURE); - - if (priv->act_request) - g_object_unref(priv->act_request); - priv->act_request = g_object_ref(req); - - connection = nm_act_request_get_applied_connection(req); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - setting_name = nm_connection_need_secrets(connection, &hints); - if (!setting_name) { - nm_assert(!hints); - return NM_MODEM_GET_CLASS(self)->modem_act_stage1_prepare(self, - connection, - out_failure_reason); - } - - /* Secrets required... */ - if (priv->secrets_tries++) - flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - - if (hints) - g_ptr_array_add(hints, NULL); - - priv->secrets_id = nm_act_request_get_secrets(req, - FALSE, - setting_name, - flags, - hints ? (const char *const *) hints->pdata : NULL, - modem_secrets_cb, - self); - g_return_val_if_fail(priv->secrets_id, NM_ACT_STAGE_RETURN_FAILURE); - g_signal_emit(self, signals[AUTH_REQUESTED], 0); - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -/*****************************************************************************/ - -void -nm_modem_act_stage2_config(NMModem *self) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - /* Clear secrets tries counter since secrets were successfully used - * already if we get here. - */ - priv->secrets_tries = 0; -} - -/*****************************************************************************/ - -gboolean -nm_modem_check_connection_compatible(NMModem *self, NMConnection *connection, GError **error) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - if (nm_streq0(nm_connection_get_connection_type(connection), NM_SETTING_GSM_SETTING_NAME)) { - NMSettingGsm *s_gsm; - const char * str; - - s_gsm = _nm_connection_check_main_setting(connection, NM_SETTING_GSM_SETTING_NAME, error); - if (!s_gsm) - return FALSE; - - str = nm_setting_gsm_get_device_id(s_gsm); - if (str) { - if (!priv->device_id) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "GSM profile has device-id, device does not"); - return FALSE; - } - if (!nm_streq(str, priv->device_id)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has differing device-id than GSM profile"); - return FALSE; - } - } - - /* SIM properties may not be available before the SIM is unlocked, so - * to ensure that autoconnect works, the connection's SIM properties - * are only compared if present on the device. - */ - - if (priv->sim_id && (str = nm_setting_gsm_get_sim_id(s_gsm))) { - if (!nm_streq(str, priv->sim_id)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has differing sim-id than GSM profile"); - return FALSE; - } - } - - if (priv->sim_operator_id && (str = nm_setting_gsm_get_sim_operator_id(s_gsm))) { - if (!nm_streq(str, priv->sim_operator_id)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "device has differing sim-operator-id than GSM profile"); - return FALSE; - } - } - } - - return NM_MODEM_GET_CLASS(self)->check_connection_compatible_with_modem(self, - connection, - error); -} - -/*****************************************************************************/ - -gboolean -nm_modem_complete_connection(NMModem * self, - const char * iface, - NMConnection * connection, - NMConnection *const *existing_connections, - GError ** error) -{ - NMModemClass *klass; - - klass = NM_MODEM_GET_CLASS(self); - if (!klass->complete_connection) { - g_set_error(error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "Modem class %s had no complete_connection method", - G_OBJECT_TYPE_NAME(self)); - return FALSE; - } - - return klass->complete_connection(self, iface, connection, existing_connections, error); -} - -/*****************************************************************************/ - -static void -deactivate_cleanup(NMModem *self, NMDevice *device, gboolean stop_ppp_manager) -{ - NMModemPrivate *priv; - int ifindex; - - g_return_if_fail(NM_IS_MODEM(self)); - - 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_signal_handlers_disconnect_by_data(priv->ppp_manager, self); - if (stop_ppp_manager) - nm_ppp_manager_stop(priv->ppp_manager, NULL, NULL, NULL); - g_clear_object(&priv->ppp_manager); - } - - if (device) { - g_return_if_fail(NM_IS_DEVICE(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) { - NMPlatform *platform = nm_device_get_platform(device); - - nm_platform_ip_route_flush(platform, AF_UNSPEC, ifindex); - nm_platform_ip_address_flush(platform, AF_UNSPEC, ifindex); - nm_platform_link_set_down(platform, ifindex); - } - } - } - - nm_clear_g_free(&priv->data_port); - priv->mm_ip_timeout = 0; - priv->ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; - priv->ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - _set_ip_ifindex(self, -1, NULL); -} - -/*****************************************************************************/ - -typedef struct { - NMModem * self; - NMDevice * device; - GCancellable * cancellable; - NMModemDeactivateCallback callback; - gpointer callback_user_data; -} DeactivateContext; - -static void -deactivate_context_complete(DeactivateContext *ctx, GError *error) -{ - NMModem *self = ctx->self; - - _LOGD("modem deactivation finished %s%s%s", - NM_PRINT_FMT_QUOTED(error, "with failure: ", error->message, "", "successfully")); - - if (ctx->callback) - ctx->callback(ctx->self, error, ctx->callback_user_data); - nm_g_object_unref(ctx->cancellable); - g_object_unref(ctx->device); - g_object_unref(ctx->self); - g_slice_free(DeactivateContext, ctx); -} - -static void -_deactivate_call_disconnect_cb(NMModem *self, GError *error, gpointer user_data) -{ - deactivate_context_complete(user_data, error); -} - -static void -_deactivate_call_disconnect(DeactivateContext *ctx) -{ - NM_MODEM_GET_CLASS(ctx->self)->disconnect(ctx->self, - FALSE, - ctx->cancellable, - _deactivate_call_disconnect_cb, - ctx); -} - -static void -_deactivate_ppp_manager_stop_cb(NMPPPManager * ppp_manager, - NMPPPManagerStopHandle *handle, - gboolean was_cancelled, - gpointer user_data) -{ - DeactivateContext *ctx = user_data; - - g_object_unref(ppp_manager); - - if (was_cancelled) { - gs_free_error GError *error = NULL; - - if (!g_cancellable_set_error_if_cancelled(ctx->cancellable, &error)) - nm_assert_not_reached(); - deactivate_context_complete(ctx, error); - return; - } - - nm_assert(!g_cancellable_is_cancelled(ctx->cancellable)); - _deactivate_call_disconnect(ctx); -} - -void -nm_modem_deactivate_async(NMModem * self, - NMDevice * device, - GCancellable * cancellable, - NMModemDeactivateCallback callback, - gpointer user_data) -{ - NMModemPrivate * priv = NM_MODEM_GET_PRIVATE(self); - DeactivateContext *ctx; - NMPPPManager * ppp_manager; - - g_return_if_fail(NM_IS_MODEM(self)); - g_return_if_fail(NM_IS_DEVICE(device)); - g_return_if_fail(G_IS_CANCELLABLE(cancellable)); - - ctx = g_slice_new(DeactivateContext); - ctx->self = g_object_ref(self); - ctx->device = g_object_ref(device); - ctx->cancellable = g_object_ref(cancellable); - ctx->callback = callback; - ctx->callback_user_data = user_data; - - ppp_manager = nm_g_object_ref(priv->ppp_manager); - - NM_MODEM_GET_CLASS(self)->deactivate_cleanup(self, ctx->device, FALSE); - - if (ppp_manager) { - /* If we have a PPP manager, stop it. - * - * Pass on the reference in @ppp_manager. */ - nm_ppp_manager_stop(ppp_manager, ctx->cancellable, _deactivate_ppp_manager_stop_cb, ctx); - return; - } - - _deactivate_call_disconnect(ctx); -} - -/*****************************************************************************/ - -void -nm_modem_deactivate(NMModem *self, NMDevice *device) -{ - /* First cleanup */ - NM_MODEM_GET_CLASS(self)->deactivate_cleanup(self, device, TRUE); - /* Then disconnect without waiting */ - NM_MODEM_GET_CLASS(self)->disconnect(self, FALSE, NULL, NULL, NULL); -} - -/*****************************************************************************/ - -void -nm_modem_device_state_changed(NMModem *self, NMDeviceState new_state, NMDeviceState old_state) -{ - 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_FAILED: - case NM_DEVICE_STATE_DISCONNECTED: - 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 || new_state == NM_DEVICE_STATE_DISCONNECTED) - warn = FALSE; - /* First cleanup */ - NM_MODEM_GET_CLASS(self)->deactivate_cleanup(self, NULL, TRUE); - NM_MODEM_GET_CLASS(self)->disconnect(self, warn, NULL, NULL, NULL); - } - 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; -} - -int -nm_modem_get_ip_ifindex(NMModem *self) -{ - NMModemPrivate *priv; - - g_return_val_if_fail(NM_IS_MODEM(self), 0); - - priv = NM_MODEM_GET_PRIVATE(self); - - /* internally we track an unset ip_ifindex as -1. - * For the caller of nm_modem_get_ip_ifindex(), this - * shall be zero too. */ - return priv->ip_ifindex != -1 ? priv->ip_ifindex : 0; -} - -static void -_set_ip_ifindex(NMModem *self, int ifindex, const char *ifname) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - nm_assert(ifindex >= -1); - nm_assert((ifindex > 0) == !!ifname); - - if (!nm_streq0(priv->ip_iface, ifname)) { - g_free(priv->ip_iface); - priv->ip_iface = g_strdup(ifname); - } - - if (priv->ip_ifindex != ifindex) { - priv->ip_ifindex = ifindex; - _notify(self, PROP_IP_IFINDEX); - } -} - -gboolean -nm_modem_set_data_port(NMModem * self, - NMPlatform * platform, - const char * data_port, - NMModemIPMethod ip4_method, - NMModemIPMethod ip6_method, - guint timeout, - GError ** error) -{ - NMModemPrivate *priv; - gboolean is_ppp; - int ifindex = -1; - - g_return_val_if_fail(NM_IS_MODEM(self), FALSE); - g_return_val_if_fail(NM_IS_PLATFORM(platform), FALSE); - g_return_val_if_fail(!error || !*error, FALSE); - - priv = NM_MODEM_GET_PRIVATE(self); - - if (priv->ppp_manager || priv->data_port || priv->ip_ifindex != -1) { - g_set_error_literal(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "cannot set data port in activated state"); - /* this really shouldn't happen. Assert. */ - g_return_val_if_reached(FALSE); - } - - if (!data_port) { - g_set_error_literal(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "missing data port"); - return FALSE; - } - - is_ppp = (ip4_method == NM_MODEM_IP_METHOD_PPP) || (ip6_method == NM_MODEM_IP_METHOD_PPP); - if (is_ppp) { - if (!NM_IN_SET(ip4_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_PPP) - || !NM_IN_SET(ip6_method, NM_MODEM_IP_METHOD_UNKNOWN, NM_MODEM_IP_METHOD_PPP)) { - g_set_error_literal(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "conflicting ip methods"); - return FALSE; - } - } else if (!NM_IN_SET(ip4_method, - NM_MODEM_IP_METHOD_UNKNOWN, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_AUTO) - || !NM_IN_SET(ip6_method, - NM_MODEM_IP_METHOD_UNKNOWN, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_AUTO) - || (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN - && ip6_method == NM_MODEM_IP_METHOD_UNKNOWN)) { - g_set_error_literal(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "invalid ip methods"); - return FALSE; - } - - if (!is_ppp) { - ifindex = nm_platform_if_nametoindex(platform, data_port); - if (ifindex <= 0) { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "cannot find network interface %s", - data_port); - return FALSE; - } - if (!nm_platform_process_events_ensure_link(platform, ifindex, data_port)) { - g_set_error(error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "cannot find network interface %s in platform cache", - data_port); - return FALSE; - } - } - - priv->mm_ip_timeout = timeout; - priv->ip4_method = ip4_method; - priv->ip6_method = ip6_method; - if (is_ppp) { - priv->data_port = g_strdup(data_port); - _set_ip_ifindex(self, -1, NULL); - } else { - priv->data_port = NULL; - _set_ip_ifindex(self, ifindex, data_port); - } - return TRUE; -} - -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); - - return NM_IN_STRSET(iface, priv->ip_iface, priv->data_port, priv->control_port); -} - -gboolean -nm_modem_get_iid(NMModem *self, NMUtilsIPv6IfaceId *out_iid) -{ - g_return_val_if_fail(NM_IS_MODEM(self), FALSE); - - *out_iid = NM_MODEM_GET_PRIVATE(self)->iid; - return TRUE; -} - -/*****************************************************************************/ - -void -nm_modem_get_route_parameters(NMModem *self, - guint32 *out_ip4_route_table, - guint32 *out_ip4_route_metric, - guint32 *out_ip6_route_table, - guint32 *out_ip6_route_metric) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - NM_SET_OUT(out_ip4_route_table, priv->ip4_route_table); - NM_SET_OUT(out_ip4_route_metric, priv->ip4_route_metric); - NM_SET_OUT(out_ip6_route_table, priv->ip6_route_table); - NM_SET_OUT(out_ip6_route_metric, priv->ip6_route_metric); -} - -void -nm_modem_set_route_parameters(NMModem *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric) -{ - NMModemPrivate *priv; - - g_return_if_fail(NM_IS_MODEM(self)); - - priv = NM_MODEM_GET_PRIVATE(self); - if (priv->ip4_route_table != ip4_route_table || priv->ip4_route_metric != ip4_route_metric - || priv->ip6_route_table != ip6_route_table || priv->ip6_route_metric != ip6_route_metric) { - priv->ip4_route_table = ip4_route_table; - priv->ip4_route_metric = ip4_route_metric; - priv->ip6_route_table = ip6_route_table; - priv->ip6_route_metric = ip6_route_metric; - - _LOGT("route-parameters: table-v4: %u, metric-v4: %u, table-v6: %u, metric-v6: %u", - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } - - if (priv->ppp_manager) { - nm_ppp_manager_set_route_parameters(priv->ppp_manager, - priv->ip4_route_table, - priv->ip4_route_metric, - priv->ip6_route_table, - priv->ip6_route_metric); - } -} - -void -nm_modem_set_route_parameters_from_device(NMModem *self, NMDevice *device) -{ - g_return_if_fail(NM_IS_DEVICE(device)); - - nm_modem_set_route_parameters(self, - nm_device_get_route_table(device, AF_INET), - nm_device_get_route_metric(device, AF_INET), - nm_device_get_route_table(device, AF_INET6), - nm_device_get_route_metric(device, AF_INET6)); -} - -/*****************************************************************************/ - -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); -} - -/*****************************************************************************/ - -void -_nm_modem_set_operator_code(NMModem *self, const char *operator_code) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - if (g_strcmp0(priv->operator_code, operator_code) != 0) { - g_free(priv->operator_code); - priv->operator_code = g_strdup(operator_code); - _notify(self, PROP_OPERATOR_CODE); - } -} - -void -_nm_modem_set_apn(NMModem *self, const char *apn) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - if (g_strcmp0(priv->apn, apn) != 0) { - g_free(priv->apn); - priv->apn = g_strdup(apn); - _notify(self, PROP_APN); - } -} - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMModem * self = NM_MODEM(object); - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(self); - - 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_IP_IFINDEX: - g_value_set_int(value, nm_modem_get_ip_ifindex(self)); - break; - case PROP_UID: - g_value_set_string(value, priv->uid); - break; - case PROP_STATE: - g_value_set_int(value, priv->state); - break; - case PROP_DEVICE_ID: - g_value_set_string(value, priv->device_id); - break; - case PROP_SIM_ID: - g_value_set_string(value, priv->sim_id); - break; - case PROP_IP_TYPES: - g_value_set_uint(value, priv->ip_types); - break; - case PROP_SIM_OPERATOR_ID: - g_value_set_string(value, priv->sim_operator_id); - break; - case PROP_OPERATOR_CODE: - g_value_set_string(value, priv->operator_code); - break; - case PROP_APN: - g_value_set_string(value, priv->apn); - 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); - const char * s; - - switch (prop_id) { - case PROP_PATH: - /* construct-only */ - priv->path = g_value_dup_string(value); - g_return_if_fail(priv->path); - break; - case PROP_DRIVER: - /* construct-only */ - priv->driver = g_value_dup_string(value); - break; - case PROP_CONTROL_PORT: - /* construct-only */ - priv->control_port = g_value_dup_string(value); - break; - case PROP_UID: - /* construct-only */ - priv->uid = g_value_dup_string(value); - break; - case PROP_STATE: - /* construct-only */ - priv->state = g_value_get_int(value); - break; - case PROP_DEVICE_ID: - /* construct-only */ - priv->device_id = g_value_dup_string(value); - break; - case PROP_SIM_ID: - g_free(priv->sim_id); - priv->sim_id = g_value_dup_string(value); - break; - case PROP_IP_TYPES: - priv->ip_types = g_value_get_uint(value); - break; - case PROP_SIM_OPERATOR_ID: - nm_clear_g_free(&priv->sim_operator_id); - s = g_value_get_string(value); - if (s && s[0]) - priv->sim_operator_id = g_strdup(s); - break; - case PROP_OPERATOR_CODE: - /* construct-only */ - priv->operator_code = g_value_dup_string(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_modem_init(NMModem *self) -{ - NMModemPrivate *priv; - - self->_priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_MODEM, NMModemPrivate); - priv = self->_priv; - - priv->ip_ifindex = -1; - priv->ip4_route_table = RT_TABLE_MAIN; - priv->ip4_route_metric = 700; - priv->ip6_route_table = RT_TABLE_MAIN; - priv->ip6_route_metric = 700; -} - -static void -constructed(GObject *object) -{ - NMModemPrivate *priv; - - G_OBJECT_CLASS(nm_modem_parent_class)->constructed(object); - - priv = NM_MODEM_GET_PRIVATE(NM_MODEM(object)); - - g_return_if_fail(priv->control_port); -} - -/*****************************************************************************/ - -static void -dispose(GObject *object) -{ - NMModemPrivate *priv = NM_MODEM_GET_PRIVATE(object); - - g_clear_object(&priv->act_request); - - 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_free(priv->ip_iface); - g_free(priv->device_id); - g_free(priv->sim_id); - g_free(priv->sim_operator_id); - g_free(priv->operator_code); - g_free(priv->apn); - - 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)); - - object_class->constructed = constructed; - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - klass->modem_act_stage1_prepare = modem_act_stage1_prepare; - klass->stage3_ip6_config_request = stage3_ip6_config_request; - klass->deactivate_cleanup = deactivate_cleanup; - - obj_properties[PROP_UID] = - g_param_spec_string(NM_MODEM_UID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_PATH] = - g_param_spec_string(NM_MODEM_PATH, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_DRIVER] = - g_param_spec_string(NM_MODEM_DRIVER, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_CONTROL_PORT] = - g_param_spec_string(NM_MODEM_CONTROL_PORT, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IP_IFINDEX] = g_param_spec_int(NM_MODEM_IP_IFINDEX, - "", - "", - 0, - G_MAXINT, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_STATE] = - g_param_spec_int(NM_MODEM_STATE, - "", - "", - NM_MODEM_STATE_UNKNOWN, - _NM_MODEM_STATE_LAST, - NM_MODEM_STATE_UNKNOWN, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_DEVICE_ID] = - g_param_spec_string(NM_MODEM_DEVICE_ID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SIM_ID] = - g_param_spec_string(NM_MODEM_SIM_ID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IP_TYPES] = - g_param_spec_uint(NM_MODEM_IP_TYPES, - "IP Types", - "Supported IP types", - 0, - G_MAXUINT32, - NM_MODEM_IP_TYPE_IPV4, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_SIM_OPERATOR_ID] = - g_param_spec_string(NM_MODEM_SIM_OPERATOR_ID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_OPERATOR_CODE] = - g_param_spec_string(NM_MODEM_OPERATOR_CODE, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_APN] = - g_param_spec_string(NM_MODEM_APN, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[PPP_STATS] = g_signal_new(NM_MODEM_PPP_STATS, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_UINT /*guint32 in_bytes*/, - G_TYPE_UINT /*guint32 out_bytes*/); - - signals[PPP_FAILED] = g_signal_new(NM_MODEM_PPP_FAILED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - 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, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_POINTER); - - /** - * NMModem::ip6-config-result: - * @modem: the #NMModem on which the signal is emitted - * @config: the #NMIP6Config to apply to the modem's data port - * @do_slaac: %TRUE if IPv6 SLAAC should be started - * @error: a #GError if any error occurred during IP configuration - * - * This signal is emitted when IPv6 configuration has completed or failed. - * If @error is set the configuration failed. If @config is set, then - * the details should be applied to the data port before any further - * configuration (like SLAAC) is done. @do_slaac indicates whether SLAAC - * should be started after applying @config to the data port. - */ - signals[IP6_CONFIG_RESULT] = g_signal_new(NM_MODEM_IP6_CONFIG_RESULT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 3, - G_TYPE_OBJECT, - G_TYPE_BOOLEAN, - G_TYPE_POINTER); - - signals[PREPARE_RESULT] = g_signal_new(NM_MODEM_PREPARE_RESULT, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - 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, - 0, - 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, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_POINTER); - - signals[REMOVED] = g_signal_new(NM_MODEM_REMOVED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 0); - - signals[STATE_CHANGED] = g_signal_new(NM_MODEM_STATE_CHANGED, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_INT, - G_TYPE_INT); -} diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h deleted file mode 100644 index 4b275cf7..00000000 --- a/src/devices/wwan/nm-modem.h +++ /dev/null @@ -1,269 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2009 - 2011 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_MODEM_H__ -#define __NETWORKMANAGER_MODEM_H__ - -#include "ppp/nm-ppp-manager.h" -#include "devices/nm-device.h" - -#define NM_TYPE_MODEM (nm_modem_get_type()) -#define NM_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_MODEM, NMModem)) -#define NM_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_MODEM, NMModemClass)) -#define NM_IS_MODEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_MODEM)) -#define NM_IS_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_MODEM)) -#define NM_MODEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_MODEM, NMModemClass)) - -/* Properties */ -#define NM_MODEM_UID "uid" -#define NM_MODEM_PATH "path" -#define NM_MODEM_DRIVER "driver" -#define NM_MODEM_CONTROL_PORT "control-port" -#define NM_MODEM_IP_IFINDEX "ip-ifindex" -#define NM_MODEM_STATE "state" -#define NM_MODEM_DEVICE_ID "device-id" -#define NM_MODEM_SIM_ID "sim-id" -#define NM_MODEM_IP_TYPES "ip-types" /* Supported IP types */ -#define NM_MODEM_SIM_OPERATOR_ID "sim-operator-id" -#define NM_MODEM_OPERATOR_CODE "operator-code" -#define NM_MODEM_APN "apn" - -/* Signals */ -#define NM_MODEM_PPP_STATS "ppp-stats" -#define NM_MODEM_PPP_FAILED "ppp-failed" -#define NM_MODEM_PREPARE_RESULT "prepare-result" -#define NM_MODEM_IP4_CONFIG_RESULT "ip4-config-result" -#define NM_MODEM_IP6_CONFIG_RESULT "ip6-config-result" -#define NM_MODEM_AUTH_REQUESTED "auth-requested" -#define NM_MODEM_AUTH_RESULT "auth-result" -#define NM_MODEM_REMOVED "removed" -#define NM_MODEM_STATE_CHANGED "state-changed" - -typedef enum { - NM_MODEM_IP_METHOD_UNKNOWN = 0, - NM_MODEM_IP_METHOD_PPP, - NM_MODEM_IP_METHOD_STATIC, - NM_MODEM_IP_METHOD_AUTO, /* DHCP and/or SLAAC */ -} NMModemIPMethod; - -/** - * NMModemIPType: - * @NM_MODEM_IP_TYPE_UNKNOWN: unknown or no IP support - * @NM_MODEM_IP_TYPE_IPV4: IPv4-only bearers are supported - * @NM_MODEM_IP_TYPE_IPV6: IPv6-only bearers are supported - * @NM_MODEM_IP_TYPE_IPV4V6: dual-stack IPv4 + IPv6 bearers are supported - * - * Indicates what IP protocols the modem supports for an IP bearer. Any - * combination of flags is possible. For example, (%NM_MODEM_IP_TYPE_IPV4 | - * %NM_MODEM_IP_TYPE_IPV6) indicates that the modem supports IPv4 and IPv6 - * but not simultaneously on the same bearer. - */ -typedef enum { - NM_MODEM_IP_TYPE_UNKNOWN = 0x0, - NM_MODEM_IP_TYPE_IPV4 = 0x1, - NM_MODEM_IP_TYPE_IPV6 = 0x2, - NM_MODEM_IP_TYPE_IPV4V6 = 0x4 -} NMModemIPType; - -typedef enum { /*< underscore_name=nm_modem_state >*/ - NM_MODEM_STATE_UNKNOWN = 0, - NM_MODEM_STATE_FAILED = 1, - NM_MODEM_STATE_INITIALIZING = 2, - NM_MODEM_STATE_LOCKED = 3, - NM_MODEM_STATE_DISABLED = 4, - NM_MODEM_STATE_DISABLING = 5, - NM_MODEM_STATE_ENABLING = 6, - NM_MODEM_STATE_ENABLED = 7, - NM_MODEM_STATE_SEARCHING = 8, - NM_MODEM_STATE_REGISTERED = 9, - NM_MODEM_STATE_DISCONNECTING = 10, - NM_MODEM_STATE_CONNECTING = 11, - NM_MODEM_STATE_CONNECTED = 12, - - _NM_MODEM_STATE_LAST0, - _NM_MODEM_STATE_LAST = _NM_MODEM_STATE_LAST0 - 1, -} NMModemState; - -struct _NMModemPrivate; - -struct _NMModem { - GObject parent; - struct _NMModemPrivate *_priv; -}; - -typedef struct _NMModem NMModem; - -typedef void (*_NMModemDisconnectCallback)(NMModem *modem, GError *error, gpointer user_data); - -typedef struct { - GObjectClass parent; - - void (*get_capabilities)(NMModem * self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps); - - gboolean (*get_user_pass)(NMModem * modem, - NMConnection *connection, - const char ** user, - const char ** pass); - - gboolean (*check_connection_compatible_with_modem)(NMModem * modem, - NMConnection *connection, - GError ** error); - - gboolean (*complete_connection)(NMModem * modem, - const char * iface, - NMConnection * connection, - NMConnection *const *existing_connections, - GError ** error); - - NMActStageReturn (*modem_act_stage1_prepare)(NMModem * modem, - NMConnection * connection, - NMDeviceStateReason *out_failure_reason); - - NMActStageReturn (*static_stage3_ip4_config_start)(NMModem * self, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason); - - /* Request the IP6 config; when the config returns the modem - * subclass should emit the ip6_config_result signal. - */ - NMActStageReturn (*stage3_ip6_config_request)(NMModem * self, - NMDeviceStateReason *out_failure_reason); - - void (*set_mm_enabled)(NMModem *self, gboolean enabled); - - void (*disconnect)(NMModem * self, - gboolean warn, - GCancellable * cancellable, - _NMModemDisconnectCallback callback, - gpointer user_data); - - void (*deactivate_cleanup)(NMModem *self, NMDevice *device, gboolean stop_ppp_manager); - - gboolean (*owns_port)(NMModem *self, const char *iface); -} NMModemClass; - -GType nm_modem_get_type(void); - -gboolean nm_modem_is_claimed(NMModem *modem); -NMModem *nm_modem_claim(NMModem *modem); -void nm_modem_unclaim(NMModem *modem); - -const char *nm_modem_get_path(NMModem *modem); -const char *nm_modem_get_uid(NMModem *modem); -const char *nm_modem_get_control_port(NMModem *modem); -int nm_modem_get_ip_ifindex(NMModem *modem); -const char *nm_modem_get_driver(NMModem *modem); -const char *nm_modem_get_device_id(NMModem *modem); -const char *nm_modem_get_sim_id(NMModem *modem); -const char *nm_modem_get_sim_operator_id(NMModem *modem); -gboolean nm_modem_get_iid(NMModem *modem, NMUtilsIPv6IfaceId *out_iid); -const char *nm_modem_get_operator_code(NMModem *modem); -const char *nm_modem_get_apn(NMModem *modem); - -gboolean nm_modem_set_data_port(NMModem * self, - NMPlatform * platform, - const char * data_port, - NMModemIPMethod ip4_method, - NMModemIPMethod ip6_method, - guint timeout, - GError ** error); - -gboolean nm_modem_owns_port(NMModem *modem, const char *iface); - -void nm_modem_get_capabilities(NMModem * self, - NMDeviceModemCapabilities *modem_caps, - NMDeviceModemCapabilities *current_caps); - -gboolean -nm_modem_check_connection_compatible(NMModem *self, NMConnection *connection, GError **error); - -gboolean nm_modem_complete_connection(NMModem * self, - const char * iface, - NMConnection * connection, - NMConnection *const *existing_connections, - GError ** error); - -void nm_modem_get_route_parameters(NMModem *self, - guint32 *out_ip4_route_table, - guint32 *out_ip4_route_metric, - guint32 *out_ip6_route_table, - guint32 *out_ip6_route_metric); - -void nm_modem_set_route_parameters(NMModem *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric); - -void nm_modem_set_route_parameters_from_device(NMModem *modem, NMDevice *device); - -NMActStageReturn nm_modem_act_stage1_prepare(NMModem * modem, - NMActRequest * req, - NMDeviceStateReason *out_failure_reason); - -void nm_modem_act_stage2_config(NMModem *modem); - -NMActStageReturn nm_modem_stage3_ip4_config_start(NMModem * modem, - NMDevice * device, - NMDeviceClass * device_class, - NMDeviceStateReason *out_failure_reason); - -NMActStageReturn nm_modem_stage3_ip6_config_start(NMModem * modem, - NMDevice * device, - NMDeviceStateReason *out_failure_reason); - -void nm_modem_ip4_pre_commit(NMModem *modem, NMDevice *device, NMIP4Config *config); - -void nm_modem_get_secrets(NMModem * modem, - const char *setting_name, - gboolean request_new, - const char *hint); - -void nm_modem_deactivate(NMModem *modem, NMDevice *device); - -typedef void (*NMModemDeactivateCallback)(NMModem *self, GError *error, gpointer user_data); - -void nm_modem_deactivate_async(NMModem * self, - NMDevice * device, - GCancellable * cancellable, - NMModemDeactivateCallback callback, - gpointer user_data); - -void -nm_modem_device_state_changed(NMModem *modem, NMDeviceState new_state, NMDeviceState old_state); - -void nm_modem_set_mm_enabled(NMModem *self, gboolean enabled); - -NMModemState nm_modem_get_state(NMModem *self); -void nm_modem_set_state(NMModem *self, NMModemState new_state, const char *reason); -void nm_modem_set_prev_state(NMModem *self, const char *reason); -const char * nm_modem_state_to_string(NMModemState state); - -NMModemIPType nm_modem_get_supported_ip_types(NMModem *self); - -/* For the modem-manager only */ -void nm_modem_emit_removed(NMModem *self); - -void nm_modem_emit_prepare_result(NMModem *self, gboolean success, NMDeviceStateReason reason); - -void nm_modem_emit_ppp_failed(NMModem *self, NMDeviceStateReason reason); - -GArray *nm_modem_get_connection_ip_type(NMModem *self, NMConnection *connection, GError **error); - -/* For subclasses */ -void nm_modem_emit_ip6_config_result(NMModem *self, NMIP6Config *config, GError *error); - -const char *nm_modem_ip_type_to_string(NMModemIPType ip_type); - -guint32 -nm_modem_get_configured_mtu(NMDevice *self, NMDeviceMtuSource *out_source, gboolean *out_force); - -void _nm_modem_set_operator_code(NMModem *self, const char *operator_code); -void _nm_modem_set_apn(NMModem *self, const char *apn); - -#endif /* __NETWORKMANAGER_MODEM_H__ */ diff --git a/src/devices/wwan/nm-service-providers.c b/src/devices/wwan/nm-service-providers.c deleted file mode 100644 index f7c6b5b8..00000000 --- a/src/devices/wwan/nm-service-providers.c +++ /dev/null @@ -1,455 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2009 Novell, Inc. - * Author: Tambet Ingo (tambet@gmail.com). - * Copyright (C) 2009 - 2019 Red Hat, Inc. - * Copyright (C) 2012 Lanedo GmbH - */ - -#include "nm-default.h" - -#include "nm-service-providers.h" - -typedef enum { - PARSER_TOPLEVEL = 0, - PARSER_COUNTRY, - PARSER_PROVIDER, - PARSER_METHOD_GSM, - PARSER_METHOD_GSM_APN, - PARSER_METHOD_CDMA, - PARSER_DONE, - PARSER_ERROR -} ParseContextState; - -typedef struct { - char * mccmnc; - NMServiceProvidersGsmApnCallback callback; - gpointer user_data; - GCancellable * cancellable; - GMarkupParseContext * ctx; - char buffer[4096]; - - char * text_buffer; - ParseContextState state; - - gboolean mccmnc_matched; - gboolean found_internet_apn; - char * apn; - char * username; - char * password; - char * gateway; - char * auth_method; - GSList * dns; -} ParseContext; - -/*****************************************************************************/ - -static void -parser_toplevel_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - int i; - - if (strcmp(name, "serviceproviders") == 0) { - for (i = 0; attribute_names && attribute_names[i]; i++) { - if (strcmp(attribute_names[i], "format") == 0) { - if (strcmp(attribute_values[i], "2.0")) { - g_warning("%s: mobile broadband provider database format '%s'" - " not supported.", - __func__, - attribute_values[i]); - parse_context->state = PARSER_ERROR; - break; - } - } - } - } else if (strcmp(name, "country") == 0) { - parse_context->state = PARSER_COUNTRY; - } -} - -static void -parser_country_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - if (strcmp(name, "provider") == 0) - parse_context->state = PARSER_PROVIDER; -} - -static void -parser_provider_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - parse_context->mccmnc_matched = FALSE; - if (strcmp(name, "gsm") == 0) - parse_context->state = PARSER_METHOD_GSM; - else if (strcmp(name, "cdma") == 0) - parse_context->state = PARSER_METHOD_CDMA; -} - -static void -parser_gsm_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - int i; - - if (strcmp(name, "network-id") == 0) { - const char *mcc = NULL, *mnc = NULL; - - for (i = 0; attribute_names && attribute_names[i]; i++) { - if (strcmp(attribute_names[i], "mcc") == 0) - mcc = attribute_values[i]; - else if (strcmp(attribute_names[i], "mnc") == 0) - mnc = attribute_values[i]; - if (mcc && strlen(mcc) && mnc && strlen(mnc)) { - char *mccmnc = g_strdup_printf("%s%s", mcc, mnc); - - if (strcmp(mccmnc, parse_context->mccmnc) == 0) - parse_context->mccmnc_matched = TRUE; - g_free(mccmnc); - break; - } - } - } else if (strcmp(name, "apn") == 0) { - parse_context->found_internet_apn = FALSE; - nm_clear_g_free(&parse_context->apn); - nm_clear_g_free(&parse_context->username); - nm_clear_g_free(&parse_context->password); - nm_clear_g_free(&parse_context->gateway); - nm_clear_g_free(&parse_context->auth_method); - g_slist_free_full(parse_context->dns, g_free); - parse_context->dns = NULL; - - for (i = 0; attribute_names && attribute_names[i]; i++) { - if (strcmp(attribute_names[i], "value") == 0) { - parse_context->state = PARSER_METHOD_GSM_APN; - parse_context->apn = g_strstrip(g_strdup(attribute_values[i])); - break; - } - } - } -} - -static void -parser_gsm_apn_start(ParseContext *parse_context, - const char * name, - const char ** attribute_names, - const char ** attribute_values) -{ - int i; - - if (strcmp(name, "usage") == 0) { - for (i = 0; attribute_names && attribute_names[i]; i++) { - if ((strcmp(attribute_names[i], "type") == 0) - && (strcmp(attribute_values[i], "internet") == 0)) { - parse_context->found_internet_apn = TRUE; - break; - } - } - } else if (strcmp(name, "authentication") == 0) { - for (i = 0; attribute_names && attribute_names[i]; i++) { - if (strcmp(attribute_names[i], "method") == 0) { - nm_clear_g_free(&parse_context->auth_method); - parse_context->auth_method = g_strstrip(g_strdup(attribute_values[i])); - break; - } - } - } -} - -static void -parser_start_element(GMarkupParseContext *context, - const char * element_name, - const char ** attribute_names, - const char ** attribute_values, - gpointer user_data, - GError ** error) -{ - ParseContext *parse_context = user_data; - - nm_clear_g_free(&parse_context->text_buffer); - - switch (parse_context->state) { - case PARSER_TOPLEVEL: - parser_toplevel_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_COUNTRY: - parser_country_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_PROVIDER: - parser_provider_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_METHOD_GSM: - parser_gsm_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_METHOD_GSM_APN: - parser_gsm_apn_start(parse_context, element_name, attribute_names, attribute_values); - break; - case PARSER_METHOD_CDMA: - break; - case PARSER_ERROR: - break; - case PARSER_DONE: - break; - } -} - -static void -parser_country_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "country") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - parse_context->state = PARSER_TOPLEVEL; - } -} - -static void -parser_provider_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "provider") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - parse_context->state = PARSER_COUNTRY; - } -} - -static void -parser_gsm_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "gsm") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - parse_context->state = PARSER_PROVIDER; - } -} - -static void -parser_gsm_apn_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "username") == 0) { - nm_clear_g_free(&parse_context->username); - parse_context->username = g_steal_pointer(&parse_context->text_buffer); - } else if (strcmp(name, "password") == 0) { - nm_clear_g_free(&parse_context->password); - parse_context->password = g_steal_pointer(&parse_context->text_buffer); - } else if (strcmp(name, "dns") == 0) { - parse_context->dns = - g_slist_prepend(parse_context->dns, g_steal_pointer(&parse_context->text_buffer)); - } else if (strcmp(name, "gateway") == 0) { - nm_clear_g_free(&parse_context->gateway); - parse_context->gateway = g_steal_pointer(&parse_context->text_buffer); - } else if (strcmp(name, "apn") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - - if (parse_context->mccmnc_matched && parse_context->found_internet_apn) - parse_context->state = PARSER_DONE; - else - parse_context->state = PARSER_METHOD_GSM; - } -} - -static void -parser_cdma_end(ParseContext *parse_context, const char *name) -{ - if (strcmp(name, "cdma") == 0) { - nm_clear_g_free(&parse_context->text_buffer); - parse_context->state = PARSER_PROVIDER; - } -} - -static void -parser_end_element(GMarkupParseContext *context, - const char * element_name, - gpointer user_data, - GError ** error) -{ - ParseContext *parse_context = user_data; - - switch (parse_context->state) { - case PARSER_TOPLEVEL: - break; - case PARSER_COUNTRY: - parser_country_end(parse_context, element_name); - break; - case PARSER_PROVIDER: - parser_provider_end(parse_context, element_name); - break; - case PARSER_METHOD_GSM: - parser_gsm_end(parse_context, element_name); - break; - case PARSER_METHOD_GSM_APN: - parser_gsm_apn_end(parse_context, element_name); - break; - case PARSER_METHOD_CDMA: - parser_cdma_end(parse_context, element_name); - break; - case PARSER_ERROR: - break; - case PARSER_DONE: - break; - } -} - -static void -parser_text(GMarkupParseContext *context, - const char * text, - gsize text_len, - gpointer user_data, - GError ** error) -{ - ParseContext *parse_context = user_data; - - g_free(parse_context->text_buffer); - parse_context->text_buffer = g_strdup(text); -} - -static const GMarkupParser parser = { - .start_element = parser_start_element, - .end_element = parser_end_element, - .text = parser_text, - .passthrough = NULL, - .error = NULL, -}; - -/*****************************************************************************/ - -static void -finish_parse_context(ParseContext *parse_context, GError *error) -{ - if (parse_context->callback) { - if (error) { - parse_context - ->callback(NULL, NULL, NULL, NULL, NULL, NULL, error, parse_context->user_data); - } else { - parse_context->callback(parse_context->apn, - parse_context->username, - parse_context->password, - parse_context->gateway, - parse_context->auth_method, - parse_context->dns, - error, - parse_context->user_data); - } - } - - g_free(parse_context->mccmnc); - g_markup_parse_context_free(parse_context->ctx); - - g_free(parse_context->text_buffer); - g_free(parse_context->apn); - g_free(parse_context->username); - g_free(parse_context->password); - g_free(parse_context->gateway); - g_free(parse_context->auth_method); - g_slist_free_full(parse_context->dns, g_free); - - g_slice_free(ParseContext, parse_context); -} - -static void read_next_chunk(GInputStream *stream, ParseContext *parse_context); - -static void -stream_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - GInputStream *stream = G_INPUT_STREAM(source_object); - ParseContext *parse_context = user_data; - gssize len; - GError * error = NULL; - - len = g_input_stream_read_finish(stream, res, &error); - if (len == -1) { - g_prefix_error(&error, "Error reading service provider database: "); - finish_parse_context(parse_context, error); - g_clear_error(&error); - return; - } - - if (len == 0) { - g_set_error(&error, - NM_UTILS_ERROR, - NM_UTILS_ERROR_UNKNOWN, - "Operator ID '%s' not found in service provider database", - parse_context->mccmnc); - finish_parse_context(parse_context, error); - g_clear_error(&error); - return; - } - - if (!g_markup_parse_context_parse(parse_context->ctx, parse_context->buffer, len, &error)) { - g_prefix_error(&error, "Error parsing service provider database: "); - finish_parse_context(parse_context, error); - g_clear_error(&error); - return; - } - - if (parse_context->state == PARSER_DONE) { - finish_parse_context(parse_context, NULL); - return; - } - - read_next_chunk(stream, parse_context); -} - -static void -read_next_chunk(GInputStream *stream, ParseContext *parse_context) -{ - g_input_stream_read_async(stream, - parse_context->buffer, - sizeof(parse_context->buffer), - G_PRIORITY_DEFAULT, - parse_context->cancellable, - stream_read_cb, - parse_context); -} - -static void -file_read_cb(GObject *source_object, GAsyncResult *res, gpointer user_data) -{ - GFile * file = G_FILE(source_object); - ParseContext * parse_context = user_data; - GFileInputStream *stream; - gs_free_error GError *error = NULL; - - stream = g_file_read_finish(file, res, &error); - if (!stream) { - g_prefix_error(&error, "Error opening service provider database: "); - finish_parse_context(parse_context, error); - return; - } - - read_next_chunk(G_INPUT_STREAM(stream), parse_context); - - g_object_unref(stream); -} - -/*****************************************************************************/ - -void -nm_service_providers_find_gsm_apn(const char * service_providers, - const char * mccmnc, - GCancellable * cancellable, - NMServiceProvidersGsmApnCallback callback, - gpointer user_data) -{ - GFile * file; - ParseContext *parse_context; - - parse_context = g_slice_new0(ParseContext); - parse_context->mccmnc = g_strdup(mccmnc); - parse_context->cancellable = cancellable; - parse_context->callback = callback; - parse_context->user_data = user_data; - parse_context->ctx = g_markup_parse_context_new(&parser, 0, parse_context, NULL); - - file = g_file_new_for_path(service_providers); - - g_file_read_async(file, G_PRIORITY_DEFAULT, cancellable, file_read_cb, parse_context); - - g_object_unref(file); -} diff --git a/src/devices/wwan/nm-service-providers.h b/src/devices/wwan/nm-service-providers.h deleted file mode 100644 index 093bcd5b..00000000 --- a/src/devices/wwan/nm-service-providers.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_SERVICE_PROVIDERS_H__ -#define __NETWORKMANAGER_SERVICE_PROVIDERS_H__ - -typedef void (*NMServiceProvidersGsmApnCallback)(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data); - -void nm_service_providers_find_gsm_apn(const char * service_providers, - const char * mccmnc, - GCancellable * cancellable, - NMServiceProvidersGsmApnCallback callback, - gpointer user_data); - -#endif /* __NETWORKMANAGER_SERVICE_PROVIDERS_H__ */ diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c deleted file mode 100644 index 1c3406da..00000000 --- a/src/devices/wwan/nm-wwan-factory.c +++ /dev/null @@ -1,146 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include <gmodule.h> - -#include "devices/nm-device-factory.h" -#include "nm-setting-gsm.h" -#include "nm-setting-cdma.h" -#include "nm-modem-manager.h" -#include "nm-device-modem.h" -#include "platform/nm-platform.h" - -/*****************************************************************************/ - -#define NM_TYPE_WWAN_FACTORY (nm_wwan_factory_get_type()) -#define NM_WWAN_FACTORY(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) -#define NM_WWAN_FACTORY_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_WWAN_FACTORY, NMWwanFactoryClass)) -#define NM_IS_WWAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_WWAN_FACTORY)) -#define NM_IS_WWAN_FACTORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_WWAN_FACTORY)) -#define NM_WWAN_FACTORY_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactoryClass)) - -typedef struct { - NMModemManager *mm; -} NMWwanFactoryPrivate; - -typedef struct { - NMDeviceFactory parent; - NMWwanFactoryPrivate _priv; -} NMWwanFactory; - -typedef struct { - NMDeviceFactoryClass parent; -} NMWwanFactoryClass; - -static GType nm_wwan_factory_get_type(void); - -G_DEFINE_TYPE(NMWwanFactory, nm_wwan_factory, NM_TYPE_DEVICE_FACTORY) - -#define NM_WWAN_FACTORY_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMWwanFactory, NM_IS_WWAN_FACTORY) - -/*****************************************************************************/ - -NM_DEVICE_FACTORY_DECLARE_TYPES(NM_DEVICE_FACTORY_DECLARE_LINK_TYPES( - NM_LINK_TYPE_WWAN_NET) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_CDMA_SETTING_NAME)) - -G_MODULE_EXPORT NMDeviceFactory * - nm_device_factory_create(GError **error) -{ - return (NMDeviceFactory *) g_object_new(NM_TYPE_WWAN_FACTORY, NULL); -} - -/*****************************************************************************/ - -static void -modem_added_cb(NMModemManager *manager, NMModem *modem, gpointer user_data) -{ - NMWwanFactory * self = NM_WWAN_FACTORY(user_data); - gs_unref_object NMDevice *device = NULL; - const char * driver; - - if (nm_modem_is_claimed(modem)) - return; - - driver = nm_modem_get_driver(modem); - - /* If it was a Bluetooth modem and no bluetooth device claimed it, ignore - * it. The rfcomm port (and thus the modem) gets created automatically - * by the Bluetooth code during the connection process. - */ - if (driver && strstr(driver, "bluetooth")) { - nm_log_dbg( - LOGD_MB, - "WWAN factory ignores bluetooth modem '%s' which should be handled by bluetooth plugin", - nm_modem_get_control_port(modem)); - return; - } - - /* Make the new modem device */ - device = nm_device_modem_new(modem); - g_signal_emit_by_name(self, NM_DEVICE_FACTORY_DEVICE_ADDED, device); -} - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - g_return_val_if_fail(plink, NULL); - g_return_val_if_fail(plink->type == NM_LINK_TYPE_WWAN_NET, NULL); - *out_ignore = TRUE; - return NULL; -} - -static void -start(NMDeviceFactory *factory) -{ - NMWwanFactory * self = NM_WWAN_FACTORY(factory); - NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE(self); - - priv->mm = g_object_ref(nm_modem_manager_get()); - - g_signal_connect(priv->mm, NM_MODEM_MANAGER_MODEM_ADDED, G_CALLBACK(modem_added_cb), self); -} - -/*****************************************************************************/ - -static void -nm_wwan_factory_init(NMWwanFactory *self) -{} - -static void -dispose(GObject *object) -{ - NMWwanFactory * self = NM_WWAN_FACTORY(object); - NMWwanFactoryPrivate *priv = NM_WWAN_FACTORY_GET_PRIVATE(self); - - if (priv->mm) - g_signal_handlers_disconnect_by_func(priv->mm, modem_added_cb, self); - g_clear_object(&priv->mm); - - /* Chain up to the parent class */ - G_OBJECT_CLASS(nm_wwan_factory_parent_class)->dispose(object); -} - -static void -nm_wwan_factory_class_init(NMWwanFactoryClass *klass) -{ - GObjectClass * object_class = G_OBJECT_CLASS(klass); - NMDeviceFactoryClass *factory_class = NM_DEVICE_FACTORY_CLASS(klass); - - object_class->dispose = dispose; - - factory_class->get_supported_types = get_supported_types; - factory_class->create_device = create_device; - factory_class->start = start; -} diff --git a/src/devices/wwan/tests/test-service-providers.c b/src/devices/wwan/tests/test-service-providers.c deleted file mode 100644 index ec19d588..00000000 --- a/src/devices/wwan/tests/test-service-providers.c +++ /dev/null @@ -1,130 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2019 Red Hat - */ - -#include "nm-default.h" - -#include "nm-service-providers.h" - -#include "nm-test-utils-core.h" - -static void -test_positive_cb(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data) -{ - GMainLoop *loop = user_data; - - g_main_loop_quit(loop); - g_assert_no_error(error); - g_assert_cmpstr(apn, ==, "gprs.example.com"); - g_assert_cmpstr(username, ==, "praise"); - g_assert_cmpstr(password, ==, "santa"); - g_assert_cmpstr(gateway, ==, "192.0.2.3"); - g_assert_cmpstr(auth_method, ==, "pap"); - - g_assert_nonnull(dns); - g_assert_cmpstr(dns->data, ==, "192.0.2.2"); - dns = dns->next; - g_assert_nonnull(dns); - g_assert_cmpstr(dns->data, ==, "192.0.2.1"); - g_assert_null(dns->next); -} - -static void -test_positive(void) -{ - GMainLoop *loop = g_main_loop_new(NULL, FALSE); - - nm_service_providers_find_gsm_apn(NM_BUILD_SRCDIR - "/src/devices/wwan/tests/test-service-providers.xml", - "13337", - NULL, - test_positive_cb, - loop); - g_main_loop_run(loop); - g_main_loop_unref(loop); -} - -/*****************************************************************************/ - -static void -test_negative_cb(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data) -{ - GMainLoop *loop = user_data; - - g_main_loop_quit(loop); - g_assert_error(error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN); -} - -static void -test_negative(void) -{ - GMainLoop *loop = g_main_loop_new(NULL, FALSE); - - nm_service_providers_find_gsm_apn(NM_BUILD_SRCDIR - "/src/devices/wwan/tests/test-service-providers.xml", - "78130", - NULL, - test_negative_cb, - loop); - g_main_loop_run(loop); - g_main_loop_unref(loop); -} - -/*****************************************************************************/ - -static void -test_nonexistent_cb(const char * apn, - const char * username, - const char * password, - const char * gateway, - const char * auth_method, - const GSList *dns, - GError * error, - gpointer user_data) -{ - GMainLoop *loop = user_data; - - g_main_loop_quit(loop); - g_assert_error(error, G_IO_ERROR, G_IO_ERROR_AGAIN); -} - -static void -test_nonexistent(void) -{ - GMainLoop *loop = g_main_loop_new(NULL, FALSE); - - nm_service_providers_find_gsm_apn("nonexistent.xml", "13337", NULL, test_nonexistent_cb, loop); - g_main_loop_run(loop); - g_main_loop_unref(loop); -} - -/*****************************************************************************/ - -NMTST_DEFINE(); - -int -main(int argc, char **argv) -{ - nmtst_init_assert_logging(&argc, &argv, "INFO", "DEFAULT"); - - g_test_add_func("/service-providers/positive", test_positive); - g_test_add_func("/service-providers/negative", test_negative); - g_test_add_func("/service-providers/nonexistent", test_nonexistent); - - return g_test_run(); -} diff --git a/src/devices/wwan/tests/test-service-providers.xml b/src/devices/wwan/tests/test-service-providers.xml deleted file mode 100644 index f0ca2deb..00000000 --- a/src/devices/wwan/tests/test-service-providers.xml +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding='utf-8'?> -<!DOCTYPE serviceproviders SYSTEM "serviceproviders.2.dtd"> - -<serviceproviders format="2.0"> - -<country code="feh"> - <provider> - <name>Sophia</name> - <gsm> - <network-id mcc="666" mnc="999"/> - <apn value="access.example.com"> - <plan type="postpaid"/> - <usage type="internet"/> - <name>APN</name> - <dns>192.0.2.1</dns> - <dns>192.0.2.2</dns> - </apn> - </gsm> - </provider> -</country> - -<country code="meh"> - <provider> - <name>Demiurge</name> - <gsm> - <network-id mcc="133" mnc="37"/> - <network-id mcc="133" mnc="666"/> - <apn value="mms"> - <usage type="mms"/> - <name>Unsolicited Nudes MMS</name> - <username>mms</username> - <password>mms</password> - <mmsc>http://mms.example.com/</mmsc> - <mmsproxy>192.0.2.1:8080</mmsproxy> - </apn> - <apn value="gprs.example.com"> - <plan type="postpaid"/> - <usage type="internet"/> - <name>GPRS</name> - <username>praise</username> - <password>santa</password> - <dns>192.0.2.1</dns> - <dns>192.0.2.2</dns> - <gateway>192.0.2.3</gateway> - <authentication method="pap"/> - </apn> - <apn value="second.example.com"> - <plan type="postpaid"/> - <usage type="internet"/> - <name>Second</name> - <username>worship</username> - <password>doom</password> - </apn> - </gsm> - </provider> - - <provider> - <name>Personal</name> - <gsm> - <network-id mcc="666" mnc="999"/> - <apn value="access.example.com"> - <plan type="postpaid"/> - <usage type="internet"/> - <name>APN</name> - <dns>192.0.2.1</dns> - <dns>192.0.2.2</dns> - </apn> - </gsm> - </provider> -</country> - -</serviceproviders> - |