diff options
-rw-r--r-- | introspection/nm-ppp-manager.xml | 5 | ||||
-rw-r--r-- | src/ppp-manager/Makefile.am | 4 | ||||
-rw-r--r-- | src/ppp-manager/nm-ppp-manager.c | 154 | ||||
-rw-r--r-- | src/ppp-manager/nm-ppp-manager.h | 6 | ||||
-rw-r--r-- | src/ppp-manager/nm-pppd-plugin.c | 74 | ||||
-rw-r--r-- | src/ppp-manager/nm-pppd-plugin.h | 19 |
6 files changed, 226 insertions, 36 deletions
diff --git a/introspection/nm-ppp-manager.xml b/introspection/nm-ppp-manager.xml index 9e2dfdb1c3..2867daf979 100644 --- a/introspection/nm-ppp-manager.xml +++ b/introspection/nm-ppp-manager.xml @@ -14,6 +14,11 @@ <arg name="config" type="a{sv}" direction="in"/> </method> + <method name="SetIp6Config"> + <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_ppp_manager_set_ip6_config"/> + <arg name="config" type="a{sv}" direction="in"/> + </method> + <method name="SetState"> <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_ppp_manager_set_state"/> <arg name="state" type="u" direction="in"/> diff --git a/src/ppp-manager/Makefile.am b/src/ppp-manager/Makefile.am index 2d740f14a3..ba8c2d7be5 100644 --- a/src/ppp-manager/Makefile.am +++ b/src/ppp-manager/Makefile.am @@ -20,8 +20,8 @@ nm_pppd_plugin_la_SOURCES = \ nm_pppd_plugin_la_LDFLAGS = -module -avoid-version nm_pppd_plugin_la_LIBADD = \ - $(top_builddir)/libnm-util/libnm-util.la \ $(DBUS_LIBS) \ - $(GLIB_LIBS) + $(GLIB_LIBS) \ + -ldl endif diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c index 7a837fbce4..9e7669d85c 100644 --- a/src/ppp-manager/nm-ppp-manager.c +++ b/src/ppp-manager/nm-ppp-manager.c @@ -67,6 +67,10 @@ static gboolean impl_ppp_manager_set_ip4_config (NMPPPManager *manager, GHashTable *config, GError **err); +static gboolean impl_ppp_manager_set_ip6_config (NMPPPManager *manager, + GHashTable *config, + GError **err); + #include "nm-ppp-manager-glue.h" static void _ppp_cleanup (NMPPPManager *manager); @@ -101,6 +105,7 @@ G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, G_TYPE_OBJECT) enum { STATE_CHANGED, IP4_CONFIG, + IP6_CONFIG, STATS, LAST_SIGNAL @@ -132,6 +137,7 @@ nm_ppp_manager_error_quark (void) static void nm_ppp_manager_init (NMPPPManager *manager) { + NM_PPP_MANAGER_GET_PRIVATE (manager)->monitor_fd = -1; } static void @@ -245,6 +251,14 @@ nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) G_TYPE_STRING, G_TYPE_OBJECT); + signals[IP6_CONFIG] = + g_signal_new ("ip6-config", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMPPPManagerClass, ip6_config), + NULL, NULL, NULL, + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_OBJECT); + signals[STATS] = g_signal_new ("stats", G_OBJECT_CLASS_TYPE (object_class), @@ -300,8 +314,12 @@ monitor_stats (NMPPPManager *manager) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + /* already monitoring */ + if (priv->monitor_fd >= 0) + return; + priv->monitor_fd = socket (AF_INET, SOCK_DGRAM, 0); - if (priv->monitor_fd > 0) { + if (priv->monitor_fd >= 0) { g_warn_if_fail (priv->monitor_id == 0); if (priv->monitor_id) g_source_remove (priv->monitor_id); @@ -499,19 +517,51 @@ static gboolean impl_ppp_manager_set_state (NMPPPManager *manager, } static gboolean +set_ip_config_common (NMPPPManager *self, + GHashTable *hash, + const char *iface_prop, + guint32 *out_mtu) +{ + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); + NMConnection *connection; + NMSettingPPP *s_ppp; + GValue *val; + + val = g_hash_table_lookup (hash, iface_prop); + if (!val || !G_VALUE_HOLDS_STRING (val)) { + nm_log_err (LOGD_PPP, "no interface received!"); + return FALSE; + } + if (priv->ip_iface == NULL) + priv->ip_iface = g_value_dup_string (val); + + /* Got successful IP config; obviously the secrets worked */ + connection = nm_act_request_get_connection (priv->act_req); + g_assert (connection); + g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, NULL); + + /* Get any custom MTU */ + s_ppp = nm_connection_get_setting_ppp (connection); + if (s_ppp && out_mtu) + *out_mtu = nm_setting_ppp_get_mtu (s_ppp); + + monitor_stats (self); + return TRUE; +} + +static gboolean impl_ppp_manager_set_ip4_config (NMPPPManager *manager, GHashTable *config_hash, GError **err) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - NMConnection *connection; - NMSettingPPP *s_ppp; NMIP4Config *config; NMPlatformIP4Address address; GValue *val; int i; + guint32 mtu = 0; - nm_log_info (LOGD_PPP, "PPP manager(IP Config Get) reply received."); + nm_log_info (LOGD_PPP, "PPP manager (IPv4 Config Get) reply received."); remove_timeout_handler (manager); @@ -557,35 +607,89 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager, nm_ip4_config_add_wins (config, g_array_index (wins, guint, i)); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_INTERFACE); - if (!val || !G_VALUE_HOLDS_STRING (val)) { - nm_log_err (LOGD_PPP, "no interface received!"); + if (!set_ip_config_common (manager, config_hash, NM_PPP_IP4_CONFIG_INTERFACE, &mtu)) goto out; + + if (mtu) + nm_ip4_config_set_mtu (config, mtu); + + /* Push the IP4 config up to the device */ + g_signal_emit (manager, signals[IP4_CONFIG], 0, priv->ip_iface, config); + +out: + g_object_unref (config); + return TRUE; +} + +/* Converts the named Interface Identifier item to an IPv6 LL address and + * returns the IID. + */ +static gboolean +iid_value_to_ll6_addr (GHashTable *hash, + const char *prop, + struct in6_addr *out_addr, + NMUtilsIPv6IfaceId *out_iid) +{ + GValue *val; + guint64 iid; + + val = g_hash_table_lookup (hash, prop); + if (!val || !G_VALUE_HOLDS (val, G_TYPE_UINT64)) { + nm_log_dbg (LOGD_PPP, "pppd plugin property '%s' missing or not a uint64", prop); + return FALSE; } - priv->ip_iface = g_value_dup_string (val); - /* Got successful IP4 config; obviously the secrets worked */ - connection = nm_act_request_get_connection (priv->act_req); - g_assert (connection); - g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, NULL); + iid = g_value_get_uint64 (val); + g_return_val_if_fail (iid != 0, FALSE); - /* Merge in custom MTU */ - s_ppp = nm_connection_get_setting_ppp (connection); - if (s_ppp) { - guint32 mtu = nm_setting_ppp_get_mtu (s_ppp); + /* Construct an IPv6 LL address from the interface identifier. See + * http://tools.ietf.org/html/rfc4291#section-2.5.1 (IPv6) and + * http://tools.ietf.org/html/rfc5072#section-4.1 (IPv6 over PPP). + */ + memset (out_addr->s6_addr, 0, sizeof (out_addr->s6_addr)); + out_addr->s6_addr16[0] = htons (0xfe80); + memcpy (out_addr->s6_addr + 8, &iid, sizeof (iid)); + if (out_iid) + nm_utils_ipv6_interface_identfier_get_from_addr (out_iid, out_addr); + return TRUE; +} + +static gboolean +impl_ppp_manager_set_ip6_config (NMPPPManager *manager, + GHashTable *hash, + GError **err) +{ + NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); + NMIP6Config *config; + NMPlatformIP6Address addr; + struct in6_addr a; + NMUtilsIPv6IfaceId iid = NM_UTILS_IPV6_IFACE_ID_INIT; + + nm_log_info (LOGD_PPP, "PPP manager (IPv6 Config Get) reply received."); + + remove_timeout_handler (manager); + + config = nm_ip6_config_new (); + + memset (&addr, 0, sizeof (addr)); + addr.plen = 64; - if (mtu) - nm_ip4_config_set_mtu (config, mtu); + if (iid_value_to_ll6_addr (hash, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) { + nm_ip6_config_set_gateway (config, &a); + addr.peer_address = a; } - /* Push the IP4 config up to the device */ - g_signal_emit (manager, signals[IP4_CONFIG], 0, priv->ip_iface, config); + if (iid_value_to_ll6_addr (hash, NM_PPP_IP6_CONFIG_OUR_IID, &addr.address, &iid)) { + nm_ip6_config_add_address (config, &addr); - monitor_stats (manager); + if (set_ip_config_common (manager, hash, NM_PPP_IP6_CONFIG_INTERFACE, NULL)) { + /* Push the IPv6 config and interface identifier up to the device */ + g_signal_emit (manager, signals[IP6_CONFIG], 0, priv->ip_iface, &iid, config); + } + } else + nm_log_err (LOGD_PPP, "invalid IPv6 address received!"); - out: g_object_unref (config); - return TRUE; } @@ -1127,11 +1231,11 @@ _ppp_cleanup (NMPPPManager *manager) priv->monitor_id = 0; } - if (priv->monitor_fd) { + if (priv->monitor_fd >= 0) { /* Get the stats one last time */ monitor_cb (manager); close (priv->monitor_fd); - priv->monitor_fd = 0; + priv->monitor_fd = -1; } if (priv->ppp_timeout_handler) { diff --git a/src/ppp-manager/nm-ppp-manager.h b/src/ppp-manager/nm-ppp-manager.h index 1b4bc1886d..7b0125b413 100644 --- a/src/ppp-manager/nm-ppp-manager.h +++ b/src/ppp-manager/nm-ppp-manager.h @@ -29,7 +29,9 @@ #include "nm-activation-request.h" #include "nm-connection.h" #include "nm-ip4-config.h" +#include "nm-ip6-config.h" #include "nm-pppd-plugin.h" +#include "NetworkManagerUtils.h" #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)) @@ -50,6 +52,10 @@ typedef struct { /* Signals */ void (*state_changed) (NMPPPManager *manager, NMPPPStatus status); void (*ip4_config) (NMPPPManager *manager, const char *iface, NMIP4Config *config); + void (*ip6_config) (NMPPPManager *manager, + const char *iface, + const NMUtilsIPv6IfaceId *iid, + NMIP6Config *config); void (*stats) (NMPPPManager *manager, guint32 in_bytes, guint32 out_bytes); } NMPPPManagerClass; diff --git a/src/ppp-manager/nm-pppd-plugin.c b/src/ppp-manager/nm-pppd-plugin.c index e6ee86f7a4..0cea4e1d10 100644 --- a/src/ppp-manager/nm-pppd-plugin.c +++ b/src/ppp-manager/nm-pppd-plugin.c @@ -19,6 +19,7 @@ * Copyright (C) 2008 Red Hat, Inc. */ +#include <config.h> #include <string.h> #include <pppd/pppd.h> #include <pppd/fsm.h> @@ -26,10 +27,15 @@ #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> +#include <dlfcn.h> #include <glib.h> #include <glib-object.h> #include <dbus/dbus-glib.h> +#define INET6 +#include <pppd/eui64.h> +#include <pppd/ipv6cp.h> + #include "NetworkManager.h" #include "nm-pppd-plugin.h" #include "nm-ppp-status.h" @@ -128,7 +134,6 @@ str_to_gvalue (const char *str) val = g_slice_new0 (GValue); g_value_init (val, G_TYPE_STRING); g_value_set_string (val, str); - return val; } @@ -140,7 +145,6 @@ uint_to_gvalue (guint32 i) val = g_slice_new0 (GValue); g_value_init (val, G_TYPE_UINT); g_value_set_uint (val, i); - return val; } @@ -230,7 +234,7 @@ nm_ip_up (void *data, int arg) g_hash_table_insert (hash, NM_PPP_IP4_CONFIG_WINS, val); } - g_message ("nm-ppp-plugin: (%s): sending Ip4Config to NetworkManager...", __func__); + g_message ("nm-ppp-plugin: (%s): sending IPv4 config to NetworkManager...", __func__); dbus_g_proxy_call_no_reply (proxy, "SetIp4Config", DBUS_TYPE_G_MAP_OF_VARIANT, hash, G_TYPE_INVALID, @@ -239,6 +243,48 @@ nm_ip_up (void *data, int arg) g_hash_table_destroy (hash); } +static GValue * +eui64_to_gvalue (eui64_t eui) +{ + GValue *val; + guint64 iid; + + G_STATIC_ASSERT (sizeof (iid) == sizeof (eui)); + + val = g_slice_new0 (GValue); + g_value_init (val, G_TYPE_UINT64); + memcpy (&iid, &eui, sizeof (eui)); + g_value_set_uint64 (val, iid); + return val; +} + +static void +nm_ip6_up (void *data, int arg) +{ + ipv6cp_options *ho = &ipv6cp_hisoptions[0]; + ipv6cp_options *go = &ipv6cp_gotoptions[0]; + GHashTable *hash; + + g_return_if_fail (DBUS_IS_G_PROXY (proxy)); + + g_message ("nm-ppp-plugin: (%s): ip6-up event", __func__); + + hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, value_destroy); + g_hash_table_insert (hash, NM_PPP_IP6_CONFIG_INTERFACE, str_to_gvalue (ifname)); + g_hash_table_insert (hash, NM_PPP_IP6_CONFIG_OUR_IID, eui64_to_gvalue (go->ourid)); + g_hash_table_insert (hash, NM_PPP_IP6_CONFIG_PEER_IID, eui64_to_gvalue (ho->hisid)); + + /* DNS is done via DHCPv6 or router advertisements */ + + g_message ("nm-ppp-plugin: (%s): sending IPv6 config to NetworkManager...", __func__); + + dbus_g_proxy_call_no_reply (proxy, "SetIp6Config", + DBUS_TYPE_G_MAP_OF_VARIANT, hash, G_TYPE_INVALID, + G_TYPE_INVALID); + + g_hash_table_destroy (hash); +} + static int get_chap_check (void) { @@ -319,6 +365,27 @@ nm_exit_notify (void *data, int arg) proxy = NULL; } +static void +add_ip6_notifier (void) +{ + static struct notifier **notifier = NULL; + static gsize load_once = 0; + + if (g_once_init_enter (&load_once)) { + void *handle = dlopen(NULL, RTLD_NOW | RTLD_GLOBAL); + + if (handle) { + notifier = dlsym (handle, "ipv6_up_notifier"); + dlclose (handle); + } + g_once_init_leave (&load_once, 1); + } + if (notifier) + add_notifier (notifier, nm_ip6_up, NULL); + else + g_message ("nm-ppp-plugin: no IPV6CP notifier support; IPv6 not available"); +} + int plugin_init (void) { @@ -356,6 +423,7 @@ plugin_init (void) add_notifier (&phasechange, nm_phasechange, NULL); add_notifier (&ip_up_notifier, nm_ip_up, NULL); add_notifier (&exitnotify, nm_exit_notify, proxy); + add_ip6_notifier (); return 0; } diff --git a/src/ppp-manager/nm-pppd-plugin.h b/src/ppp-manager/nm-pppd-plugin.h index 95a2a18291..2c3073e4ee 100644 --- a/src/ppp-manager/nm-pppd-plugin.h +++ b/src/ppp-manager/nm-pppd-plugin.h @@ -16,14 +16,21 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. + * Copyright (C) 2008 - 2014 Red Hat, Inc. */ #define NM_DBUS_INTERFACE_PPP "org.freedesktop.NetworkManager.PPP" #define NM_PPP_IP4_CONFIG_INTERFACE "interface" -#define NM_PPP_IP4_CONFIG_ADDRESS "address" -#define NM_PPP_IP4_CONFIG_PREFIX "prefix" -#define NM_PPP_IP4_CONFIG_GATEWAY "gateway" -#define NM_PPP_IP4_CONFIG_DNS "dns" -#define NM_PPP_IP4_CONFIG_WINS "wins" +#define NM_PPP_IP4_CONFIG_ADDRESS "address" +#define NM_PPP_IP4_CONFIG_PREFIX "prefix" +#define NM_PPP_IP4_CONFIG_GATEWAY "gateway" +#define NM_PPP_IP4_CONFIG_DNS "dns" +#define NM_PPP_IP4_CONFIG_WINS "wins" + +#define NM_PPP_IP6_CONFIG_INTERFACE "interface" +#define NM_PPP_IP6_CONFIG_OUR_IID "our-iid" +#define NM_PPP_IP6_CONFIG_PEER_IID "peer-iid" + +#define DBUS_TYPE_EUI64 (dbus_g_type_get_collection ("GByteArray", G_TYPE_UINT8)) + |