diff options
Diffstat (limited to 'src/core/ppp')
| -rw-r--r-- | src/core/ppp/nm-ppp-manager-call.c | 32 | ||||
| -rw-r--r-- | src/core/ppp/nm-ppp-manager-call.h | 14 | ||||
| -rw-r--r-- | src/core/ppp/nm-ppp-manager.c | 436 | ||||
| -rw-r--r-- | src/core/ppp/nm-ppp-manager.h | 5 | ||||
| -rw-r--r-- | src/core/ppp/nm-ppp-mgr.c | 620 | ||||
| -rw-r--r-- | src/core/ppp/nm-ppp-mgr.h | 131 | ||||
| -rw-r--r-- | src/core/ppp/nm-ppp-plugin-api.h | 14 | ||||
| -rw-r--r-- | src/core/ppp/nm-ppp-status.h | 5 | ||||
| -rw-r--r-- | src/core/ppp/nm-pppd-plugin.c | 12 |
9 files changed, 1000 insertions, 269 deletions
diff --git a/src/core/ppp/nm-ppp-manager-call.c b/src/core/ppp/nm-ppp-manager-call.c index 5e84f596..8c788fad 100644 --- a/src/core/ppp/nm-ppp-manager-call.c +++ b/src/core/ppp/nm-ppp-manager-call.c @@ -25,9 +25,9 @@ static const NMPPPOps *_ppp_ops = NULL; NMPPPManager * nm_ppp_manager_create(const char *iface, GError **error) { - NMPPPManager * ret; - GModule * plugin; - GError * error_local = NULL; + NMPPPManager *ret; + GModule *plugin; + GError *error_local = NULL; struct stat st; const NMPPPOps *ppp_ops; @@ -94,31 +94,13 @@ again: return ret; } -void -nm_ppp_manager_set_route_parameters(NMPPPManager *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric) -{ - const NMPPPOps *ppp_ops = ppp_ops_get(); - - g_return_if_fail(ppp_ops); - - ppp_ops->set_route_parameters(self, - ip4_route_table, - ip4_route_metric, - ip6_route_table, - ip6_route_metric); -} - gboolean nm_ppp_manager_start(NMPPPManager *self, NMActRequest *req, - const char * ppp_name, + const char *ppp_name, guint32 timeout_secs, guint baud_override, - GError ** err) + GError **err) { const NMPPPOps *ppp_ops = ppp_ops_get(); @@ -128,8 +110,8 @@ nm_ppp_manager_start(NMPPPManager *self, } NMPPPManagerStopHandle * -nm_ppp_manager_stop(NMPPPManager * self, - GCancellable * cancellable, +nm_ppp_manager_stop(NMPPPManager *self, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data) { diff --git a/src/core/ppp/nm-ppp-manager-call.h b/src/core/ppp/nm-ppp-manager-call.h index c831cf0d..ef081200 100644 --- a/src/core/ppp/nm-ppp-manager-call.h +++ b/src/core/ppp/nm-ppp-manager-call.h @@ -10,21 +10,15 @@ NMPPPManager *nm_ppp_manager_create(const char *iface, GError **error); -void nm_ppp_manager_set_route_parameters(NMPPPManager *ppp_manager, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric); - gboolean nm_ppp_manager_start(NMPPPManager *self, NMActRequest *req, - const char * ppp_name, + const char *ppp_name, guint32 timeout_secs, guint baud_override, - GError ** error); + GError **error); -NMPPPManagerStopHandle *nm_ppp_manager_stop(NMPPPManager * self, - GCancellable * cancellable, +NMPPPManagerStopHandle *nm_ppp_manager_stop(NMPPPManager *self, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data); diff --git a/src/core/ppp/nm-ppp-manager.c b/src/core/ppp/nm-ppp-manager.c index e6790f22..f1f10305 100644 --- a/src/core/ppp/nm-ppp-manager.c +++ b/src/core/ppp/nm-ppp-manager.c @@ -32,8 +32,7 @@ #include "libnm-platform/nm-platform-utils.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-act-request.h" -#include "nm-ip4-config.h" -#include "nm-ip6-config.h" +#include "nm-l3-config-data.h" #include "nm-dbus-object.h" #include "nm-pppd-plugin.h" @@ -46,6 +45,26 @@ static NM_CACHED_QUARK_FCN("ppp-manager-secret-tries", ppp_manager_secret_tries_ /*****************************************************************************/ +/* FIXME(l3cfg:ppp): I think NMPPPManager's API should be improved to be easier + * usable (by the higher layers). That means to make the class more complex, to + * provide a simpler API. + * + * For example: + * + * - NM_PPP_MANAGER_SIGNAL_STATE_CHANGED just gets re-emitted when we receive + * the D-Bus call from the plugin. The emitted state is like NM_PPP_STATUS_SERIALCONN, + * but none of the users cares about this (what would it mean anyway)? The + * class should itself consume the state, and emit something more consumable + * (like: interface is ready (with ifindex), IPvX configuration done (with l3cd). + * + * - currently signals can be emitted in any order, and it's not clear which + * signals we can expect. For example, when we activate a device, we may want to wait + * for IPv4 and IPv6 configuration, but it's not clear whether this configuration + * is still to be received or whether we can stop waiting. + **/ + +/*****************************************************************************/ + #define NM_TYPE_PPP_MANAGER (nm_ppp_manager_get_type()) #define NM_PPP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_PPP_MANAGER, NMPPPManager)) #define NM_PPP_MANAGER_CLASS(klass) \ @@ -62,8 +81,7 @@ GType nm_ppp_manager_get_type(void); enum { STATE_CHANGED, IFINDEX_SET, - IP4_CONFIG, - IP6_CONFIG, + NEW_CONFIG, STATS, LAST_SIGNAL @@ -80,10 +98,10 @@ typedef struct { char *ip_iface; int ifindex; - NMActRequest * act_req; - GDBusMethodInvocation * pending_secrets_context; + NMActRequest *act_req; + GDBusMethodInvocation *pending_secrets_context; NMActRequestGetSecretsCallId *secrets_id; - const char * secrets_setting_name; + const char *secrets_setting_name; guint ppp_watch_id; guint ppp_timeout_handler; @@ -91,11 +109,6 @@ typedef struct { /* Monitoring */ int monitor_fd; guint monitor_id; - - guint32 ip4_route_table; - guint32 ip4_route_metric; - guint32 ip6_route_table; - guint32 ip6_route_metric; } NMPPPManagerPrivate; struct _NMPPPManager { @@ -121,8 +134,8 @@ G_DEFINE_TYPE(NMPPPManager, nm_ppp_manager, NM_TYPE_DBUS_OBJECT) static void _ppp_cleanup(NMPPPManager *self); -static NMPPPManagerStopHandle *_ppp_manager_stop(NMPPPManager * self, - GCancellable * cancellable, +static NMPPPManagerStopHandle *_ppp_manager_stop(NMPPPManager *self, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data); @@ -131,30 +144,19 @@ static void _ppp_manager_stop_cancel(NMPPPManagerStopHandle *handle); /*****************************************************************************/ static void -_ppp_manager_set_route_parameters(NMPPPManager *self, - guint32 ip4_route_table, - guint32 ip4_route_metric, - guint32 ip6_route_table, - guint32 ip6_route_metric) +_emit_signal_new_config(NMPPPManager *self, + int addr_family, + const NML3ConfigData *l3cd, + const NMUtilsIPv6IfaceId *iid) { - NMPPPManagerPrivate *priv; + nm_assert(NM_IS_PPP_MANAGER(self)); + nm_assert_addr_family(addr_family); + nm_assert(NM_IS_L3_CONFIG_DATA(l3cd)); + nm_assert((!!iid) == (addr_family == AF_INET6)); - g_return_if_fail(NM_IS_PPP_MANAGER(self)); + nm_l3_config_data_seal(l3cd); - priv = NM_PPP_MANAGER_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); - } + g_signal_emit(self, signals[NEW_CONFIG], 0, addr_family, l3cd, iid); } /*****************************************************************************/ @@ -162,9 +164,9 @@ _ppp_manager_set_route_parameters(NMPPPManager *self, static gboolean monitor_cb(gpointer user_data) { - NMPPPManager * self = NM_PPP_MANAGER(user_data); + NMPPPManager *self = NM_PPP_MANAGER(user_data); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - const char * ifname; + const char *ifname; int errsv; ifname = nm_platform_link_get_name(NM_PLATFORM_GET, priv->ifindex); @@ -172,7 +174,7 @@ monitor_cb(gpointer user_data) if (ifname) { struct ppp_stats stats = {}; struct ifreq req = { - .ifr_data = (caddr_t) &stats, + .ifr_data = (caddr_t) &stats, }; nm_utils_ifname_cpy(req.ifr_name, ifname); @@ -230,14 +232,14 @@ cancel_get_secrets(NMPPPManager *self) static gboolean extract_details_from_connection(NMConnection *connection, - const char * secrets_setting_name, - const char ** username, - const char ** password, - GError ** error) + const char *secrets_setting_name, + const char **username, + const char **password, + GError **error) { NMSettingConnection *s_con; - NMSetting * setting; - const char * setting_name; + NMSetting *setting; + const char *setting_name; g_return_val_if_fail(connection != NULL, FALSE); g_return_val_if_fail(username != NULL, FALSE); @@ -290,18 +292,18 @@ extract_details_from_connection(NMConnection *connection, } static void -ppp_secrets_cb(NMActRequest * req, +ppp_secrets_cb(NMActRequest *req, NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection * settings_connection, /* unused (we pass NULL here) */ - GError * error, + NMSettingsConnection *settings_connection, /* unused (we pass NULL here) */ + GError *error, gpointer user_data) { - NMPPPManager * self = NM_PPP_MANAGER(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; + 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); @@ -344,22 +346,22 @@ out: } static void -impl_ppp_manager_need_secrets(NMDBusObject * obj, +impl_ppp_manager_need_secrets(NMDBusObject *obj, const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) { - NMPPPManager * self = NM_PPP_MANAGER(obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - NMConnection * applied_connection; - const char * username = NULL; - const char * password = NULL; - guint32 tries; + NMPPPManager *self = NM_PPP_MANAGER(obj); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); + NMConnection *applied_connection; + const char *username = NULL; + const char *password = NULL; + guint32 tries; gs_unref_ptrarray GPtrArray *hints = NULL; - GError * error = 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)); @@ -410,35 +412,42 @@ impl_ppp_manager_need_secrets(NMDBusObject * obj, } static void -impl_ppp_manager_set_state(NMDBusObject * obj, +impl_ppp_manager_set_state(NMDBusObject *obj, const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) { NMPPPManager *self = NM_PPP_MANAGER(obj); - guint32 state; + guint32 ppp_state; - g_variant_get(parameters, "(u)", &state); - g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) state); + g_variant_get(parameters, "(u)", &ppp_state); + + if (ppp_state >= NM_PPP_STATUS_INTERN_DEAD) { + /* we don't expect an intern state to be reported by the plugin. */ + ppp_state = NM_PPP_STATUS_UNKNOWN; + } + + g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) ppp_state); g_dbus_method_invocation_return_value(invocation, NULL); } static void -impl_ppp_manager_set_ifindex(NMDBusObject * obj, +impl_ppp_manager_set_ifindex(NMDBusObject *obj, const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) { - NMPPPManager * self = NM_PPP_MANAGER(obj); - NMPPPManagerPrivate * priv = NM_PPP_MANAGER_GET_PRIVATE(self); - const NMPlatformLink *plink = NULL; - nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; + NMPPPManager *self = NM_PPP_MANAGER(obj); + gs_unref_object NMPPPManager *self_keep_alive = NULL; + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); + const NMPlatformLink *plink = NULL; + nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; gint32 ifindex; g_variant_get(parameters, "(i)", &ifindex); @@ -456,6 +465,10 @@ impl_ppp_manager_set_ifindex(NMDBusObject * obj, if (ifindex > 0) { plink = nm_platform_link_get(NM_PLATFORM_GET, ifindex); if (!plink) { + /* processing events has side-effects. We need to keep self alive + * during that.*/ + self_keep_alive = g_object_ref(self); + nm_platform_process_events(NM_PLATFORM_GET); plink = nm_platform_link_get(NM_PLATFORM_GET, ifindex); } @@ -481,8 +494,8 @@ static gboolean set_ip_config_common(NMPPPManager *self, GVariant *config_dict, guint32 *out_mtu) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - NMConnection * applied_connection; - NMSettingPpp * s_ppp; + NMConnection *applied_connection; + NMSettingPpp *s_ppp; if (priv->ifindex <= 0) return FALSE; @@ -502,21 +515,21 @@ set_ip_config_common(NMPPPManager *self, GVariant *config_dict, guint32 *out_mtu } static void -impl_ppp_manager_set_ip4_config(NMDBusObject * obj, +impl_ppp_manager_set_ip4_config(NMDBusObject *obj, const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) { - NMPPPManager * self = NM_PPP_MANAGER(obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - gs_unref_object NMIP4Config *config = NULL; - NMPlatformIP4Address address; - guint32 u32, mtu; - GVariantIter * iter; - gs_unref_variant GVariant *config_dict = NULL; + NMPPPManager *self = NM_PPP_MANAGER(obj); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP4Address address; + guint32 u32, mtu; + GVariantIter *iter; + gs_unref_variant GVariant *config_dict = NULL; _LOGI("(IPv4 Config Get) reply received."); @@ -527,37 +540,41 @@ impl_ppp_manager_set_ip4_config(NMDBusObject * obj, if (!set_ip_config_common(self, config_dict, &mtu)) goto out; - config = nm_ip4_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex); + l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), + priv->ifindex, + NM_IP_CONFIG_SOURCE_PPP); - if (mtu) - nm_ip4_config_set_mtu(config, mtu, NM_IP_CONFIG_SOURCE_PPP); + nm_l3_config_data_set_mtu(l3cd, mtu); - memset(&address, 0, sizeof(address)); - address.plen = 32; + address = (NMPlatformIP4Address){ + .plen = 32, + }; if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32)) address.address = u32; + if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32)) + address.plen = u32; + if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) { const NMPlatformIP4Route r = { .ifindex = priv->ifindex, .rt_source = NM_IP_CONFIG_SOURCE_PPP, .gateway = u32, - .table_coerced = nm_platform_route_table_coerce(priv->ip4_route_table), - .metric = priv->ip4_route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; - nm_ip4_config_add_route(config, &r, NULL); + nm_l3_config_data_add_route_4(l3cd, &r); address.peer_address = u32; } else address.peer_address = address.address; - if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32)) - address.plen = u32; - - if (address.address && address.plen && address.plen <= 32) { + if (address.address && address.plen > 0 && address.plen <= 32) { address.addr_source = NM_IP_CONFIG_SOURCE_PPP; - nm_ip4_config_add_address(config, &address); + nm_l3_config_data_add_address_4(l3cd, &address); } else { _LOGE("invalid IPv4 address received!"); goto out; @@ -565,18 +582,17 @@ impl_ppp_manager_set_ip4_config(NMDBusObject * obj, if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_DNS, "au", &iter)) { while (g_variant_iter_next(iter, "u", &u32)) - nm_ip4_config_add_nameserver(config, u32); + nm_l3_config_data_add_nameserver(l3cd, AF_INET, &u32); g_variant_iter_free(iter); } if (g_variant_lookup(config_dict, NM_PPP_IP4_CONFIG_WINS, "au", &iter)) { while (g_variant_iter_next(iter, "u", &u32)) - nm_ip4_config_add_wins(config, u32); + nm_l3_config_data_add_wins(l3cd, u32); g_variant_iter_free(iter); } - /* Push the IP4 config up to the device */ - g_signal_emit(self, signals[IP4_CONFIG], 0, config); + _emit_signal_new_config(self, AF_INET, l3cd, NULL); out: g_dbus_method_invocation_return_value(invocation, NULL); @@ -586,9 +602,9 @@ out: * returns the IID. */ static gboolean -iid_value_to_ll6_addr(GVariant * dict, - const char * prop, - struct in6_addr * out_addr, +iid_value_to_ll6_addr(GVariant *dict, + const char *prop, + struct in6_addr *out_addr, NMUtilsIPv6IfaceId *out_iid) { guint64 iid; @@ -612,22 +628,22 @@ iid_value_to_ll6_addr(GVariant * dict, } static void -impl_ppp_manager_set_ip6_config(NMDBusObject * obj, +impl_ppp_manager_set_ip6_config(NMDBusObject *obj, const NMDBusInterfaceInfoExtended *interface_info, - const NMDBusMethodInfoExtended * method_info, - GDBusConnection * connection, - const char * sender, - GDBusMethodInvocation * invocation, - GVariant * parameters) + const NMDBusMethodInfoExtended *method_info, + GDBusConnection *connection, + const char *sender, + GDBusMethodInvocation *invocation, + GVariant *parameters) { - NMPPPManager * self = NM_PPP_MANAGER(obj); - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - gs_unref_object NMIP6Config *config = NULL; - NMPlatformIP6Address addr; - struct in6_addr a; - NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; - gboolean has_peer = FALSE; - gs_unref_variant GVariant *config_dict = NULL; + NMPPPManager *self = NM_PPP_MANAGER(obj); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP6Address address; + struct in6_addr a; + NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; + gboolean has_peer = FALSE; + gs_unref_variant GVariant *config_dict = NULL; _LOGI("(IPv6 Config Get) reply received."); @@ -638,32 +654,37 @@ impl_ppp_manager_set_ip6_config(NMDBusObject * obj, if (!set_ip_config_common(self, config_dict, NULL)) goto out; - config = nm_ip6_config_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), priv->ifindex); + l3cd = nm_l3_config_data_new(nm_platform_get_multi_idx(NM_PLATFORM_GET), + priv->ifindex, + NM_IP_CONFIG_SOURCE_PPP); - memset(&addr, 0, sizeof(addr)); - addr.plen = 64; + address = (NMPlatformIP6Address){ + .plen = 64, + .addr_source = NM_IP_CONFIG_SOURCE_PPP, + }; if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) { const NMPlatformIP6Route r = { .ifindex = priv->ifindex, .rt_source = NM_IP_CONFIG_SOURCE_PPP, .gateway = a, - .table_coerced = nm_platform_route_table_coerce(priv->ip6_route_table), - .metric = priv->ip6_route_metric, + .table_any = TRUE, + .table_coerced = 0, + .metric_any = TRUE, + .metric = 0, }; - nm_ip6_config_add_route(config, &r, NULL); - addr.peer_address = a; - has_peer = TRUE; + nm_l3_config_data_add_route_6(l3cd, &r); + address.peer_address = a; + has_peer = TRUE; } - if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_OUR_IID, &addr.address, &iid)) { + if (iid_value_to_ll6_addr(config_dict, NM_PPP_IP6_CONFIG_OUR_IID, &address.address, &iid)) { if (!has_peer) - addr.peer_address = addr.address; - nm_ip6_config_add_address(config, &addr); + address.peer_address = address.address; + nm_l3_config_data_add_address_6(l3cd, &address); - /* Push the IPv6 config and interface identifier up to the device */ - g_signal_emit(self, signals[IP6_CONFIG], 0, &iid, config); + _emit_signal_new_config(self, AF_INET6, l3cd, &iid); } else _LOGE("invalid IPv6 address received!"); @@ -703,7 +724,7 @@ static NM_UTILS_LOOKUP_STR_DEFINE( static void ppp_watch_cb(GPid pid, int status, gpointer user_data) { - NMPPPManager * self = NM_PPP_MANAGER(user_data); + NMPPPManager *self = NM_PPP_MANAGER(user_data); NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); int err; const long long lpid = (long long) pid; @@ -726,7 +747,7 @@ ppp_watch_cb(GPid pid, int status, gpointer user_data) priv->pid = 0; priv->ppp_watch_id = 0; _ppp_cleanup(self); - g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD); + g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_INTERN_DEAD); } static gboolean @@ -734,28 +755,34 @@ pppd_timed_out(gpointer data) { NMPPPManager *self = NM_PPP_MANAGER(data); + /* FIXME(l3cfg): we should not use NMPPPManager directly, instead use + * NMPppMgr. That one already schedules a (better) timer. We don't need + * a timeout here anymore. + * + * At this moment, NMPPPManager is still used by NMModem. Once that changes, + * this timer needs to go. */ _LOGW("pppd timed out or didn't initialize our dbus module"); _ppp_manager_stop(self, NULL, NULL, NULL); - g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_DEAD); + g_signal_emit(self, signals[STATE_CHANGED], 0, (guint) NM_PPP_STATUS_INTERN_DEAD); return FALSE; } static GPtrArray * -create_pppd_cmd_line(NMPPPManager * self, - NMSettingPpp * setting, +create_pppd_cmd_line(NMPPPManager *self, + NMSettingPpp *setting, NMSettingPppoe *pppoe, - NMSettingAdsl * adsl, - const char * ppp_name, + NMSettingAdsl *adsl, + const char *ppp_name, guint baud_override, gboolean ip4_enabled, gboolean ip6_enabled, - GError ** err) + GError **err) { - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - const char * pppd_binary = NULL; - gs_unref_ptrarray GPtrArray *cmd = NULL; + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); + const char *pppd_binary = NULL; + gs_unref_ptrarray GPtrArray *cmd = NULL; gboolean ppp_debug; g_return_val_if_fail(setting != NULL, NULL); @@ -961,23 +988,22 @@ pppoe_fill_defaults(NMSettingPpp *setting) static gboolean _ppp_manager_start(NMPPPManager *self, NMActRequest *req, - const char * ppp_name, + const char *ppp_name, guint32 timeout_secs, guint baud_override, - GError ** err) + GError **err) { - NMPPPManagerPrivate *priv; - NMConnection * connection; - NMSettingPpp * s_ppp; + NMPPPManagerPrivate *priv; + NMConnection *connection; + NMSettingPpp *s_ppp; gs_unref_object NMSettingPpp *s_ppp_free = NULL; - NMSettingPppoe * pppoe_setting; - NMSettingAdsl * adsl_setting; - gs_unref_ptrarray GPtrArray *ppp_cmd = NULL; - gs_free char * cmd_str = NULL; - struct stat st; - const char * ip6_method, *ip4_method; - gboolean ip6_enabled = FALSE; - gboolean ip4_enabled = FALSE; + NMSettingPppoe *pppoe_setting; + NMSettingAdsl *adsl_setting; + gs_unref_ptrarray GPtrArray *ppp_cmd = NULL; + gs_free char *cmd_str = NULL; + struct stat st; + gboolean ip6_enabled; + gboolean ip4_enabled; g_return_val_if_fail(NM_IS_PPP_MANAGER(self), FALSE); g_return_val_if_fail(NM_IS_ACT_REQUEST(req), FALSE); @@ -1022,11 +1048,7 @@ _ppp_manager_start(NMPPPManager *self, adsl_setting = (NMSettingAdsl *) nm_connection_get_setting(connection, NM_TYPE_SETTING_ADSL); - /* Figure out what address methods should be enabled */ - ip4_method = nm_utils_get_ip_config_method(connection, AF_INET); - ip4_enabled = nm_streq(ip4_method, NM_SETTING_IP4_CONFIG_METHOD_AUTO); - ip6_method = nm_utils_get_ip_config_method(connection, AF_INET6); - ip6_enabled = nm_streq(ip6_method, NM_SETTING_IP6_CONFIG_METHOD_AUTO); + nm_utils_ppp_ip_methods_enabled(connection, &ip4_enabled, &ip6_enabled); ppp_cmd = create_pppd_cmd_line(self, s_ppp, @@ -1059,9 +1081,10 @@ _ppp_manager_start(NMPPPManager *self, _LOGI("pppd started with pid %lld", (long long) priv->pid); - priv->ppp_watch_id = g_child_watch_add(priv->pid, (GChildWatchFunc) ppp_watch_cb, self); - priv->ppp_timeout_handler = g_timeout_add_seconds(timeout_secs, pppd_timed_out, self); - priv->act_req = g_object_ref(req); + priv->ppp_watch_id = g_child_watch_add(priv->pid, (GChildWatchFunc) ppp_watch_cb, self); + if (timeout_secs > 0) + priv->ppp_timeout_handler = g_timeout_add_seconds(timeout_secs, pppd_timed_out, self); + priv->act_req = g_object_ref(req); return TRUE; fail: @@ -1096,7 +1119,7 @@ _ppp_cleanup(NMPPPManager *self) /*****************************************************************************/ struct _NMPPPManagerStopHandle { - NMPPPManager * self; + NMPPPManager *self; NMPPPManagerStopCallback callback; gpointer user_data; @@ -1170,13 +1193,13 @@ _stop_cancelled_cb(GCancellable *cancellable, gpointer user_data) } static NMPPPManagerStopHandle * -_ppp_manager_stop(NMPPPManager * self, - GCancellable * cancellable, +_ppp_manager_stop(NMPPPManager *self, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data) { - NMPPPManagerPrivate * priv = NM_PPP_MANAGER_GET_PRIVATE(self); - NMDBusObject * dbus = NM_DBUS_OBJECT(self); + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); + NMDBusObject *dbus = NM_DBUS_OBJECT(self); NMPPPManagerStopHandle *handle; if (nm_dbus_object_is_exported(dbus)) @@ -1290,12 +1313,8 @@ nm_ppp_manager_init(NMPPPManager *self) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); - priv->ifindex = -1; - priv->monitor_fd = -1; - priv->ip4_route_table = RT_TABLE_MAIN; - priv->ip4_route_metric = 460; - priv->ip6_route_table = RT_TABLE_MAIN; - priv->ip6_route_metric = 460; + priv->ifindex = -1; + priv->monitor_fd = -1; } static NMPPPManager * @@ -1309,7 +1328,7 @@ _ppp_manager_new(const char *iface) static void dispose(GObject *object) { - NMPPPManager * self = (NMPPPManager *) object; + NMPPPManager *self = (NMPPPManager *) object; NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE(self); /* we expect the user to first stop the manager. As fallback, @@ -1371,7 +1390,7 @@ static const NMDBusInterfaceInfoExtended interface_info_ppp = { static void nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) { - GObjectClass * object_class = G_OBJECT_CLASS(manager_class); + GObjectClass *object_class = G_OBJECT_CLASS(manager_class); NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(manager_class); object_class->dispose = dispose; @@ -1400,7 +1419,7 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) NULL, G_TYPE_NONE, 1, - G_TYPE_UINT); + G_TYPE_UINT /* ppp_state */); signals[IFINDEX_SET] = g_signal_new(NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, G_OBJECT_CLASS_TYPE(object_class), @@ -1411,21 +1430,10 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) NULL, G_TYPE_NONE, 2, - G_TYPE_INT, - G_TYPE_STRING); - - signals[IP4_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_IP4_CONFIG, - G_OBJECT_CLASS_TYPE(object_class), - G_SIGNAL_RUN_FIRST, - 0, - NULL, - NULL, - NULL, - G_TYPE_NONE, - 1, - G_TYPE_OBJECT); + G_TYPE_INT /* ifindex */, + G_TYPE_STRING /* ifname */); - signals[IP6_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_IP6_CONFIG, + signals[NEW_CONFIG] = g_signal_new(NM_PPP_MANAGER_SIGNAL_NEW_CONFIG, G_OBJECT_CLASS_TYPE(object_class), G_SIGNAL_RUN_FIRST, 0, @@ -1433,9 +1441,10 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) NULL, NULL, G_TYPE_NONE, - 2, - G_TYPE_POINTER, - G_TYPE_OBJECT); + 3, + G_TYPE_INT, /* addr_family */ + G_TYPE_POINTER, /* (const NML3ConfigData *) */ + G_TYPE_POINTER); /* (const NMUtilsIPv6IfaceId *) */ signals[STATS] = g_signal_new(NM_PPP_MANAGER_SIGNAL_STATS, G_OBJECT_CLASS_TYPE(object_class), @@ -1451,9 +1460,8 @@ nm_ppp_manager_class_init(NMPPPManagerClass *manager_class) } const NMPPPOps ppp_ops = { - .create = _ppp_manager_new, - .set_route_parameters = _ppp_manager_set_route_parameters, - .start = _ppp_manager_start, - .stop = _ppp_manager_stop, - .stop_cancel = _ppp_manager_stop_cancel, + .create = _ppp_manager_new, + .start = _ppp_manager_start, + .stop = _ppp_manager_stop, + .stop_cancel = _ppp_manager_stop_cancel, }; diff --git a/src/core/ppp/nm-ppp-manager.h b/src/core/ppp/nm-ppp-manager.h index c41dda20..21ea3715 100644 --- a/src/core/ppp/nm-ppp-manager.h +++ b/src/core/ppp/nm-ppp-manager.h @@ -11,15 +11,14 @@ #define NM_PPP_MANAGER_SIGNAL_STATE_CHANGED "state-changed" #define NM_PPP_MANAGER_SIGNAL_IFINDEX_SET "ifindex-set" -#define NM_PPP_MANAGER_SIGNAL_IP4_CONFIG "ip4-config" -#define NM_PPP_MANAGER_SIGNAL_IP6_CONFIG "ip6-config" +#define NM_PPP_MANAGER_SIGNAL_NEW_CONFIG "new-config" #define NM_PPP_MANAGER_SIGNAL_STATS "stats" typedef struct _NMPPPManager NMPPPManager; typedef struct _NMPPPManagerStopHandle NMPPPManagerStopHandle; -typedef void (*NMPPPManagerStopCallback)(NMPPPManager * manager, +typedef void (*NMPPPManagerStopCallback)(NMPPPManager *manager, NMPPPManagerStopHandle *handle, gboolean was_cancelled, gpointer user_data); diff --git a/src/core/ppp/nm-ppp-mgr.c b/src/core/ppp/nm-ppp-mgr.c new file mode 100644 index 00000000..31c173a3 --- /dev/null +++ b/src/core/ppp/nm-ppp-mgr.c @@ -0,0 +1,620 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "src/core/nm-default-daemon.h" + +#include "nm-ppp-mgr.h" + +#include <net/if.h> + +#include "NetworkManagerUtils.h" +#include "devices/nm-device-utils.h" +#include "nm-act-request.h" +#include "nm-netns.h" +#include "nm-ppp-manager-call.h" +#include "nm-ppp-status.h" + +/*****************************************************************************/ + +struct _NMPppMgr { + NMPppMgrConfig config; + NMPPPManager *ppp_manager; + GSource *idle_start; + GSource *connect_timeout_source; + union { + struct { + NMPppMgrIPData ip_data_6; + NMPppMgrIPData ip_data_4; + }; + NMPppMgrIPData ip_data_x[2]; + }; + int ifindex; + NMPppMgrStatsData stats_data; + NMPppMgrState state; + NMUtilsIPv6IfaceId ipv6_iid; + bool ppp_started : 1; +}; + +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_PPP +#define _NMLOG_PREFIX_NAME "ppp-mgr" +#define _NMLOG(level, ...) \ + __NMLOG_DEFAULT_WITH_ADDR(level, _NMLOG_DOMAIN, _NMLOG_PREFIX_NAME, __VA_ARGS__) + +/*****************************************************************************/ + +NM_UTILS_LOOKUP_STR_DEFINE( + nm_ppp_mgr_state_to_string, + NMPppMgrState, + NM_UTILS_LOOKUP_DEFAULT_WARN("???"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_STARTING, "starting"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX, "waiting-for-ifindex"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_HAVE_IFINDEX, "have-ifindex"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_HAVE_IP_CONFIG, "have-ip-config"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_FAILED_TO_START, "failed-to-start"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_FAILED_TO_IFINDEX, "failed-to-ifindex"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_STATE_FAILED, "failed")); + +NM_UTILS_LOOKUP_STR_DEFINE(nm_ppp_mgr_callback_type_to_string, + NMPppMgrCallbackType, + NM_UTILS_LOOKUP_DEFAULT_WARN("???"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + "state-changed"), + NM_UTILS_LOOKUP_STR_ITEM(NM_PPP_MGR_CALLBACK_TYPE_STATS_CHANGED, + "stats-changed")); + +/*****************************************************************************/ + +#define SELF_TO_USERDATA(self) (&(self)->idle_start) + +#define SELF_FROM_USERDATA(user_data) \ + ((NMPppMgr *) (((const char *) (user_data)) - G_STRUCT_OFFSET(NMPppMgr, idle_start))) + +/*****************************************************************************/ + +gboolean +_nm_assert_is_ppp_mgr(const NMPppMgr *self) +{ + nm_assert(G_IS_OBJECT(self->ppp_manager)); + nm_assert(NM_IS_NETNS(self->config.netns)); + nm_assert(self->config.parent_iface); + + return TRUE; +} + +/*****************************************************************************/ + +static void +_callback_emit_with_data(NMPppMgr *self, const NMPppMgrCallbackData *callback_data) +{ + char sbuf_int[30]; + + switch (callback_data->callback_type) { + case NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED: + _LOGT("emit signal: %s, state=%s%s%s%s%s, reason=%s", + nm_ppp_mgr_callback_type_to_string(callback_data->callback_type), + nm_ppp_mgr_state_to_string(callback_data->data.state), + NM_PRINT_FMT_QUOTED2(callback_data->data.state != callback_data->data.old_state, + ", old-state=", + nm_ppp_mgr_state_to_string(callback_data->data.old_state), + ""), + NM_PRINT_FMT_QUOTED2(callback_data->data.ifindex > 0, + ", ifindex=", + nm_sprintf_buf(sbuf_int, "%d", callback_data->data.ifindex), + ""), + callback_data->data.reason_msg); + break; + case NM_PPP_MGR_CALLBACK_TYPE_STATS_CHANGED: + /* This signal might be emitted every 5 seconds. It's too verbose for logging. + * Be silent. */ + break; + default: + nm_assert_not_reached(); + } + + self->config.callback(self, callback_data, self->config.user_data); +} + +static void +_callback_emit_state_change(NMPppMgr *self, + NMPppMgrCallbackType callback_type, + NMPppMgrState old_state, + gboolean ip_changed_4, + gboolean ip_changed_6, + NMDeviceStateReason reason, + const char *reason_msg) +{ + const NMPppMgrCallbackData callback_data = { + .callback_type = callback_type, + .data = + { + .old_state = old_state, + .state = self->state, + .ifindex = self->ifindex, + .reason = reason, + .reason_msg = reason_msg, + .ip_data_4 = &self->ip_data_4, + .ip_data_6 = &self->ip_data_6, + .stats_data = &self->stats_data, + .ip_changed_4 = ip_changed_4, + .ip_changed_6 = ip_changed_6, + }, + }; + + _callback_emit_with_data(self, &callback_data); +} + +/*****************************************************************************/ + +NMPppMgrState +nm_ppp_mgr_get_state(const NMPppMgr *self) +{ + g_return_val_if_fail(NM_IS_PPP_MGR(self), NM_PPP_MGR_STATE_FAILED); + + return self->state; +} + +int +nm_ppp_mgr_get_ifindex(const NMPppMgr *self) +{ + g_return_val_if_fail(NM_IS_PPP_MGR(self), 0); + + return self->ifindex; +} + +const NMPppMgrIPData * +nm_ppp_mgr_get_ip_data(const NMPppMgr *self, int addr_family) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + + g_return_val_if_fail(NM_IS_PPP_MGR(self), NULL); + + return &self->ip_data_x[IS_IPv4]; +} + +const NMPppMgrStatsData * +nm_ppp_mgr_get_stats(const NMPppMgr *self) +{ + g_return_val_if_fail(NM_IS_PPP_MGR(self), NULL); + + return &self->stats_data; +} + +/*****************************************************************************/ + +static void +_set_state(NMPppMgr *self, NMPppMgrState state, NMPppMgrState *out_old_state) +{ + if (state >= NM_PPP_MGR_STATE_HAVE_IP_CONFIG) + nm_clear_g_source_inst(&self->connect_timeout_source); + + NM_SET_OUT(out_old_state, self->state); + if (self->state != state) { + _LOGT("set state: %s (was %s)", + nm_ppp_mgr_state_to_string(state), + nm_ppp_mgr_state_to_string(self->state)); + self->state = state; + } +} + +static void +_set_state_failed(NMPppMgr *self, NMPppMgrState state, NMPppMgrState *out_old_state) +{ + nm_assert(state >= _NM_PPP_MGR_STATE_FAILED_START); + nm_assert(self->state < _NM_PPP_MGR_STATE_FAILED_START); + + _set_state(self, state, out_old_state); + + self->ifindex = 0; + nm_clear_l3cd(&self->ip_data_4.l3cd); + nm_clear_l3cd(&self->ip_data_6.l3cd); + self->ip_data_4 = (NMPppMgrIPData){ + .ip_received = FALSE, + .ip_enabled = FALSE, + }; + self->ip_data_6 = (NMPppMgrIPData){ + .ip_received = FALSE, + .ip_enabled = FALSE, + }; + + if (self->ppp_manager) { + g_signal_handlers_disconnect_by_data(self->ppp_manager, SELF_TO_USERDATA(self)); + if (self->ppp_started) { + self->ppp_started = FALSE; + nm_ppp_manager_stop(self->ppp_manager, NULL, NULL, NULL); + } + g_object_unref(self->ppp_manager); + } +} + +static gboolean +_state_ready_for_have_ifindex(NMPppMgr *self) +{ + if (self->ip_data_4.ip_received) { + /* once we receive an IPv4 config, we consider this as ready. + * + * The problem is that we don't know when we can expect an IPv6 config + * too, so we cannot just keep waiting. I don't know how to solve this, but + * it means IPv4+IPv6 together doesn't work well (because we would not + * wait for IPv6, once IPv4 config is received. */ + return TRUE; + } + + return ((!self->ip_data_4.ip_enabled || self->ip_data_4.ip_received) + && (!self->ip_data_6.ip_enabled || self->ip_data_6.ip_received)); +} + +/*****************************************************************************/ + +static void +_ppp_signal_state_changed(NMPPPManager *ppp_manager, guint ppp_state_u, gpointer user_data) +{ + NMPppMgr *self = SELF_FROM_USERDATA(user_data); + NMPPPStatus ppp_state = ppp_state_u; + NMPppMgrState state; + NMPppMgrState old_state; + NMDeviceStateReason reason; + const char *reason_msg; + + if ((guint) ppp_state != ppp_state_u) + ppp_state = NM_PPP_STATUS_UNKNOWN; + + switch (ppp_state) { + case NM_PPP_STATUS_DISCONNECT: + state = NM_PPP_MGR_STATE_FAILED; + reason = NM_DEVICE_STATE_REASON_PPP_DISCONNECT; + reason_msg = "ppp signals disconnect"; + break; + case NM_PPP_STATUS_DEAD: + case NM_PPP_STATUS_INTERN_DEAD: + state = NM_PPP_MGR_STATE_FAILED; + reason = NM_DEVICE_STATE_REASON_PPP_FAILED; + reason_msg = "ppp signals disconnect"; + break; + default: + _LOGT("ppp signal about state changed: #%u signal (ignored)", ppp_state_u); + return; + } + + _LOGT("ppp signal about state changed: #%u signal, new-state %s, state-reason=%s, %s", + ppp_state_u, + nm_ppp_mgr_state_to_string(state), + nm_device_state_reason_to_string(reason), + reason_msg); + + _set_state_failed(self, state, &old_state); + _callback_emit_state_change(self, + NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + old_state, + FALSE, + FALSE, + reason, + reason_msg); +} + +static void +_ppp_signal_ifindex_set(NMPPPManager *ppp_manager, + int ifindex, + const char *ifname, + gpointer user_data) +{ + NMPppMgr *self = SELF_FROM_USERDATA(user_data); + NMPppMgrState old_state; + NMPppMgrState new_state; + gboolean ip_changed_4; + gboolean ip_changed_6; + + if (ifindex <= 0) { + nm_assert(self->state == NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX); + _LOGT("ifindex set: invalid ifindex received"); + _set_state_failed(self, NM_PPP_MGR_STATE_FAILED_TO_IFINDEX, &old_state); + _callback_emit_state_change(self, + NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + old_state, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_PPP_FAILED, + "invalid ifindex provided by ppp plugin"); + return; + } + + if (self->ifindex > 0) { + nm_assert(self->state > NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX); + nm_assert(self->state < _NM_PPP_MGR_STATE_FAILED_START); + + _LOGT("ifindex set: ignore ifindex %d, already set to %d", ifindex, self->ifindex); + return; + } + + nm_assert(self->state == NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX); + self->ifindex = ifindex; + + if (_state_ready_for_have_ifindex(self)) { + new_state = NM_PPP_MGR_STATE_HAVE_IP_CONFIG; + ip_changed_4 = self->ip_data_4.ip_received; + ip_changed_6 = self->ip_data_6.ip_received; + } else { + new_state = NM_PPP_MGR_STATE_HAVE_IFINDEX; + ip_changed_4 = FALSE; + ip_changed_6 = FALSE; + } + + _LOGT("ifindex set: ifindex %d", ifindex); + + _set_state(self, new_state, &old_state); + _callback_emit_state_change(self, + NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + old_state, + ip_changed_4, + ip_changed_6, + NM_DEVICE_STATE_REASON_PPP_FAILED, + "invalid ifindex provided by ppp plugin"); +} + +static void +_ppp_signal_new_config(NMPPPManager *ppp_manager, + int addr_family, + const NML3ConfigData *l3cd, + const NMUtilsIPv6IfaceId *iid, + gpointer user_data) +{ + NMPppMgr *self = SELF_FROM_USERDATA(user_data); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMPppMgrState old_state; + gboolean ip_changed_4; + gboolean ip_changed_6; + + nm_assert(self->state >= NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX); + nm_assert(self->state < _NM_PPP_MGR_STATE_FAILED_START); + + if (nm_l3_config_data_equal(self->ip_data_x[IS_IPv4].l3cd, l3cd)) + l3cd = self->ip_data_x[IS_IPv4].l3cd; + + nm_l3_config_data_reset(&self->ip_data_x[IS_IPv4].l3cd, l3cd); + if (!IS_IPv4) { + if (iid) + self->ipv6_iid = *iid; + else + self->ipv6_iid = (NMUtilsIPv6IfaceId) NM_UTILS_IPV6_IFACE_ID_INIT; + self->ip_data_6.ipv6_iid = + nm_utils_memeqzero(&self->ipv6_iid, sizeof(self->ipv6_iid)) ? NULL : &self->ipv6_iid; + } + self->ip_data_x[IS_IPv4].ip_received = TRUE; + + if (self->state == NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX) { + /* we still wait for the ifindex. We just cache the IP configuration, + * but leave the state unchanged. */ + _LOGT("ip-config v%c received (still waiting for ifindex)", + nm_utils_addr_family_to_char(addr_family)); + old_state = NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX; + } else { + NMPppMgrState new_state; + + _LOGT("ip-config v%c received", nm_utils_addr_family_to_char(addr_family)); + new_state = _state_ready_for_have_ifindex(self) ? NM_PPP_MGR_STATE_HAVE_IP_CONFIG + : NM_PPP_MGR_STATE_HAVE_IFINDEX; + nm_assert((self->state == NM_PPP_MGR_STATE_HAVE_IFINDEX) + || (self->state == NM_PPP_MGR_STATE_HAVE_IP_CONFIG + && new_state == NM_PPP_MGR_STATE_HAVE_IP_CONFIG)); + _set_state(self, new_state, &old_state); + } + + ip_changed_4 = IS_IPv4; + ip_changed_6 = !IS_IPv4; + + _callback_emit_state_change(self, + NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + old_state, + ip_changed_4, + ip_changed_6, + NM_DEVICE_STATE_REASON_NONE, + "ip config received"); +} + +static void +_ppp_signal_stats(NMPPPManager *ppp_manager, guint in_bytes, guint out_bytes, gpointer user_data) +{ + NMPppMgr *self = SELF_FROM_USERDATA(user_data); + + if (self->stats_data.in_bytes == in_bytes && self->stats_data.out_bytes == out_bytes) + return; + + self->stats_data.in_bytes = in_bytes; + self->stats_data.out_bytes = out_bytes; + + _callback_emit_state_change(self, + NM_PPP_MGR_CALLBACK_TYPE_STATS_CHANGED, + self->state, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_NONE, + "stats update"); +} + +/*****************************************************************************/ + +static gboolean +_ifindex_timeout_cb(gpointer user_data) +{ + NMPppMgr *self = user_data; + NMPppMgrState old_state; + + nm_clear_g_source_inst(&self->connect_timeout_source); + + _set_state_failed(self, NM_PPP_MGR_STATE_FAILED_TO_IFINDEX, &old_state); + _callback_emit_state_change(self, + NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + old_state, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_PPP_FAILED, + "timeout connecting"); + return G_SOURCE_CONTINUE; +} + +/*****************************************************************************/ + +static gboolean +_idle_start_cb(gpointer user_data) +{ + NMPppMgr *self = user_data; + gs_free_error GError *error = NULL; + NMPppMgrState old_state; + gboolean ip4_enabled; + gboolean ip6_enabled; + NMPlatform *platform; + const NMPlatformLink *plink; + + nm_clear_g_source_inst(&self->idle_start); + + /* We only evaluate ipx_enabled here. That is because nm_ppp_manager_start() + * will evaluate it based on act_req's applied connection (like we do now), + * but as the applied connection can be reapplied, let's do it at the + * same time to be sure we agree. + * + * This should be nicer solved by NMPPPManager not accessing the NMConnection + * or make little/no use of NMActRequest. */ + nm_utils_ppp_ip_methods_enabled(nm_act_request_get_applied_connection(self->config.act_req), + &ip4_enabled, + &ip6_enabled); + self->ip_data_4.ip_enabled = !!ip4_enabled; + self->ip_data_6.ip_enabled = !!ip6_enabled; + + g_signal_connect(self->ppp_manager, + NM_PPP_MANAGER_SIGNAL_STATE_CHANGED, + G_CALLBACK(_ppp_signal_state_changed), + SELF_TO_USERDATA(self)); + g_signal_connect(self->ppp_manager, + NM_PPP_MANAGER_SIGNAL_IFINDEX_SET, + G_CALLBACK(_ppp_signal_ifindex_set), + SELF_TO_USERDATA(self)); + g_signal_connect(self->ppp_manager, + NM_PPP_MANAGER_SIGNAL_NEW_CONFIG, + G_CALLBACK(_ppp_signal_new_config), + SELF_TO_USERDATA(self)); + g_signal_connect(self->ppp_manager, + NM_PPP_MANAGER_SIGNAL_STATS, + G_CALLBACK(_ppp_signal_stats), + SELF_TO_USERDATA(self)); + + platform = nm_netns_get_platform(self->config.netns); + plink = nm_platform_link_get_by_ifname(platform, self->config.parent_iface); + if (plink && !NM_FLAGS_HAS(plink->n_ifi_flags, IFF_UP)) { + nm_platform_link_change_flags(platform, plink->ifindex, IFF_UP, TRUE); + } + + self->ppp_started = TRUE; + if (!nm_ppp_manager_start(self->ppp_manager, + self->config.act_req, + self->config.ppp_username, + 0, + self->config.baud_override, + &error)) { + gs_free char *reason_msg = NULL; + + _set_state_failed(self, NM_PPP_MGR_STATE_FAILED_TO_START, &old_state); + reason_msg = g_strdup_printf("failed to start: %s", error->message); + _callback_emit_state_change(self, + NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + old_state, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_PPP_START_FAILED, + reason_msg); + return G_SOURCE_CONTINUE; + } + + nm_assert(self->state == NM_PPP_MGR_STATE_STARTING); + _set_state(self, NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX, &old_state); + + self->connect_timeout_source = + nm_g_timeout_add_seconds_source(self->config.timeout_secs, _ifindex_timeout_cb, self); + + _callback_emit_state_change(self, + NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + old_state, + FALSE, + FALSE, + NM_DEVICE_STATE_REASON_NONE, + "pppd is starting"); + + return G_SOURCE_CONTINUE; +} + +/*****************************************************************************/ + +NMPppMgr * +nm_ppp_mgr_start(const NMPppMgrConfig *config, GError **error) +{ + NMPppMgr *self; + NMPPPManager *ppp_manager; + + g_return_val_if_fail(config, NULL); + g_return_val_if_fail(NM_IS_NETNS(config->netns), NULL); + g_return_val_if_fail(config->parent_iface, NULL); + g_return_val_if_fail(NM_IS_ACT_REQUEST(config->act_req), NULL); + g_return_val_if_fail(config->callback, NULL); + g_return_val_if_fail(!error || !*error, NULL); + + ppp_manager = nm_ppp_manager_create(config->parent_iface, error); + + if (!ppp_manager) + return NULL; + + self = g_slice_new(NMPppMgr); + + *self = (NMPppMgr){ + .config = *config, + .ppp_manager = ppp_manager, + .idle_start = nm_g_idle_add_source(_idle_start_cb, self), + .state = NM_PPP_MGR_STATE_STARTING, + .ip_data_4 = + { + .ip_received = FALSE, + .ip_enabled = NM_OPTION_BOOL_DEFAULT, + }, + .ip_data_6 = + { + .ip_received = FALSE, + .ip_enabled = NM_OPTION_BOOL_DEFAULT, + }, + .stats_data = + { + .in_bytes = 0, + .out_bytes = 0, + }, + }; + + g_object_ref(self->config.act_req); + g_object_ref(self->config.netns); + self->config.parent_iface = g_strdup(self->config.parent_iface); + self->config.ppp_username = g_strdup(self->config.ppp_username); + + _LOGD("created"); + + return self; +} + +void +nm_ppp_mgr_destroy(NMPppMgr *self) +{ + if (!self) + return; + + _LOGD("destroying"); + + if (self->state < _NM_PPP_MGR_STATE_FAILED_START) + _set_state_failed(self, NM_PPP_MGR_STATE_FAILED, NULL); + + nm_clear_g_source_inst(&self->idle_start); + nm_clear_g_source_inst(&self->connect_timeout_source); + + g_object_unref(self->config.act_req); + + g_free((char *) self->config.parent_iface); + g_free((char *) self->config.ppp_username); + + g_object_unref(self->config.netns); + + nm_g_slice_free(self); +} diff --git a/src/core/ppp/nm-ppp-mgr.h b/src/core/ppp/nm-ppp-mgr.h new file mode 100644 index 00000000..f6165411 --- /dev/null +++ b/src/core/ppp/nm-ppp-mgr.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef __NM_PPP_MGR_H__ +#define __NM_PPP_MGR_H__ + +#include "nm-l3cfg.h" + +typedef struct _NMPppMgr NMPppMgr; + +typedef enum _nm_packed { + /* NMPppMgr is starting. It will call nm_ppp_manager_start() on an idle + * handler. */ + NM_PPP_MGR_STATE_STARTING, + + /* NMPppMgr called nm_ppp_manager_start() and is now waiting to get + * an ifindex. At this time, we theoretically might already get IP configuration + * but that is cached and meaningless until we have the ifindex. */ + NM_PPP_MGR_STATE_WAITING_FOR_IFINDEX, + + /* NMPppMgr received an ifindex from NMPPPManager. But no IP configuration + * is yet received. */ + NM_PPP_MGR_STATE_HAVE_IFINDEX, + + /* NMPppMgr received an ifindex and IP configuration from NMPPPManager. + * Whether we have IPv4 and/or IPv6 is unspecified. + * + * If we have only either IPv4 or IPv6, then it's also unclear unknown + * whether the other address family will still arrive or not. */ + NM_PPP_MGR_STATE_HAVE_IP_CONFIG, + + /* Meta enum value which is the first failed state. All states larger than + * this are final (dead) states. */ + _NM_PPP_MGR_STATE_FAILED_START, + + /* NMPPPManager failed to start. This is a final (dead) state. */ + NM_PPP_MGR_STATE_FAILED_TO_START = _NM_PPP_MGR_STATE_FAILED_START, + + /* NMPppMgr started, but it failed to get the ifindex (possibly after timeout). + * This is a final (dead) state. */ + NM_PPP_MGR_STATE_FAILED_TO_IFINDEX, + + /* An unspecified failed state. This is a final (dead) state. */ + NM_PPP_MGR_STATE_FAILED, +} NMPppMgrState; + +const char *nm_ppp_mgr_state_to_string(NMPppMgrState state); + +typedef enum { + NM_PPP_MGR_CALLBACK_TYPE_STATE_CHANGED, + NM_PPP_MGR_CALLBACK_TYPE_STATS_CHANGED, +} NMPppMgrCallbackType; + +const char *nm_ppp_mgr_callback_type_to_string(NMPppMgrCallbackType callback_type); + +typedef struct { + guint32 in_bytes; + guint32 out_bytes; +} NMPppMgrStatsData; + +typedef struct { + const NML3ConfigData *l3cd; + const NMUtilsIPv6IfaceId *ipv6_iid; + NMOptionBool ip_enabled; + bool ip_received; +} NMPppMgrIPData; + +typedef struct { + NMPppMgrCallbackType callback_type; + union { + struct { + const char *reason_msg; + union { + struct { + const NMPppMgrIPData *ip_data_6; + const NMPppMgrIPData *ip_data_4; + }; + const NMPppMgrIPData *ip_data_x[2]; + }; + const NMPppMgrStatsData *stats_data; + int ifindex; + NMDeviceStateReason reason; + NMPppMgrState old_state; + NMPppMgrState state; + union { + struct { + bool ip_changed_6; + bool ip_changed_4; + }; + bool ip_changed_x[2]; + }; + } data; + }; +} NMPppMgrCallbackData; + +typedef void (*NMPppMgrCallback)(NMPppMgr *self, + const NMPppMgrCallbackData *callback_data, + gpointer user_data); + +typedef struct { + NMNetns *netns; + const char *parent_iface; + + NMPppMgrCallback callback; + gpointer user_data; + + NMActRequest *act_req; + const char *ppp_username; + guint32 timeout_secs; + guint baud_override; +} NMPppMgrConfig; + +gboolean _nm_assert_is_ppp_mgr(const NMPppMgr *self); + +#define NM_IS_PPP_MGR(self) \ + ({ \ + const NMPppMgr *_self = (self); \ + \ + nm_assert(_nm_assert_is_ppp_mgr(_self)); \ + !!_self; \ + }) + +NMPppMgr *nm_ppp_mgr_start(const NMPppMgrConfig *config, GError **error); + +NMPppMgrState nm_ppp_mgr_get_state(const NMPppMgr *self); +int nm_ppp_mgr_get_ifindex(const NMPppMgr *self); +const NMPppMgrIPData *nm_ppp_mgr_get_ip_data(const NMPppMgr *self, int addr_family); +const NMPppMgrStatsData *nm_ppp_mgr_get_stats(const NMPppMgr *self); + +void nm_ppp_mgr_destroy(NMPppMgr *self); + +#endif /* __NM_PPP_MGR_H__ */ diff --git a/src/core/ppp/nm-ppp-plugin-api.h b/src/core/ppp/nm-ppp-plugin-api.h index 647e1c24..de4cfae3 100644 --- a/src/core/ppp/nm-ppp-plugin-api.h +++ b/src/core/ppp/nm-ppp-plugin-api.h @@ -11,21 +11,15 @@ typedef const struct { NMPPPManager *(*create)(const char *iface); - void (*set_route_parameters)(NMPPPManager *manager, - guint32 route_table_v4, - guint32 route_metric_v4, - guint32 route_table_v6, - guint32 route_metric_v6); - gboolean (*start)(NMPPPManager *manager, NMActRequest *req, - const char * ppp_name, + const char *ppp_name, guint32 timeout_secs, guint baud_override, - GError ** err); + GError **err); - NMPPPManagerStopHandle *(*stop)(NMPPPManager * manager, - GCancellable * cancellable, + NMPPPManagerStopHandle *(*stop)(NMPPPManager *manager, + GCancellable *cancellable, NMPPPManagerStopCallback callback, gpointer user_data); diff --git a/src/core/ppp/nm-ppp-status.h b/src/core/ppp/nm-ppp-status.h index c346b119..df0ac10b 100644 --- a/src/core/ppp/nm-ppp-status.h +++ b/src/core/ppp/nm-ppp-status.h @@ -22,7 +22,10 @@ typedef enum { NM_PPP_STATUS_TERMINATE, NM_PPP_STATUS_DISCONNECT, NM_PPP_STATUS_HOLDOFF, - NM_PPP_STATUS_MASTER + NM_PPP_STATUS_MASTER, + + /* these states are internal and not announced by the pppd plugin. */ + NM_PPP_STATUS_INTERN_DEAD, } NMPPPStatus; #endif /* __NM_PPP_STATUS_H__ */ diff --git a/src/core/ppp/nm-pppd-plugin.c b/src/core/ppp/nm-pppd-plugin.c index 5ffa7d17..e2e34d2a 100644 --- a/src/core/ppp/nm-pppd-plugin.c +++ b/src/core/ppp/nm-pppd-plugin.c @@ -33,14 +33,14 @@ char pppd_version[] = VERSION; static struct { GDBusConnection *dbus_connection; - char * ipparam; + char *ipparam; } gl; static void nm_phasechange(int arg) { NMPPPStatus ppp_status = NM_PPP_STATUS_UNKNOWN; - char * ppp_phase; + char *ppp_phase; g_return_if_fail(G_IS_DBUS_CONNECTION(gl.dbus_connection)); @@ -332,10 +332,10 @@ get_pap_check(void) static int get_credentials(char *username, char *password) { - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - const char * my_username; - const char * my_password; + gs_unref_variant GVariant *ret = NULL; + gs_free_error GError *error = NULL; + const char *my_username; + const char *my_password; if (!password) { /* pppd is checking pap support; return 1 for supported */ |