summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-06-12 09:59:38 -0500
committerDan Williams <dcbw@redhat.com>2014-07-23 14:26:39 -0500
commit75fa46bd19dd63f78bf0990e69219e416e6354ea (patch)
tree683ab077b8fe20cd05a73c9cd2bbc355697ad518
parentaf1f183b3d1a38548be96cf41e835847e89b953b (diff)
downloadNetworkManager-75fa46bd19dd63f78bf0990e69219e416e6354ea.tar.gz
ppp: add IPv6 support
Add support for IPv6 to the pppd plugin and return the interface identifiers to NetworkManager. Use those to construct the IPv6LL addresses for the PPP interface and the peer.
-rw-r--r--introspection/nm-ppp-manager.xml5
-rw-r--r--src/ppp-manager/Makefile.am4
-rw-r--r--src/ppp-manager/nm-ppp-manager.c154
-rw-r--r--src/ppp-manager/nm-ppp-manager.h6
-rw-r--r--src/ppp-manager/nm-pppd-plugin.c74
-rw-r--r--src/ppp-manager/nm-pppd-plugin.h19
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))
+