static gboolean set_ip_config_common (NMPPPManager *self, GVariant *config_dict, const char *iface_prop, guint32 *out_mtu) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); NMConnection *applied_connection; NMSettingPpp *s_ppp; const char *iface; if (!g_variant_lookup (config_dict, iface_prop, "&s", &iface)) { _LOGE ("no interface received!"); return FALSE; } if (priv->ip_iface == NULL) priv->ip_iface = g_strdup (iface); /* Got successful IP config; obviously the secrets worked */ applied_connection = nm_act_request_get_applied_connection (priv->act_req); g_object_set_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES, NULL); if (out_mtu) { /* Get any custom MTU */ s_ppp = nm_connection_get_setting_ppp (applied_connection); *out_mtu = s_ppp ? nm_setting_ppp_get_mtu (s_ppp) : 0; } monitor_stats (self); return TRUE; }
static NMActStageReturn act_stage3_ip4_config_start (NMDevice *device, NMIP4Config **out_config, NMDeviceStateReason *reason) { NMDeviceAdsl *self = NM_DEVICE_ADSL (device); NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self); NMConnection *connection; NMSettingAdsl *s_adsl; NMActRequest *req; GError *err = NULL; NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; const char *ppp_iface; req = nm_device_get_act_request (device); g_assert (req); connection = nm_act_request_get_applied_connection (req); g_assert (req); s_adsl = nm_connection_get_setting_adsl (connection); g_assert (s_adsl); /* PPPoE uses the NAS interface, not the ATM interface */ if (g_strcmp0 (nm_setting_adsl_get_protocol (s_adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) { g_assert (priv->nas_ifname); ppp_iface = priv->nas_ifname; _LOGD (LOGD_ADSL, "starting PPPoE on NAS interface %s", priv->nas_ifname); } else { ppp_iface = nm_device_get_iface (device); _LOGD (LOGD_ADSL, "starting PPPoA"); } priv->ppp_manager = nm_ppp_manager_new (ppp_iface); if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), 30, &err)) { g_signal_connect (priv->ppp_manager, "state-changed", G_CALLBACK (ppp_state_changed), self); g_signal_connect (priv->ppp_manager, "ip4-config", G_CALLBACK (ppp_ip4_config), self); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else { _LOGW (LOGD_ADSL, "PPP failed to start: %s", err->message); g_error_free (err); g_object_unref (priv->ppp_manager); priv->ppp_manager = NULL; *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; } return ret; }
NMActStageReturn nm_modem_stage3_ip4_config_start (NMModem *self, NMDevice *device, NMDeviceClass *device_class, NMDeviceStateReason *reason) { NMModemPrivate *priv; NMActRequest *req; NMConnection *connection; const char *method; NMActStageReturn ret; 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); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); req = nm_device_get_act_request (device); g_assert (req); connection = nm_act_request_get_applied_connection (req); g_assert (connection); method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); /* Only Disabled and Auto methods make sense for WWAN */ if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0) return NM_ACT_STAGE_RETURN_STOP; if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) != 0) { nm_log_warn (LOGD_MB | LOGD_IP4, "(%s): unhandled WWAN IPv4 method '%s'; will fail", nm_modem_get_uid (self), method); *reason = NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE; 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, reason); break; case NM_MODEM_IP_METHOD_STATIC: ret = NM_MODEM_GET_CLASS (self)->static_stage3_ip4_config_start (self, req, reason); break; case NM_MODEM_IP_METHOD_AUTO: ret = device_class->act_stage3_ip4_config_start (device, NULL, reason); break; default: nm_log_info (LOGD_MB, "(%s): IPv4 configuration disabled", nm_modem_get_uid (self)); ret = NM_ACT_STAGE_RETURN_STOP; break; } return ret; }
NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *self, NMActRequest *req, NMDeviceStateReason *reason) { NMModemPrivate *priv; NMActStageReturn ret; NMConnection *connection; const char *method; g_return_val_if_fail (self != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (NM_IS_MODEM (self), NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); connection = nm_act_request_get_applied_connection (req); g_assert (connection); method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); /* Only Ignore and Auto methods make sense for WWAN */ if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0) return NM_ACT_STAGE_RETURN_STOP; if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) != 0) { nm_log_warn (LOGD_MB | LOGD_IP6, "(%s): unhandled WWAN IPv6 method '%s'; will fail", nm_modem_get_uid (self), method); *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, 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, reason); break; default: nm_log_info (LOGD_MB, "(%s): IPv6 configuration disabled", nm_modem_get_uid (self)); ret = NM_ACT_STAGE_RETURN_STOP; break; } return ret; }
static void impl_ppp_manager_need_secrets (NMPPPManager *manager, GDBusMethodInvocation *context) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); NMConnection *applied_connection; const char *username = NULL; const char *password = NULL; guint32 tries; GPtrArray *hints = NULL; GError *error = NULL; NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (priv->act_req)); applied_connection = nm_act_request_get_applied_connection (priv->act_req); priv->secrets_setting_name = nm_connection_need_secrets (applied_connection, &hints); if (!priv->secrets_setting_name) { /* Use existing secrets from the connection */ if (extract_details_from_connection (applied_connection, NULL, &username, &password, &error)) { /* Send existing secrets to the PPP plugin */ priv->pending_secrets_context = context; ppp_secrets_cb (priv->act_req, priv->secrets_id, NULL, NULL, manager); } else { _LOGW ("%s", error->message); g_dbus_method_invocation_take_error (priv->pending_secrets_context, error); } return; } /* Only ask for completely new secrets after retrying them once; some devices * appear to ask a few times when they actually don't even care what you * pass back. */ tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES)); if (tries > 1) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; priv->secrets_id = nm_act_request_get_secrets (priv->act_req, priv->secrets_setting_name, flags, hints ? g_ptr_array_index (hints, 0) : NULL, ppp_secrets_cb, manager); g_object_set_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES, GUINT_TO_POINTER (++tries)); priv->pending_secrets_context = context; if (hints) g_ptr_array_free (hints, TRUE); }
static NMActStageReturn act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) { NMActRequest *req; NMConnection *connection; NMSettingVlan *s_vlan; NMSettingWired *s_wired; const char *cloned_mac; NMActStageReturn ret; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); ret = NM_DEVICE_CLASS (nm_device_vlan_parent_class)->act_stage1_prepare (dev, reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; req = nm_device_get_act_request (dev); g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); connection = nm_act_request_get_applied_connection (req); g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); s_wired = nm_connection_get_setting_wired (connection); if (s_wired) { /* Set device MAC address if the connection wants to change it */ cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); if (cloned_mac) nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_VLAN); } s_vlan = nm_connection_get_setting_vlan (connection); if (s_vlan) { int ifindex = nm_device_get_ifindex (dev); int num, i; guint32 from, to; num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP); for (i = 0; i < num; i++) { if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to)) nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, from, to); } num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP); for (i = 0; i < num; i++) { if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to)) nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, from, to); } } return ret; }
static void ppp_secrets_cb (NMActRequest *req, NMActRequestGetSecretsCallId call_id, NMSettingsConnection *settings_connection, /* unused (we pass NULL here) */ GError *error, gpointer user_data) { NMPPPManager *self = NM_PPP_MANAGER (user_data); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); const char *username = NULL; const char *password = NULL; GError *local = NULL; NMConnection *applied_connection; g_return_if_fail (priv->pending_secrets_context != NULL); g_return_if_fail (req == priv->act_req); g_return_if_fail (call_id == priv->secrets_id); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) goto out; if (error) { _LOGW ("%s", error->message); g_dbus_method_invocation_return_gerror (priv->pending_secrets_context, error); goto out; } applied_connection = nm_act_request_get_applied_connection (req); if (!extract_details_from_connection (applied_connection, priv->secrets_setting_name, &username, &password, &local)) { _LOGW ("%s", local->message); g_dbus_method_invocation_take_error (priv->pending_secrets_context, local); goto out; } /* This is sort of a hack but... * pppd plugin only ever needs username and password. Passing the full * connection there would mean some bloat: the plugin would need to link * against libnm just to parse this. So instead, let's just send what * it needs. */ g_dbus_method_invocation_return_value ( priv->pending_secrets_context, g_variant_new ("(ss)", username ? username : "", password ? password : "")); out: priv->pending_secrets_context = NULL; priv->secrets_id = NULL; priv->secrets_setting_name = NULL; }
/** * nm_act_request_get_secrets: * @self: * @setting_name: * @flags: * @hint: * @callback: * @callback_data: * * Asnychronously starts the request for secrets. This function cannot * fail. * * The return call-id can be used to cancel the request. You are * only allowed to cancel a still pending operation (once). * The callback will always be invoked once, even for canceling * or disposing of NMActRequest. * * Returns: a call-id. */ NMActRequestGetSecretsCallId nm_act_request_get_secrets (NMActRequest *self, const char *setting_name, NMSecretAgentGetSecretsFlags flags, const char *hint, NMActRequestSecretsFunc callback, gpointer callback_data) { NMActRequestPrivate *priv; GetSecretsInfo *info; NMSettingsConnectionCallId call_id_s; NMSettingsConnection *settings_connection; NMConnection *applied_connection; const char *hints[2] = { hint, NULL }; g_return_val_if_fail (NM_IS_ACT_REQUEST (self), 0); priv = NM_ACT_REQUEST_GET_PRIVATE (self); settings_connection = nm_act_request_get_settings_connection (self); applied_connection = nm_act_request_get_applied_connection (self); info = _get_secrets_info_new (self, callback, callback_data); priv->secrets_calls = g_slist_append (priv->secrets_calls, info); if (nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (self))) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED; call_id_s = nm_settings_connection_get_secrets (settings_connection, applied_connection, nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (self)), setting_name, flags, hints, get_secrets_cb, info); info->call_id = call_id_s; g_return_val_if_fail (call_id_s, NULL); return info; }
NMActStageReturn nm_modem_act_stage1_prepare (NMModem *self, NMActRequest *req, NMDeviceStateReason *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; 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_assert (connection); setting_name = nm_connection_need_secrets (connection, &hints); if (!setting_name) { /* Ready to connect */ g_assert (!hints); return NM_MODEM_GET_CLASS (self)->act_stage1_prepare (self, connection, reason); } /* Secrets required... */ if (priv->secrets_tries++) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; priv->secrets_id = nm_act_request_get_secrets (req, setting_name, flags, hints ? g_ptr_array_index (hints, 0) : 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; }
static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); NMActRequest *req; NMConnection *connection; NMSettingWired *s_wired; const char *cloned_mac; NMActStageReturn ret; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); ret = NM_DEVICE_CLASS (nm_device_tun_parent_class)->act_stage1_prepare (device, reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; /* Nothing to do for TUN devices */ if (g_strcmp0 (priv->mode, "tap")) return NM_ACT_STAGE_RETURN_SUCCESS; req = nm_device_get_act_request (device); g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); connection = nm_act_request_get_applied_connection (req); g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); s_wired = nm_connection_get_setting_wired (connection); if (s_wired) { /* Set device MAC address if the connection wants to change it */ cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); if (cloned_mac) nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE); } return NM_ACT_STAGE_RETURN_SUCCESS; }
static NMActStageReturn ppp_stage3_ip_config_start (NMModem *self, NMActRequest *req, NMDeviceStateReason *reason) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); const char *ppp_name = NULL; GError *error = NULL; NMActStageReturn ret; guint ip_timeout = 30; 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); g_return_val_if_fail (reason != NULL, 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; } /* 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) { nm_log_info (LOGD_PPP, "(%s): using modem-specified IP timeout: %u seconds", nm_modem_get_uid (self), priv->mm_ip_timeout); ip_timeout = priv->mm_ip_timeout; } priv->ppp_manager = nm_ppp_manager_new (priv->data_port); if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) { g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_STATE_CHANGED, G_CALLBACK (ppp_state_changed), self); g_signal_connect (priv->ppp_manager, "ip4-config", G_CALLBACK (ppp_ip4_config), self); g_signal_connect (priv->ppp_manager, "ip6-config", G_CALLBACK (ppp_ip6_config), self); g_signal_connect (priv->ppp_manager, "stats", G_CALLBACK (ppp_stats), self); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else { nm_log_err (LOGD_PPP, "(%s): error starting PPP: %s", nm_modem_get_uid (self), error->message); g_error_free (error); nm_exported_object_clear_and_unexport (&priv->ppp_manager); *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; ret = NM_ACT_STAGE_RETURN_FAILURE; } return ret; }
gboolean nm_ppp_manager_start (NMPPPManager *manager, NMActRequest *req, const char *ppp_name, guint32 timeout_secs, GError **err) { NMPPPManagerPrivate *priv; NMConnection *connection; NMSettingPpp *s_ppp; gboolean s_ppp_created = FALSE; NMSettingPppoe *pppoe_setting; NMSettingAdsl *adsl_setting; NMCmdLine *ppp_cmd; char *cmd_str; struct stat st; g_return_val_if_fail (NM_IS_PPP_MANAGER (manager), FALSE); g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); priv = NM_PPP_MANAGER_GET_PRIVATE (manager); #if !WITH_PPP /* PPP support disabled */ g_set_error_literal (err, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "PPP support is not enabled."); return FALSE; #endif priv->pid = 0; /* Make sure /dev/ppp exists (bgo #533064) */ if (stat ("/dev/ppp", &st) || !S_ISCHR (st.st_mode)) nm_utils_modprobe (NULL, FALSE, "ppp_generic", NULL); connection = nm_act_request_get_applied_connection (req); g_assert (connection); s_ppp = nm_connection_get_setting_ppp (connection); if (!s_ppp) { /* If the PPP settings are all default we may not have a PPP setting yet, * so just make a default one here. */ s_ppp = NM_SETTING_PPP (nm_setting_ppp_new ()); s_ppp_created = TRUE; } pppoe_setting = nm_connection_get_setting_pppoe (connection); if (pppoe_setting) pppoe_fill_defaults (s_ppp); adsl_setting = (NMSettingAdsl *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ADSL); ppp_cmd = create_pppd_cmd_line (manager, s_ppp, pppoe_setting, adsl_setting, ppp_name, err); if (!ppp_cmd) goto out; g_ptr_array_add (ppp_cmd->array, NULL); _LOGI ("starting PPP connection"); cmd_str = nm_cmd_line_to_str (ppp_cmd); _LOGD ("command line: %s", cmd_str); g_free (cmd_str); priv->pid = 0; if (!g_spawn_async (NULL, (char **) ppp_cmd->array->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, nm_utils_setpgid, NULL, &priv->pid, err)) { goto out; } _LOGI ("pppd started with pid %d", priv->pid); priv->ppp_watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) ppp_watch_cb, manager); priv->ppp_timeout_handler = g_timeout_add_seconds (timeout_secs, pppd_timed_out, manager); priv->act_req = g_object_ref (req); out: if (s_ppp_created) g_object_unref (s_ppp); if (ppp_cmd) nm_cmd_line_destroy (ppp_cmd); return priv->pid > 0; }