diff options
Diffstat (limited to 'src/devices/wwan/nm-modem.c')
| -rw-r--r-- | src/devices/wwan/nm-modem.c | 2037 |
1 files changed, 0 insertions, 2037 deletions
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); -} |