2007-08-15 Tambet Ingo <tambet@gmail.com>

* src/ppp-manager: Implement ppp-manager. It's sort of dead code
        * for now since
        nothing is using it at the moment, but it'll be all useful and
stuff later on.

        * libnm-util/nm-setting.h: Define NMSettingPPP.

        * libnm-util/nm-setting.c: Implement NMSettingPPP.

        * libnm-util/nm-connection.c (register_default_creators):
        * Register ppp setting.

        * src/Makefile.am: Add ppp-manager to SUBDIRS.

        * configure.in: Require ppp headers. Build Makefile for
        * ppp-manager.



git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@2695 4912f4e0-d625-0410-9fb7-b9a5a253dbdc
This commit is contained in:
Tambet Ingo
2007-08-15 14:30:06 +00:00
parent 43da26b1fd
commit b1e15de652
14 changed files with 1240 additions and 1 deletions

View File

@@ -1,5 +1,18 @@
2007-08-15 Tambet Ingo <tambet@gmail.com>
* src/ppp-manager: Implement ppp-manager. It's sort of dead code for now since
nothing is using it at the moment, but it'll be all useful and stuff later on.
* libnm-util/nm-setting.h: Define NMSettingPPP.
* libnm-util/nm-setting.c: Implement NMSettingPPP.
* libnm-util/nm-connection.c (register_default_creators): Register ppp setting.
* src/Makefile.am: Add ppp-manager to SUBDIRS.
* configure.in: Require ppp headers. Build Makefile for ppp-manager.
* introspection/Makefile.am: Add nm-manager-client.xml to EXTRA_DIST.
2007-08-14 Tambet Ingo <tambet@gmail.com>

View File

@@ -215,6 +215,11 @@ fi
AC_DEFINE_UNQUOTED(IP_BINARY_PATH, "$IP_BINARY_PATH", [Define to path of ip binary])
AC_SUBST(IP_BINARY_PATH)
# PPPD
AC_CHECK_HEADERS(pppd/pppd.h,,
AC_MSG_ERROR(couldn't find pppd.h. pppd-devel package is required.))
AC_ARG_ENABLE(more-warnings,
AC_HELP_STRING([--enable-more-warnings], [Maximum compiler warnings]),
set_more_warnings="$enableval",[
@@ -259,6 +264,7 @@ src/named-manager/Makefile
src/vpn-manager/Makefile
src/dhcp-manager/Makefile
src/supplicant-manager/Makefile
src/ppp-manager/Makefile
src/backends/Makefile
libnm-util/libnm-util.pc
libnm-util/Makefile

View File

@@ -17,6 +17,7 @@ register_default_creators (void)
{ "802-11-wireless", nm_setting_wireless_new_from_hash },
{ "ipv4", nm_setting_ip4_config_new_from_hash },
{ "802-11-wireless-security", nm_setting_wireless_security_new_from_hash },
{ "ppp", nm_setting_ppp_new_from_hash },
{ NULL, NULL}
};

View File

@@ -1,3 +1,5 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#include <glib-object.h>
#include <dbus/dbus-glib.h>
#include <string.h>
@@ -1147,3 +1149,149 @@ nm_setting_wireless_security_new_from_hash (GHashTable *settings)
return setting;
}
/* PPP */
static gboolean
setting_ppp_verify (NMSetting *setting, GHashTable *all_settings)
{
/* FIXME: Do we even want this or can we just let pppd evaluate the options? */
return TRUE;
}
static GHashTable *
setting_ppp_hash (NMSetting *setting)
{
NMSettingPPP *self = (NMSettingPPP *) setting;
GHashTable *hash;
hash = setting_hash_new ();
g_hash_table_insert (hash, "noauth", boolean_to_gvalue (self->noauth));
g_hash_table_insert (hash, "refuse-eap", boolean_to_gvalue (self->refuse_eap));
g_hash_table_insert (hash, "refuse-chap", boolean_to_gvalue (self->refuse_chap));
g_hash_table_insert (hash, "refuse-mschap", boolean_to_gvalue (self->refuse_mschap));
g_hash_table_insert (hash, "nobsdcomp", boolean_to_gvalue (self->nobsdcomp));
g_hash_table_insert (hash, "nodeflate", boolean_to_gvalue (self->nodeflate));
g_hash_table_insert (hash, "require-mppe", boolean_to_gvalue (self->require_mppe));
g_hash_table_insert (hash, "require-mppe-128", boolean_to_gvalue (self->require_mppe_128));
g_hash_table_insert (hash, "mppe-stateful", boolean_to_gvalue (self->mppe_stateful));
g_hash_table_insert (hash, "require-mppc", boolean_to_gvalue (self->require_mppc));
g_hash_table_insert (hash, "crtscts", boolean_to_gvalue (self->crtscts));
g_hash_table_insert (hash, "usepeerdns", boolean_to_gvalue (self->usepeerdns));
g_hash_table_insert (hash, "baud", int_to_gvalue (self->baud));
g_hash_table_insert (hash, "mru", int_to_gvalue (self->mru));
g_hash_table_insert (hash, "mtu", int_to_gvalue (self->mtu));
g_hash_table_insert (hash, "lcp-echo-failure", int_to_gvalue (self->lcp_echo_failure));
g_hash_table_insert (hash, "lcp-echo-interval", int_to_gvalue (self->lcp_echo_interval));
return hash;
}
static void
setting_ppp_destroy (NMSetting *setting)
{
NMSettingPPP *self = (NMSettingPPP *) setting;
g_slice_free (NMSettingPPP, self);
}
NMSetting *
nm_setting_ppp_new (void)
{
NMSetting *setting;
setting = (NMSetting *) g_slice_new0 (NMSettingPPP);
setting->name = g_strdup ("ppp");
setting->verify_fn = setting_ppp_verify;
setting->hash_fn = setting_ppp_hash;
setting->destroy_fn = setting_ppp_destroy;
return setting;
}
NMSetting *
nm_setting_ppp_new_from_hash (GHashTable *settings)
{
NMSettingPPP *self;
NMSetting *setting;
GValue *value;
g_return_val_if_fail (settings != NULL, NULL);
setting = nm_setting_ppp_new ();
self = (NMSettingPPP *) setting;
value = (GValue *) g_hash_table_lookup (settings, "noauth");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->noauth = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "refuse-eap");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->refuse_eap = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "refuse-chap");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->refuse_chap = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "refuse-mschap");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->refuse_mschap = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "nobsdcomp");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->nobsdcomp = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "nodeflate");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->nodeflate = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "require-mppe");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->require_mppe = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "require-mppe-128");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->require_mppe_128 = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "mppe-stateful");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->mppe_stateful = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "require-mppc");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->require_mppc = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "crtscts");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->crtscts = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "usepeerdns");
if (value && G_VALUE_HOLDS_BOOLEAN (value))
self->usepeerdns = g_value_get_boolean (value);
value = (GValue *) g_hash_table_lookup (settings, "baud");
if (value && G_VALUE_HOLDS_INT (value))
self->baud = g_value_get_int (value);
value = (GValue *) g_hash_table_lookup (settings, "mru");
if (value && G_VALUE_HOLDS_INT (value))
self->mru = g_value_get_int (value);
value = (GValue *) g_hash_table_lookup (settings, "mtu");
if (value && G_VALUE_HOLDS_INT (value))
self->mtu = g_value_get_int (value);
value = (GValue *) g_hash_table_lookup (settings, "lcp-echo-failure");
if (value && G_VALUE_HOLDS_INT (value))
self->lcp_echo_failure = g_value_get_int (value);
value = (GValue *) g_hash_table_lookup (settings, "lcp-echo-interval");
if (value && G_VALUE_HOLDS_INT (value))
self->lcp_echo_interval = g_value_get_int (value);
return setting;
}

View File

@@ -1,3 +1,5 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#ifndef NM_SETTING_H
#define NM_SETTING_H
@@ -136,6 +138,34 @@ typedef struct {
NMSetting *nm_setting_wireless_security_new (void);
NMSetting *nm_setting_wireless_security_new_from_hash (GHashTable *settings);
/* PPP */
typedef struct {
NMSetting parent;
gboolean noauth;
gboolean refuse_eap;
gboolean refuse_chap;
gboolean refuse_mschap;
gboolean nobsdcomp;
gboolean nodeflate;
gboolean require_mppe;
gboolean require_mppe_128;
gboolean mppe_stateful;
gboolean require_mppc;
gboolean crtscts;
gboolean usepeerdns;
gint32 baud;
gint32 mru;
gint32 mtu;
gint32 lcp_echo_failure;
gint32 lcp_echo_interval;
} NMSettingPPP;
NMSetting *nm_setting_ppp_new (void);
NMSetting *nm_setting_ppp_new_from_hash (GHashTable *settings);
G_END_DECLS
#endif /* NM_SETTING_H */

View File

@@ -1,4 +1,4 @@
SUBDIRS=named-manager vpn-manager dhcp-manager supplicant-manager backends
SUBDIRS=named-manager vpn-manager dhcp-manager supplicant-manager ppp-manager backends
INCLUDES = -I${top_srcdir} \
-I${top_srcdir}/include \

View File

@@ -0,0 +1,62 @@
INCLUDES = -I${top_srcdir} \
-I${top_srcdir}/include \
-I${top_srcdir}/utils \
-I${top_srcdir}/libnm-util \
-I${top_srcdir}/src
noinst_LTLIBRARIES = libppp-manager.la
BUILT_SOURCES = \
nm-ppp-marshal.h \
nm-ppp-marshal.c
libppp_manager_la_SOURCES = \
nm-ppp-manager.c \
nm-ppp-manager.h \
nm-ppp-status.h \
nm-ppp-marshal-main.c
libppp_manager_la_CPPFLAGS = \
$(DBUS_CFLAGS) \
$(HAL_CFLAGS) \
-DG_DISABLE_DEPRECATED \
-DSYSCONFDIR=\"$(sysconfdir)\" \
-DLIBDIR=\"$(libdir)\"
libppp_manager_la_LIBADD = $(DBUS_LIBS) $(GLIB_LIBS)
nm_pppd_plugindir = $(libdir)
nm_pppd_plugin_PROGRAMS = nm-pppd-plugin.so
nm_pppd_plugin_so_SOURCES = \
nm-pppd-plugin.c \
nm-pppd-plugin.h \
nm-ppp-status.h
nm_pppd_plugin_so_CPPFLAGS = $(DBUS_CFLAGS) $(GLIB_CFLAGS)
nm_pppd_plugin_so_LDFLAGS = -shared
nm_pppd_plugin_so_LDADD = \
$(DBUS_LIBS) \
$(GLIB_LIBS) \
$(top_builddir)/libnm-util/libnm-util.la
EXTRA_DIST = nm-ppp-marshal.list
CLEANFILES = $(BUILT_SOURCES)
nm-ppp-marshal.h: nm-ppp-marshal.list
$(GLIB_GENMARSHAL) --prefix=nm_ppp_marshal $(srcdir)/nm-ppp-marshal.list --header > \
xgen-gmh \
&& (cmp -s xgen-gmh nm-ppp-marshal.h || cp xgen-gmh nm-ppp-marshal.h) \
&& rm -f xgen-gmh xgen-gmh~
nm-ppp-marshal.c: nm-ppp-marshal.list
$(GLIB_GENMARSHAL) --prefix=nm_ppp_marshal $(srcdir)/nm-ppp-marshal.list --body > \
xgen-gmc \
&& cp xgen-gmc nm-ppp-marshal.c \
&& rm -f xgen-gmc xgen-gmc~
nm-ppp-marshal-main.c: nm-ppp-marshal.c nm-ppp-marshal.h

View File

@@ -0,0 +1,597 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include "nm-ppp-manager.h"
#include "nm-dbus-manager.h"
#include "nm-utils.h"
#include "dbus-dict-helpers.h"
#include "nm-ppp-marshal.h"
#define NM_PPPD_PLUGIN LIBDIR "/nm-pppd-plugin.so"
#define NM_PPP_WAIT_PPPD 10000 /* 10 seconds */
typedef struct {
GPid pid;
NMDBusManager *dbus_manager;
guint32 signal_handler;
guint32 ppp_timeout_handler;
guint32 name_owner_changed_handler;
} NMPPPManagerPrivate;
#define NM_PPP_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PPP_MANAGER, NMPPPManagerPrivate))
G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, G_TYPE_OBJECT)
enum {
STATE_CHANGED,
IP4_CONFIG,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
GQuark
nm_ppp_manager_error_quark (void)
{
static GQuark quark;
if (!quark)
quark = g_quark_from_static_string ("nm_ppp_manager_error");
return quark;
}
static void
nm_ppp_manager_init (NMPPPManager *manager)
{
}
static void
finalize (GObject *object)
{
nm_ppp_manager_stop (NM_PPP_MANAGER (object));
G_OBJECT_CLASS (nm_ppp_manager_parent_class)->finalize (object);
}
static void
nm_ppp_manager_class_init (NMPPPManagerClass *manager_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
g_type_class_add_private (manager_class, sizeof (NMPPPManagerPrivate));
object_class->finalize = finalize;
/* signals */
signals[STATE_CHANGED] =
g_signal_new ("state-changed",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMPPPManagerClass, state_changed),
NULL, NULL,
g_cclosure_marshal_VOID__UINT,
G_TYPE_NONE, 1,
G_TYPE_UINT);
signals[IP4_CONFIG] =
g_signal_new ("ip4-config",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMPPPManagerClass, ip4_config),
NULL, NULL,
nm_ppp_marshal_VOID__STRING_OBJECT,
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_OBJECT);
}
NMPPPManager *
nm_ppp_manager_new (void)
{
return (NMPPPManager *) g_object_new (NM_TYPE_PPP_MANAGER, NULL);
}
/*******************************************/
typedef struct {
GPtrArray *array;
GStringChunk *chunk;
} NMCmdLine;
static NMCmdLine *
nm_cmd_line_new (void)
{
NMCmdLine *cmd;
cmd = g_slice_new (NMCmdLine);
cmd->array = g_ptr_array_new ();
cmd->chunk = g_string_chunk_new (1024);
return cmd;
}
static void
nm_cmd_line_destroy (NMCmdLine *cmd)
{
g_ptr_array_free (cmd->array, TRUE);
g_string_chunk_free (cmd->chunk);
g_slice_free (NMCmdLine, cmd);
}
static char *
nm_cmd_line_to_str (NMCmdLine *cmd)
{
char *str;
g_ptr_array_add (cmd->array, NULL);
str = g_strjoinv (" ", (gchar **) cmd->array->pdata);
g_ptr_array_remove_index (cmd->array, cmd->array->len - 1);
return str;
}
static void
nm_cmd_line_add_string (NMCmdLine *cmd, const char *str)
{
g_ptr_array_add (cmd->array, g_string_chunk_insert (cmd->chunk, str));
}
static void
nm_cmd_line_add_int (NMCmdLine *cmd, int i)
{
char *str;
str = g_strdup_printf ("%d", i);
nm_cmd_line_add_string (cmd, str);
g_free (str);
}
/*******************************************/
static inline const char *nm_find_pppd (void)
{
static const char *pppd_binary_paths[] =
{
"/usr/local/sbin/pppd",
"/usr/sbin/pppd",
"/sbin/pppd",
NULL
};
const char **pppd_binary = pppd_binary_paths;
while (*pppd_binary != NULL) {
if (g_file_test (*pppd_binary, G_FILE_TEST_EXISTS))
break;
pppd_binary++;
}
return *pppd_binary;
}
static void
ppp_exit_code (guint pppd_exit_status)
{
const char *msg;
switch (pppd_exit_status) {
case 1:
msg = "Fatal pppd error";
break;
case 2:
msg = "pppd options error";
break;
case 3:
msg = "No root priv error";
break;
case 4:
msg = "No ppp module error";
break;
case 5:
msg = "pppd received a signal";
break;
case 6:
msg = "Serial port lock failed";
break;
case 7:
msg = "Serial port open failed";
break;
case 8:
msg = "Connect script failed";
break;
case 9:
msg = "Pty program error";
break;
case 10:
msg = "PPP negotiation failed";
break;
case 11:
msg = "Peer didn't authenticatie itself";
break;
case 12:
msg = "Link idle: Idle Seconds reached.";
break;
case 13:
msg = "Connect time limit reached.";
break;
case 14:
msg = "Callback negotiated, call should come back.";
break;
case 15:
msg = "Lack of LCP echo responses";
break;
case 16:
msg = "A modem hung up the phone";
break;
case 17:
msg = "Loopback detected";
break;
case 18:
msg = "The init script failed";
break;
case 19:
msg = "Authentication error.\n"
"We failed to authenticate ourselves to the peer.\n"
"Maybe bad account or password?";
break;
default:
msg = "Unknown error";
}
g_warning ("pppd exited with error: %s", msg);
}
static void
ppp_watch_cb (GPid pid, gint status, gpointer user_data)
{
NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (user_data);
guint err;
if (WIFEXITED (status)) {
err = WEXITSTATUS (status);
if (err != 0)
ppp_exit_code (err);
} else if (WIFSTOPPED (status))
g_warning ("ppp stopped unexpectedly with signal %d", WSTOPSIG (status));
else if (WIFSIGNALED (status))
g_warning ("ppp died with signal %d", WTERMSIG (status));
else
g_warning ("ppp died from an unknown cause");
/* Reap child if needed. */
waitpid (pid, NULL, WNOHANG);
priv->pid = 0;
}
#define HANDLE_DICT_ITEM(in_key, in_type, in_ary_type, op) \
if (!strcmp (entry.key, in_key)) { \
if (entry.type != in_type) { \
nm_warning (in_key "had invalid type in PPP IP Config message."); \
} else { \
if (in_type == DBUS_TYPE_ARRAY && entry.array_type != in_ary_type) { \
nm_warning (in_key "had invalid type in PPP IP Config message."); \
} else { \
op \
} \
} \
goto next; \
}
static gboolean
parse_ip4_config (DBusMessage *message, char **interface, NMIP4Config **config)
{
DBusMessageIter iter;
DBusMessageIter iter_dict;
NMUDictEntry entry;
gboolean success = FALSE;
dbus_message_iter_init (message, &iter);
if (!nmu_dbus_dict_open_read (&iter, &iter_dict)) {
nm_warning ("Warning: couldn't get config dictionary from PPP IP Config message.");
goto out;
}
*config = nm_ip4_config_new ();
while (nmu_dbus_dict_has_dict_entry (&iter_dict)) {
int i;
if (!nmu_dbus_dict_get_entry (&iter_dict, &entry)) {
nm_warning ("Error: couldn't read dict entryfrom PPP IP Config message.");
goto out;
}
HANDLE_DICT_ITEM("interface", DBUS_TYPE_STRING, 0,
{ if (strlen (entry.str_value)) *interface = g_strdup (entry.str_value); });
/* IP specific options */
HANDLE_DICT_ITEM("address", DBUS_TYPE_UINT32, 0,
{ nm_ip4_config_set_address (*config, entry.uint32_value); });
HANDLE_DICT_ITEM("netmask", DBUS_TYPE_UINT32, 0,
{ nm_ip4_config_set_netmask (*config, entry.uint32_value ? entry.uint32_value : 0x00FF); });
HANDLE_DICT_ITEM("gateway", DBUS_TYPE_UINT32, 0,
{ nm_ip4_config_set_gateway (*config, entry.uint32_value); });
/* Multiple DNS servers are allowed */
HANDLE_DICT_ITEM("dns_server", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
{
for (i = 0; i < entry.array_len; i++)
nm_ip4_config_add_nameserver (*config, entry.uint32array_value[i]);
});
/* FIXME: Ignoring WINS servers for now since IP4Config doesn't have a place for it */
next:
nmu_dbus_dict_entry_clear (&entry);
}
success = TRUE;
out:
if (!success && *config) {
g_object_unref (*config);
*config = NULL;
g_free (*interface);
*interface = NULL;
}
return success;
}
static gboolean
nm_ppp_manager_dbus_signal_handler (DBusConnection *connection,
DBusMessage *message,
gpointer user_data)
{
NMPPPManager *manager = NM_PPP_MANAGER (user_data);
gboolean handled = FALSE;
if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_PPP, "Status")) {
guint32 state;
if (dbus_message_get_args (message, NULL,
DBUS_TYPE_UINT32, &state,
DBUS_TYPE_INVALID)) {
g_signal_emit (manager, signals[STATE_CHANGED], 0, state);
handled = TRUE;
}
} else if (dbus_message_is_signal (message, NM_DBUS_INTERFACE_PPP, "IP4Config")) {
char *iface = NULL;
NMIP4Config *config = NULL;
if (parse_ip4_config (message, &iface, &config)) {
g_signal_emit (manager, signals[IP4_CONFIG], 0, iface, config);
g_free (iface);
g_object_unref (config);
handled = TRUE;
}
}
return handled;
}
static gboolean
pppd_timed_out (gpointer data)
{
NMPPPManager *manager = NM_PPP_MANAGER (data);
nm_warning ("Looks like pppd didn't initialize our dbus module");
nm_ppp_manager_stop (manager);
return FALSE;
}
static void
name_owner_changed (NMDBusManager *dbus_manager,
const char *name,
const char *old,
const char *new,
gpointer user_data)
{
NMPPPManager *manager = NM_PPP_MANAGER (user_data);
NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
gboolean old_owner_good = (old && (strlen (old) > 0));
gboolean new_owner_good = (new && (strlen (new) > 0));
if (strcmp (name, NM_DBUS_SERVICE_PPP))
return;
if (!old_owner_good && new_owner_good) {
if (priv->ppp_timeout_handler) {
g_source_remove (priv->ppp_timeout_handler);
priv->ppp_timeout_handler = 0;
}
priv->signal_handler = nm_dbus_manager_register_signal_handler (priv->dbus_manager,
NM_DBUS_INTERFACE_PPP,
NM_DBUS_SERVICE_PPP,
nm_ppp_manager_dbus_signal_handler,
manager);
} else if (old_owner_good && !new_owner_good) {
nm_ppp_manager_stop (manager);
}
}
static void
start_dbus_watcher (NMPPPManager *manager)
{
NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
priv->ppp_timeout_handler = g_timeout_add (NM_PPP_WAIT_PPPD, pppd_timed_out, manager);
priv->dbus_manager = nm_dbus_manager_get ();
priv->name_owner_changed_handler = g_signal_connect (priv->dbus_manager, "name-owner-changed",
G_CALLBACK (name_owner_changed),
manager);
}
static NMCmdLine *
create_pppd_cmd_line (NMSettingPPP *setting, const char *device, GError **err)
{
const char *ppp_binary;
NMCmdLine *cmd;
ppp_binary = nm_find_pppd ();
if (!ppp_binary) {
g_set_error (err, NM_PPP_MANAGER_ERROR, NM_PPP_MANAGER_ERROR,
"Could not find ppp binary.");
return NULL;
}
/* Create pppd command line */
cmd = nm_cmd_line_new ();
nm_cmd_line_add_string (cmd, ppp_binary);
nm_cmd_line_add_string (cmd, "nodetach");
nm_cmd_line_add_string (cmd, "lock");
nm_cmd_line_add_string (cmd, device);
if (setting->baud)
nm_cmd_line_add_int (cmd, setting->baud);
if (setting->noauth)
nm_cmd_line_add_string (cmd, "noauth");
if (setting->noauth)
nm_cmd_line_add_string (cmd, "refuse-eap");
if (setting->refuse_eap)
nm_cmd_line_add_string (cmd, "refuse-chap");
if (setting->refuse_chap)
nm_cmd_line_add_string (cmd, "refuse-mschap");
if (setting->refuse_mschap)
nm_cmd_line_add_string (cmd, "nobsdcomp");
if (setting->nobsdcomp)
nm_cmd_line_add_string (cmd, "nodeflate");
if (setting->nodeflate)
nm_cmd_line_add_string (cmd, "require-mppe");
if (setting->require_mppe)
nm_cmd_line_add_string (cmd, "require-mppe-128");
if (setting->require_mppe_128)
nm_cmd_line_add_string (cmd, "mppe-stateful");
if (setting->mppe_stateful)
nm_cmd_line_add_string (cmd, "require-mppc");
if (setting->crtscts)
nm_cmd_line_add_string (cmd, "crtscts");
if (setting->usepeerdns)
nm_cmd_line_add_string (cmd, "usepeerdns");
if (setting->mru) {
nm_cmd_line_add_string (cmd, "mru");
nm_cmd_line_add_int (cmd, setting->mru);
}
if (setting->mtu) {
nm_cmd_line_add_string (cmd, "mtu");
nm_cmd_line_add_int (cmd, setting->mtu);
}
if (setting->lcp_echo_failure) {
nm_cmd_line_add_string (cmd, "lcp-echo-failure");
nm_cmd_line_add_int (cmd, setting->lcp_echo_failure);
}
if (setting->lcp_echo_interval) {
nm_cmd_line_add_string (cmd, "lcp-echo-interval");
nm_cmd_line_add_int (cmd, setting->lcp_echo_interval);
}
nm_cmd_line_add_string (cmd, "plugin");
nm_cmd_line_add_string (cmd, NM_PPPD_PLUGIN);
return cmd;
}
gboolean
nm_ppp_manager_start (NMPPPManager *manager,
const char *device,
NMSettingPPP *setting,
GError **err)
{
NMPPPManagerPrivate *priv;
NMCmdLine *ppp_cmd;
char *cmd_str;
GPid pid;
int stdin_fd;
int stdout_fd;
int stderr_fd;
GSource *ppp_watch;
g_return_val_if_fail (NM_IS_PPP_MANAGER (manager), FALSE);
g_return_val_if_fail (device != NULL, FALSE);
g_return_val_if_fail (setting != NULL, FALSE);
ppp_cmd = create_pppd_cmd_line (setting, device, err);
if (!ppp_cmd)
return FALSE;
/* FIXME: This should come from NMSettingIP4Config */
nm_cmd_line_add_string (ppp_cmd, "defaultroute");
g_ptr_array_add (ppp_cmd->array, NULL);
priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
nm_info ("Starting pppd connection");
cmd_str = nm_cmd_line_to_str (ppp_cmd);
nm_debug ("Command line: %s", cmd_str);
g_free (cmd_str);
if (!g_spawn_async_with_pipes (NULL, (char **) ppp_cmd->array->pdata, NULL,
G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &priv->pid,
&stdin_fd, &stdout_fd, &stderr_fd, err)) {
goto out;
}
nm_debug ("ppp started with pid %d", priv->pid);
ppp_watch = g_child_watch_source_new (pid);
g_source_set_callback (ppp_watch, (GSourceFunc) ppp_watch_cb, manager, NULL);
g_source_attach (ppp_watch, NULL);
g_source_unref (ppp_watch);
start_dbus_watcher (manager);
out:
if (ppp_cmd)
nm_cmd_line_destroy (ppp_cmd);
return priv->pid > 0;
}
void
nm_ppp_manager_stop (NMPPPManager *manager)
{
NMPPPManagerPrivate *priv;
g_return_if_fail (NM_IS_PPP_MANAGER (manager));
priv = NM_PPP_MANAGER_GET_PRIVATE (manager);
if (priv->ppp_timeout_handler) {
g_source_remove (priv->ppp_timeout_handler);
priv->ppp_timeout_handler = 0;
}
if (priv->signal_handler) {
nm_dbus_manager_remove_signal_handler (priv->dbus_manager, priv->signal_handler);
priv->signal_handler = 0;
}
if (priv->dbus_manager) {
g_signal_handler_disconnect (priv->dbus_manager, priv->name_owner_changed_handler);
g_object_unref (priv->dbus_manager);
priv->dbus_manager = NULL;
}
if (priv->pid) {
kill (priv->pid, SIGTERM);
priv->pid = 0;
}
}

View File

@@ -0,0 +1,46 @@
#ifndef NM_PPP_MANAGER_H
#define NM_PPP_MANAGER_H
#include <glib/gtypes.h>
#include <glib-object.h>
#include "nm-ppp-status.h"
#include "nm-setting.h"
#include "nm-ip4-config.h"
#include "nm-pppd-plugin.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))
#define NM_PPP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_PPP_MANAGER, NMPPPManagerClass))
#define NM_IS_PPP_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_PPP_MANAGER))
#define NM_IS_PPP_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_PPP_MANAGER))
#define NM_PPP_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_PPP_MANAGER, NMPPPManagerClass))
typedef struct {
GObject parent;
} NMPPPManager;
typedef struct {
GObjectClass parent;
/* Signals */
void (*state_changed) (NMPPPManager *manager, NMPPPStatus status);
void (*ip4_config) (NMPPPManager *manager, const char *iface, NMIP4Config *config);
} NMPPPManagerClass;
GType nm_ppp_manager_get_type (void);
NMPPPManager *nm_ppp_manager_new (void);
gboolean nm_ppp_manager_start (NMPPPManager *manager,
const char *device,
NMSettingPPP *setting,
GError **err);
void nm_ppp_manager_stop (NMPPPManager *manager);
#define NM_PPP_MANAGER_ERROR nm_ppp_manager_error_quark()
GQuark nm_ppp_manager_error_quark (void);
#endif /* NM_PPP_MANAGER_H */

View File

@@ -0,0 +1,3 @@
#include "nm-ppp-marshal.h"
#include "nm-ppp-marshal.c"

View File

@@ -0,0 +1 @@
VOID:STRING,OBJECT

View File

@@ -0,0 +1,22 @@
#ifndef NM_PPP_STATUS_H
#define NM_PPP_STATUS_H
typedef enum {
NM_PPP_STATUS_UNKNOWN,
NM_PPP_STATUS_DEAD,
NM_PPP_STATUS_INITIALIZE,
NM_PPP_STATUS_SERIALCONN,
NM_PPP_STATUS_DORMANT,
NM_PPP_STATUS_ESTABLISH,
NM_PPP_STATUS_AUTHENTICATE,
NM_PPP_STATUS_CALLBACK,
NM_PPP_STATUS_NETWORK,
NM_PPP_STATUS_RUNNING,
NM_PPP_STATUS_TERMINATE,
NM_PPP_STATUS_DISCONNECT,
NM_PPP_STATUS_HOLDOFF,
NM_PPP_STATUS_MASTER
} NMPPPStatus;
#endif /* NM_PPP_STATUS_H */

View File

@@ -0,0 +1,307 @@
/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
#include <pppd/pppd.h>
#include <pppd/fsm.h>
#include <pppd/ipcp.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <glib.h>
#include <dbus/dbus.h>
#include "nm-pppd-plugin.h"
#include "nm-ppp-status.h"
#include "dbus-dict-helpers.h"
char pppd_version[] = VERSION;
static void
nm_phasechange (void *data, int arg)
{
NMPPPStatus status = NM_PPP_STATUS_UNKNOWN;
char *phase;
switch (arg) {
case PHASE_DEAD:
status = NM_PPP_STATUS_DEAD;
phase = "dead";
break;
case PHASE_INITIALIZE:
status = NM_PPP_STATUS_INITIALIZE;
phase = "initialize";
break;
case PHASE_SERIALCONN:
status = NM_PPP_STATUS_SERIALCONN;
phase = "serial connection";
break;
case PHASE_DORMANT:
status = NM_PPP_STATUS_DORMANT;
phase = "dormant";
break;
case PHASE_ESTABLISH:
status = NM_PPP_STATUS_ESTABLISH;
phase = "establish";
break;
case PHASE_AUTHENTICATE:
status = NM_PPP_STATUS_AUTHENTICATE;
phase = "authenticate";
break;
case PHASE_CALLBACK:
status = NM_PPP_STATUS_CALLBACK;
phase = "callback";
break;
case PHASE_NETWORK:
status = NM_PPP_STATUS_NETWORK;
phase = "network";
break;
case PHASE_RUNNING:
status = NM_PPP_STATUS_RUNNING;
phase = "running";
break;
case PHASE_TERMINATE:
status = NM_PPP_STATUS_TERMINATE;
phase = "terminate";
break;
case PHASE_DISCONNECT:
status = NM_PPP_STATUS_DISCONNECT;
phase = "disconnect";
break;
case PHASE_HOLDOFF:
status = NM_PPP_STATUS_HOLDOFF;
phase = "holdoff";
break;
case PHASE_MASTER:
status = NM_PPP_STATUS_MASTER;
phase = "master";
break;
default:
phase = "unknown";
break;
}
g_message ("pppd reported new phase: %s", phase);
if (status != NM_PPP_STATUS_UNKNOWN) {
DBusConnection *connection = (DBusConnection *) data;
DBusMessage *message;
message = dbus_message_new_signal (NM_DBUS_PATH_PPP,
NM_DBUS_INTERFACE_PPP,
"Status");
if (!message) {
g_warning ("Couldn't allocate the dbus message");
return;
}
if (!dbus_message_append_args (message,
DBUS_TYPE_UINT32, &status,
DBUS_TYPE_INVALID)) {
g_warning ("could not append message args");
goto out;
}
if (!dbus_connection_send (connection, message, NULL)) {
g_warning ("could not send dbus message");
goto out;
}
out:
dbus_message_unref (message);
}
}
static const gchar *
ip4_address_as_string (guint32 ip)
{
struct in_addr tmp_addr;
gchar *ip_string;
tmp_addr.s_addr = ip;
ip_string = inet_ntoa (tmp_addr);
return ip_string;
}
static void
nm_ip_up (void *data, int arg)
{
DBusConnection *connection = (DBusConnection *) data;
DBusMessage *signal;
DBusMessageIter iter;
DBusMessageIter iter_dict;
guint32 ip4_address;
guint32 ip4_gateway;
guint32 ip4_dns_1;
guint32 ip4_dns_2;
guint32 ip4_wins_1;
guint32 ip4_wins_2;
guint32 ip4_netmask = 0xFFFFFFFF; /* Default mask of 255.255.255.255 */
if (!ifname) {
g_warning ("Didn't receive a tunnel device name");
return;
}
ip4_address = ipcp_gotoptions[ifunit].ouraddr;
if (!ip4_address) {
g_warning ("Didn't receive an internal IP from pppd");
return;
}
ip4_gateway = ipcp_gotoptions[ifunit].hisaddr;
ip4_dns_1 = ipcp_gotoptions[ifunit].dnsaddr[0];
ip4_dns_2 = ipcp_gotoptions[ifunit].dnsaddr[1];
ip4_wins_1 = ipcp_gotoptions[ifunit].winsaddr[0];
ip4_wins_2 = ipcp_gotoptions[ifunit].winsaddr[1];
g_message ("Got ip configuration");
g_message ("address: %s", ip4_address_as_string (ip4_address));
g_message ("gateway: %s", ip4_address_as_string (ip4_gateway));
g_message ("netmask: %s", ip4_address_as_string (ip4_netmask));
g_message ("DNS1: %s", ip4_address_as_string (ip4_dns_1));
g_message ("DNS2: %s", ip4_address_as_string (ip4_dns_2));
g_message ("WINS1: %s", ip4_address_as_string (ip4_wins_1));
g_message ("WINS2: %s", ip4_address_as_string (ip4_wins_2));
signal = dbus_message_new_signal (NM_DBUS_PATH_PPP,
NM_DBUS_INTERFACE_PPP,
"IP4Config");
if (!signal)
goto out;
dbus_message_iter_init_append (signal, &iter);
if (!nmu_dbus_dict_open_write (&iter, &iter_dict)) {
g_warning ("dict open write failed!");
goto out;
}
if (!nmu_dbus_dict_append_string (&iter_dict, "interface", ifname)) {
g_warning ("couldn't append interface to dict");
goto out;
}
if (!nmu_dbus_dict_append_uint32 (&iter_dict, "addres", ip4_address)) {
g_warning ("couldn't append address to dict");
goto out;
}
if (!nmu_dbus_dict_append_uint32 (&iter_dict, "netmask", ip4_netmask)) {
g_warning ("couldn't append netmask to dict");
goto out;
}
if (!nmu_dbus_dict_append_uint32 (&iter_dict, "gateway", ip4_gateway)) {
g_warning ("couldn't append gateway to dict");
goto out;
}
if (ip4_dns_1 || ip4_dns_2) {
guint32 ip4_dns[2];
guint32 ip4_dns_len = 0;
if (ip4_dns_1)
ip4_dns[ip4_dns_len++] = ip4_dns_1;
if (ip4_dns_2)
ip4_dns[ip4_dns_len++] = ip4_dns_2;
if (!nmu_dbus_dict_append_uint32_array (&iter_dict,
"dns_server",
ip4_dns,
ip4_dns_len)) {
g_warning ("couldn't append dns_servers to dict");
goto out;
}
}
if (ip4_wins_1 || ip4_wins_2) {
guint32 ip4_wins[2];
guint32 ip4_wins_len = 0;
if (ip4_wins_1)
ip4_wins[ip4_wins_len++] = ip4_wins_1;
if (ip4_wins_2)
ip4_wins[ip4_wins_len++] = ip4_wins_2;
if (!nmu_dbus_dict_append_uint32_array (&iter_dict,
"wins_server",
ip4_wins,
ip4_wins_len)) {
g_warning ("couldn't append wins_servers to dict");
goto out;
}
}
if (!nmu_dbus_dict_close_write (&iter, &iter_dict)) {
g_warning ("dict close write failed!");
goto out;
}
if (!dbus_connection_send (connection, signal, NULL)) {
g_warning ("could not send dbus message");
goto out;
}
out:
if (signal)
dbus_message_unref (signal);
}
static void
nm_exit_notify (void *data, int arg)
{
DBusConnection *connection = (DBusConnection *) data;
g_message ("exiting");
if (connection)
dbus_connection_unref (connection);
}
static DBusConnection *
nm_dbus_prepare_connection (void)
{
DBusConnection *connection;
DBusError err;
dbus_error_init (&err);
connection = dbus_bus_get (DBUS_BUS_SYSTEM, &err);
if (!connection || dbus_error_is_set (&err)) {
g_warning ("Could not get the system bus. Make sure the message bus daemon is running.");
goto out;
}
dbus_connection_set_exit_on_disconnect (connection, FALSE);
dbus_error_init (&err);
dbus_bus_request_name (connection, NM_DBUS_SERVICE_PPP, 0, &err);
if (dbus_error_is_set (&err)) {
g_warning ("Could not acquire the dbus service. dbus_bus_request_name() says: '%s'.", err.message);
goto out;
}
out:
if (dbus_error_is_set (&err)) {
dbus_error_free (&err);
connection = NULL;
}
return connection;
}
int
plugin_init (void)
{
DBusConnection *connection;
connection = nm_dbus_prepare_connection ();
if (connection) {
add_notifier (&phasechange, nm_phasechange, connection);
add_notifier (&ip_up_notifier, nm_ip_up, connection);
add_notifier (&exitnotify, nm_exit_notify, connection);
}
return connection ? 0 : -1;
}

View File

@@ -0,0 +1,3 @@
#define NM_DBUS_SERVICE_PPP "org.freedesktop.NetworkManager.PPP"
#define NM_DBUS_PATH_PPP "/org/freedesktop/NetworkManager/PPP"
#define NM_DBUS_INTERFACE_PPP "org.freedesktop.NetworkManager.PPP"