[RFC] ADSL: Experimental PPPoE support



This is a first cut at experimental PPPoE support for ADSL devices.
There are several shortcuts and the code is ugly, but it works so
it can be used as a strawman to improve upon.

Happily waiting for comments / testing / suggestions :)

With this code and a system keyfile connection like the following:

[connection]
id=OTENETPPPOE
uuid=34d04e69-fdd9-4231-af2c-25ed1f34dc2e
type=adsl
timestamp=1304621332

[adsl]
username=myusername myisp com
password=mypassword
vpi=8
vci=35
encapsulation=llc
protocol=pppoe

[ipv6]
method=ignore

[ipv4]
method=auto

I can connect successfully via pppoe, as evidenced by the following
extract from the logs:

NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 1 of 5 (Device Prepare) scheduled...
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 1 of 5 (Device Prepare) started...
NetworkManager[1495]: <info> starting RFC 2684 Bridge
NetworkManager[1495]: <debug> [1305654571.49055] [nm-br2684-manager.c:403] nm_br2684_manager_start(): command line: /usr/sbin/br2684ctl -c 0 -e 0 -p 1 -a 8.35
NetworkManager[1495]: <info> br2684ctl started with pid 1721
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 1 of 5 (Device Prepare) complete.
NetworkManager[1495]: <debug> [1305654571.62289] [nm-udev-manager.c:622] handle_uevent(): UDEV event: action 'add' subsys 'net' device 'nas0'
NetworkManager[1495]: <warn> /sys/devices/virtual/net/nas0: couldn't determine device driver; ignoring...
NetworkManager[1495]: <debug> [1305654571.63491] [nm-netlink-monitor.c:117] link_msg_handler(): netlink link message: iface idx 62 flags 0x1002
br2684ctl[1721]: Interface "nas0" created sucessfully
br2684ctl[1721]: Communicating over ATM 0.8.35, encapsulation: LLC
br2684ctl[1721]: Interface configured
br2684ctl[1721]: RFC 1483/2684 bridge daemon started
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 2 of 5 (Device Configure) scheduled...
NetworkManager[1495]: <debug> [1305654576.48874] [nm-netlink-monitor.c:117] link_msg_handler(): netlink link message: iface idx 62 flags 0x11043
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 2 of 5 (Device Configure) starting...
NetworkManager[1495]: <info> (ueagle-atm0): device state change: prepare -> config (reason 'none') [40 50 0]
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 2 of 5 (Device Configure) successful.
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 3 of 5 (IP Configure Start) scheduled.
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 2 of 5 (Device Configure) complete.
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 3 of 5 (IP Configure Start) started...
NetworkManager[1495]: <info> (ueagle-atm0): device state change: config -> ip-config (reason 'none') [50 70 0]
NetworkManager[1495]: <info> starting PPP connection
NetworkManager[1495]: <debug> [1305654576.59215] [nm-ppp-manager.c:1056] nm_ppp_manager_start(): command line: /usr/sbin/pppd nodetach lock nodefaultroute debug user myuser myisp com plugin rp-pppoe.so nas0 noipdefault noauth usepeerdns lcp-echo-failure 0 lcp-echo-interval 0 ipparam /org/freedesktop/NetworkManager/PPP/2 plugin /opt/nmadsl/lib/pppd/2.4.5/nm-pppd-plugin.so
NetworkManager[1495]: <info> pppd started with pid 1733
NetworkManager[1495]: <debug> [1305654576.62016] [NetworkManagerUtils.c:848] nm_utils_get_proc_sys_net_value(): (ueagle-atm0): error reading /proc/sys/net/ipv6/conf/ueagle-atm0/accept_ra: (4) Failed to open file '/proc/sys/net/ipv6/conf/ueagle-atm0/accept_ra': No such file or directory
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 3 of 5 (IP Configure Start) complete.
Plugin rp-pppoe.so loaded.
Plugin /opt/nmadsl/lib/pppd/2.4.5/nm-pppd-plugin.so loaded.
** Message: nm-ppp-plugin: (plugin_init): initializing
** Message: nm-ppp-plugin: (nm_phasechange): status 3 / phase 'serial connection'
Send PPPOE Discovery V1T1 PADI session 0x0 length 12
 dst ff:ff:ff:ff:ff:ff  src 0:60:4c:8c:5b:d6
 [service-name] [host-uniq  c5 06 00 00]
Recv PPPOE Discovery V1T1 PADO session 0x0 length 50
 dst 0:60:4c:8c:5b:d6  src 0:90:1a:41:65:24
 [AC-name bras-ari1-1440] [host-uniq  c5 06 00 00] [service-name] [AC-cookie  cc d1 10 3e 4b c8 e9 de b3 c9 73 c7 1d b4 4d 30]
Send PPPOE Discovery V1T1 PADR session 0x0 length 32
 dst 0:90:1a:41:65:24  src 0:60:4c:8c:5b:d6
 [service-name] [host-uniq  c5 06 00 00] [AC-cookie  cc d1 10 3e 4b c8 e9 de b3 c9 73 c7 1d b4 4d 30]
Recv PPPOE Discovery V1T1 PADS session 0x130d length 50
 dst 0:60:4c:8c:5b:d6  src 0:90:1a:41:65:24
 [service-name] [host-uniq  c5 06 00 00] [AC-name bras-ari1-1440] [AC-cookie  cc d1 10 3e 4b c8 e9 de b3 c9 73 c7 1d b4 4d 30]
PADS: Service-Name: ''
PPP session is 4877
Connected to 00:90:1a:41:65:24 via interface nas0
using channel 32
Using interface ppp0
Connect: ppp0 <--> nas0
** Message: nm-ppp-plugin: (nm_phasechange): status 5 / phase 'establish'
sent [LCP ConfReq id=0x1 <mru 1492> <magic 0x2de132c2>]
NetworkManager[1495]: <debug> [1305654576.314811] [nm-netlink-monitor.c:117] link_msg_handler(): netlink link message: iface idx 63 flags 0x1090
NetworkManager[1495]: <debug> [1305654576.314939] [nm-udev-manager.c:622] handle_uevent(): UDEV event: action 'add' subsys 'net' device 'ppp0'
NetworkManager[1495]: <debug> [1305654576.314991] [nm-udev-manager.c:525] net_add(): ignoring interface with type 512
rcvd [LCP ConfReq id=0x11 <mru 1492> <auth pap> <magic 0x701d0b64>]
sent [LCP ConfAck id=0x11 <mru 1492> <auth pap> <magic 0x701d0b64>]
rcvd [LCP ConfAck id=0x1 <mru 1492> <magic 0x2de132c2>]
** Message: nm-ppp-plugin: (nm_phasechange): status 6 / phase 'authenticate'
** Message: nm-ppp-plugin: (get_credentials): passwd-hook, requesting credentials...
NetworkManager[1495]: <debug> [1305654576.420633] [nm-agent-manager.c:1044] nm_agent_manager_get_secrets(): Secrets requested for connection /org/freedesktop/NetworkManager/Settings/0 (adsl)
NetworkManager[1495]: <debug> [1305654576.420743] [nm-settings-connection.c:717] nm_settings_connection_get_secrets(): (34d04e69-fdd9-4231-af2c-25ed1f34dc2e/adsl:1) secrets requested flags 0x1 hint 'password'
NetworkManager[1495]: <debug> [1305654576.421675] [nm-agent-manager.c:959] get_start(): (0x91fde80/adsl) system settings secrets sufficient
NetworkManager[1495]: <debug> [1305654576.422178] [nm-settings-connection.c:573] agent_secrets_done_cb(): (34d04e69-fdd9-4231-af2c-25ed1f34dc2e/adsl:1) existing secrets returned
NetworkManager[1495]: <debug> [1305654576.422419] [nm-settings-connection.c:579] agent_secrets_done_cb(): (34d04e69-fdd9-4231-af2c-25ed1f34dc2e/adsl:1) secrets request completed
NetworkManager[1495]: <debug> [1305654576.424015] [nm-settings-connection.c:618] agent_secrets_done_cb(): (34d04e69-fdd9-4231-af2c-25ed1f34dc2e/adsl:1) new agent secrets processed
** Message: nm-ppp-plugin: (get_credentials): got credentials from NetworkManager
sent [PAP AuthReq id=0x1 user="myuser myisp com" password=<hidden>]
rcvd [PAP AuthAck id=0x1 ""]
PAP authentication succeeded
peer from calling number 00:90:1A:41:65:24 authorized
** Message: nm-ppp-plugin: (nm_phasechange): status 8 / phase 'network'
sent [IPCP ConfReq id=0x1 <addr 0.0.0.0> <ms-dns1 0.0.0.0> <ms-dns2 0.0.0.0>]
rcvd [IPCP ConfNak id=0x1 <addr 94.70.77.249> <ms-dns1 195.170.0.1> <ms-dns2 195.170.2.2>]
sent [IPCP ConfReq id=0x2 <addr 94.70.77.249> <ms-dns1 195.170.0.1> <ms-dns2 195.170.2.2>]
rcvd [IPCP ConfAck id=0x2 <addr 94.70.77.249> <ms-dns1 195.170.0.1> <ms-dns2 195.170.2.2>]
rcvd [IPCP ConfReq id=0x40 <addr 80.106.108.12>]
sent [IPCP ConfAck id=0x40 <addr 80.106.108.12>]
NetworkManager[1495]: <debug> [1305654576.812559] [nm-netlink-monitor.c:117] link_msg_handler(): netlink link message: iface idx 63 flags 0x110D1
local  IP address 94.70.77.249
remote IP address 80.106.108.12
primary   DNS address 195.170.0.1
secondary DNS address 195.170.2.2
** Message: nm-ppp-plugin: (nm_phasechange): status 9 / phase 'running'
** Message: nm-ppp-plugin: (nm_ip_up): ip-up event
** Message: nm-ppp-plugin: (nm_ip_up): sending Ip4Config to NetworkManager...
NetworkManager[1495]: <info> PPP manager(IP Config Get) reply received.
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 4 of 5 (IP4 Configure Get) scheduled...
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 4 of 5 (IP4 Configure Get) started...
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 5 of 5 (IP Configure Commit) scheduled...
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 4 of 5 (IP4 Configure Get) complete.
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 5 of 5 (IP Configure Commit) started...
NetworkManager[1495]: <debug> [1305654576.818828] [nm-system.c:222] sync_addresses(): (ppp0): syncing addresses (family 2)
Script /etc/ppp/ip-up started (pid 1736)
Script /etc/ppp/ip-up finished (pid 1736), status = 0x0
NetworkManager[1495]: <info> (ueagle-atm0): device state change: ip-config -> activated (reason 'none') [70 100 0]
NetworkManager[1495]: <info> Policy set 'CONNPPPOE' (ppp0) as default for IPv4 routing and DNS.
NetworkManager[1495]: <info> Activation (ueagle-atm0) successful, device activated.
NetworkManager[1495]: <info> Activation (ueagle-atm0) Stage 5 of 5 (IP Configure Commit) complete.

Signed-off-by: Pantelis Koukousoulas <pktoss gmail com>
---
 configure.ac                           |    1 +
 include/NetworkManager.h               |    3 +
 src/Makefile.am                        |    2 +
 src/br2684-manager/Makefile.am         |   25 ++
 src/br2684-manager/nm-br2684-manager.c |  427 ++++++++++++++++++++++++++++++++
 src/br2684-manager/nm-br2684-manager.h |   64 +++++
 src/logging/nm-logging.c               |    3 +-
 src/logging/nm-logging.h               |    1 +
 src/nm-device-adsl.c                   |   47 ++++-
 src/nm-device.c                        |    2 +
 src/ppp-manager/nm-ppp-manager.c       |   47 ++--
 11 files changed, 599 insertions(+), 23 deletions(-)
 create mode 100644 src/br2684-manager/Makefile.am
 create mode 100644 src/br2684-manager/nm-br2684-manager.c
 create mode 100644 src/br2684-manager/nm-br2684-manager.h

diff --git a/configure.ac b/configure.ac
index b18ccc0..1679828 100644
--- a/configure.ac
+++ b/configure.ac
@@ -603,6 +603,7 @@ src/ip6-manager/Makefile
 src/supplicant-manager/Makefile
 src/supplicant-manager/tests/Makefile
 src/ppp-manager/Makefile
+src/br2684-manager/Makefile
 src/dnsmasq-manager/Makefile
 src/modem-manager/Makefile
 src/bluez-manager/Makefile
diff --git a/include/NetworkManager.h b/include/NetworkManager.h
index f2e4727..5c9ffc3 100644
--- a/include/NetworkManager.h
+++ b/include/NetworkManager.h
@@ -415,6 +415,9 @@ typedef enum {
 	/* The Bluetooth connection failed or timed out */
 	NM_DEVICE_STATE_REASON_BT_FAILED = 44,
 
+	/* Problem with the RFC 2684 Ethernet over ADSL bridge */
+	NM_DEVICE_STATE_REASON_BR2684_FAILED = 45,
+
 	/* Unused */
 	NM_DEVICE_STATE_REASON_LAST = 0xFFFF
 } NMDeviceStateReason;
diff --git a/src/Makefile.am b/src/Makefile.am
index 50b52d6..f0bc6d7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,6 +6,7 @@ SUBDIRS= \
 	ip6-manager \
 	supplicant-manager \
 	ppp-manager \
+	br2684-manager \
 	backends \
 	dnsmasq-manager \
 	modem-manager \
@@ -267,6 +268,7 @@ NetworkManager_LDADD = \
 	./supplicant-manager/libsupplicant-manager.la \
 	./dnsmasq-manager/libdnsmasq-manager.la \
 	./ppp-manager/libppp-manager.la \
+	./br2684-manager/libbr2684-manager.la \
 	./modem-manager/libmodem-manager.la \
 	./bluez-manager/libbluez-manager.la \
 	./settings/libsettings.la \
diff --git a/src/br2684-manager/Makefile.am b/src/br2684-manager/Makefile.am
new file mode 100644
index 0000000..9a6bb03
--- /dev/null
+++ b/src/br2684-manager/Makefile.am
@@ -0,0 +1,25 @@
+INCLUDES = \
+	-I${top_srcdir} \
+	-I${top_srcdir}/include \
+	-I${top_srcdir}/libnm-util \
+	-I${top_srcdir}/src \
+	-I${top_srcdir}/src/logging \
+	-I${top_builddir}/marshallers
+
+noinst_LTLIBRARIES = libbr2684-manager.la
+
+libbr2684_manager_la_SOURCES = \
+	nm-br2684-manager.c \
+	nm-br2684-manager.h
+
+$(libbr2684_manager_la_OBJECTS): 
+							   
+libbr2684_manager_la_CPPFLAGS = \
+	$(GLIB_CFLAGS) \
+	-DG_DISABLE_DEPRECATED \
+	-DSYSCONFDIR=\"$(sysconfdir)\" \
+	-DLIBDIR=\"$(libdir)\"
+
+libbr2684_manager_la_LIBADD = \
+	$(top_builddir)/src/logging/libnm-logging.la \
+	$(GLIB_LIBS)
diff --git a/src/br2684-manager/nm-br2684-manager.c b/src/br2684-manager/nm-br2684-manager.c
new file mode 100644
index 0000000..68c83a6
--- /dev/null
+++ b/src/br2684-manager/nm-br2684-manager.c
@@ -0,0 +1,427 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Pantelis Koukousoulas <pktoss gmail com>
+ */
+
+#include <config.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include "nm-br2684-manager.h"
+#include "nm-setting-adsl.h"
+#include "nm-logging.h"
+
+typedef struct {
+	gboolean disposed;
+
+	gboolean iface_up;
+	guint32  iface_poll_id;
+	guint32  br2684_watch_id;
+	GPid     pid;
+} NMBr2684ManagerPrivate;
+
+#define NM_BR2684_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_BR2684_MANAGER, NMBr2684ManagerPrivate))
+
+G_DEFINE_TYPE (NMBr2684Manager, nm_br2684_manager, G_TYPE_OBJECT)
+
+enum {
+	STATE_CHANGED,
+
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+	PROP_0,
+	LAST_PROP
+};
+
+typedef enum {
+	NM_BR2684_MANAGER_ERROR_UNKOWN
+} NMBr2684ManagerError;
+
+GQuark
+nm_br2684_manager_error_quark (void)
+{
+	static GQuark quark;
+
+	if (!quark)
+		quark = g_quark_from_static_string ("nm_br2684_manager_error");
+
+	return quark;
+}
+
+static void
+nm_br2684_manager_init (NMBr2684Manager *manager)
+{
+}
+
+static gboolean
+iface_update_cb (gpointer user_data)
+{
+	NMBr2684Manager *self = NM_BR2684_MANAGER (user_data);
+	NMBr2684ManagerPrivate *priv = NM_BR2684_MANAGER_GET_PRIVATE (self);
+
+	gchar *contents = NULL;
+	GError *error = NULL;
+	const gchar *path = "/sys/devices/virtual/net/nas0/ifindex";
+
+	if (!g_file_get_contents(path, &contents, NULL, &error)) {
+		g_clear_error (&error);
+		if (priv->iface_up) {
+			priv->iface_up = FALSE;
+			g_signal_emit(self, signals[STATE_CHANGED], 0, 0);
+		}
+
+		return TRUE;
+	}
+
+	if (!priv->iface_up) {
+		priv->iface_up = TRUE;
+		g_signal_emit(self, signals[STATE_CHANGED], 0, 1);
+	}
+
+	return TRUE;
+}
+
+static GObject *
+constructor (GType type,
+		   guint n_construct_params,
+		   GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	NMBr2684Manager *self;
+	NMBr2684ManagerPrivate *priv;
+
+	object = G_OBJECT_CLASS (nm_br2684_manager_parent_class)->constructor (type,
+	                                                                       n_construct_params,
+	                                                                       construct_params);
+
+	if (!object)
+		return NULL;
+
+	self = NM_BR2684_MANAGER (object);
+	priv = NM_BR2684_MANAGER_GET_PRIVATE (self);
+
+	priv->iface_up = FALSE;
+	priv->iface_poll_id = g_timeout_add_seconds(5, iface_update_cb, self);
+
+	return object;
+}
+
+static gboolean
+ensure_killed (gpointer data)
+{
+	int pid = GPOINTER_TO_INT (data);
+
+	if (kill (pid, 0) == 0)
+		kill (pid, SIGKILL);
+
+	/* ensure the child is reaped */
+	nm_log_dbg (LOGD_BR2684, "waiting for br2684ctl pid %d to exit", pid);
+	waitpid (pid, NULL, 0);
+	nm_log_dbg (LOGD_BR2684, "br2684ctl pid %d cleaned up", pid);
+
+	return FALSE;
+}
+
+static void br2684_cleanup (NMBr2684Manager *manager)
+{
+	NMBr2684ManagerPrivate *priv;
+
+	g_return_if_fail (NM_IS_BR2684_MANAGER (manager));
+
+	priv = NM_BR2684_MANAGER_GET_PRIVATE (manager);
+
+	nm_log_dbg (LOGD_BR2684, "br2684ctl cleanup (pid: %d)", priv->pid);
+
+	if (priv->br2684_watch_id) {
+		g_source_remove (priv->br2684_watch_id);
+		priv->br2684_watch_id = 0;
+	}
+
+	if (priv->pid) {
+		if (kill (priv->pid, SIGTERM) == 0)
+			g_timeout_add_seconds (2, ensure_killed, GINT_TO_POINTER (priv->pid));
+		else {
+			kill (priv->pid, SIGKILL);
+
+			/* ensure the child is reaped */
+			nm_log_dbg (LOGD_BR2684, "waiting for br2684ctl pid %d to exit", priv->pid);
+			waitpid (priv->pid, NULL, 0);
+			nm_log_dbg (LOGD_BR2684, "br2684ctl pid %d cleaned up", priv->pid);
+		}
+
+		priv->pid = 0;
+	}
+}
+
+static void
+dispose (GObject *object)
+{
+	NMBr2684ManagerPrivate *priv = NM_BR2684_MANAGER_GET_PRIVATE (object);
+
+	nm_log_dbg (LOGD_BR2684, "in Br2684Manager::dispose()");
+
+	if (priv->disposed == FALSE) {
+		priv->disposed = TRUE;
+
+		br2684_cleanup(NM_BR2684_MANAGER (object));
+
+		if (priv->iface_poll_id) {
+			g_source_remove(priv->iface_poll_id);
+			priv->iface_poll_id = 0;
+		}
+	}
+
+	G_OBJECT_CLASS (nm_br2684_manager_parent_class)->dispose (object);
+}
+
+static void
+nm_br2684_manager_class_init (NMBr2684ManagerClass *manager_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
+
+	g_type_class_add_private (manager_class, sizeof (NMBr2684ManagerPrivate));
+
+	object_class->constructor = constructor;
+	object_class->dispose = dispose;
+
+	/* signals */
+	signals[STATE_CHANGED] =
+		g_signal_new ("state-changed",
+				    G_OBJECT_CLASS_TYPE (object_class),
+				    G_SIGNAL_RUN_FIRST,
+				    G_STRUCT_OFFSET (NMBr2684ManagerClass, state_changed),
+				    NULL, NULL,
+				    g_cclosure_marshal_VOID__UINT,
+				    G_TYPE_NONE, 1,
+				    G_TYPE_UINT);
+}
+
+/************************************************/
+
+static inline const char *
+nm_find_br2684ctl (void)
+{
+	static const char *br2684ctl_binary_paths[] = {
+		"/usr/local/sbin/br2684ctl",
+		"/usr/sbin/br2684ctl",
+		"/sbin/br2684ctl",
+	};
+
+	const char  **br2684ctl_binary = br2684ctl_binary_paths;
+
+	while (*br2684ctl_binary != NULL) {
+		if (g_file_test (*br2684ctl_binary, G_FILE_TEST_EXISTS))
+			break;
+		br2684ctl_binary++;
+	}
+
+	return *br2684ctl_binary;
+}
+
+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 NMCmdLine *
+create_br2684ctl_cmd_line (NMBr2684Manager *manager,
+                           NMSettingAdsl *s_adsl,
+                           GError **err)
+{
+	const char *b2864_binary;
+	const char *encapsulation, *protocol, *vpi, *vci;
+	gchar *vpivci;
+	gboolean is_llc, is_pppoe;
+	NMCmdLine *cmd;
+
+	b2864_binary = nm_find_br2684ctl ();
+	if (!b2864_binary) {
+		g_set_error (err, NM_BR2684_MANAGER_ERROR, NM_BR2684_MANAGER_ERROR,
+		                               "Could not find br2684ctl binary.");
+	}
+
+	cmd = nm_cmd_line_new ();
+	nm_cmd_line_add_string (cmd, b2864_binary);
+	nm_cmd_line_add_string (cmd, "-c");
+	nm_cmd_line_add_int (cmd, 0); // interface number (for now force nas0)
+
+	encapsulation = nm_setting_adsl_get_encapsulation (s_adsl);
+	is_llc = !strcmp (encapsulation, "llc");
+
+	protocol = nm_setting_adsl_get_protocol (s_adsl);
+	is_pppoe = !strcmp (protocol, "pppoe");
+
+	vpi = nm_setting_adsl_get_vpi (s_adsl);
+	vci = nm_setting_adsl_get_vci (s_adsl);
+	vpivci = g_strdup_printf("%s.%s", vpi, vci);
+
+	nm_cmd_line_add_string (cmd, "-e");
+	nm_cmd_line_add_int (cmd, is_llc ? 0 : 1);
+	nm_cmd_line_add_string (cmd, "-p");
+	nm_cmd_line_add_int (cmd, is_pppoe ? 1 : 0);
+	nm_cmd_line_add_string (cmd, "-a");
+	nm_cmd_line_add_string (cmd, vpivci);
+
+	g_free(vpivci);
+
+	return cmd;
+}
+
+static void
+br2684_child_setup (gpointer user_data G_GNUC_UNUSED)
+{
+	/* We are in the child process at this point */
+	pid_t pid = getpid ();
+	setpgid (pid, pid);
+}
+
+static void
+br2684_watch_cb (GPid pid, gint status, gpointer user_data)
+{
+	NMBr2684Manager *manager = NM_BR2684_MANAGER (user_data);
+	NMBr2684ManagerPrivate *priv = NM_BR2684_MANAGER_GET_PRIVATE (manager);
+	guint err;
+
+	g_assert (pid == priv->pid);
+
+	if (WIFEXITED (status)) {
+		err = WEXITSTATUS (status);
+	} else if (WIFSTOPPED (status)) {
+		nm_log_info (LOGD_BR2684, "br2684ctl pid %d stopped unexpectedly with signal %d", priv->pid, WSTOPSIG (status));
+	} else if (WIFSIGNALED (status)) {
+		nm_log_info (LOGD_BR2684, "br2684ctl pid %d died with signal %d", priv->pid, WTERMSIG (status));
+	} else
+		nm_log_info (LOGD_BR2684, "br2684ctl pid %d died from an unknown cause", priv->pid);
+
+	nm_log_dbg (LOGD_BR2684, "br2684ctl pid %d cleaned up", priv->pid);
+	priv->pid = 0;
+}
+
+
+/* API Functions */
+
+gboolean nm_br2684_manager_start (NMBr2684Manager *manager,
+                                  NMActRequest *req,
+                                  guint32 timeout_secs,
+                                  GError **err)
+{
+	NMBr2684ManagerPrivate *priv;
+	NMConnection *connection;
+	NMSettingAdsl *adsl_setting;
+	NMCmdLine *b2684_cmd;
+	char *cmd_str;
+
+	g_return_val_if_fail (NM_IS_BR2684_MANAGER (manager), FALSE);
+	g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
+
+	priv = NM_BR2684_MANAGER_GET_PRIVATE (manager);
+	priv->pid = 0;
+
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
+
+	adsl_setting = (NMSettingAdsl *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ADSL);
+
+	b2684_cmd = create_br2684ctl_cmd_line (manager, adsl_setting, err);
+	if (!b2684_cmd)
+		goto out;
+
+	g_ptr_array_add (b2684_cmd->array, NULL);
+
+	nm_log_info (LOGD_BR2684, "starting RFC 2684 Bridge");
+
+	cmd_str = nm_cmd_line_to_str (b2684_cmd);
+	nm_log_dbg (LOGD_BR2684, "command line: %s", cmd_str);
+	g_free (cmd_str);
+
+	priv->pid = 0;
+	if (!g_spawn_async (NULL, (char **) b2684_cmd->array->pdata, NULL,
+	                    G_SPAWN_DO_NOT_REAP_CHILD,
+	                    br2684_child_setup,
+	                    NULL, &priv->pid, err))
+		goto out;
+
+	nm_log_info (LOGD_BR2684, "br2684ctl started with pid %d", priv->pid);
+
+	priv->br2684_watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) br2684_watch_cb, manager);
+
+out:
+	if (b2684_cmd)
+		nm_cmd_line_destroy (b2684_cmd);
+
+	return (priv->pid > 0);
+}
+
+NMBr2684Manager *nm_br2684_manager_new ()
+{
+	return (NMBr2684Manager *) g_object_new (NM_TYPE_BR2684_MANAGER,
+	                                         NULL);
+}
diff --git a/src/br2684-manager/nm-br2684-manager.h b/src/br2684-manager/nm-br2684-manager.h
new file mode 100644
index 0000000..dc73639
--- /dev/null
+++ b/src/br2684-manager/nm-br2684-manager.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Author: Pantelis Koukousoulas <pktoss gmail com>
+ */
+
+#ifndef NM_BR2684_MANAGER_H
+#define NM_BR2864_MANAGER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "nm-activation-request.h"
+#include "nm-connection.h"
+#include "nm-ip4-config.h"
+
+#define NM_TYPE_BR2684_MANAGER            (nm_br2684_manager_get_type ())
+#define NM_BR2684_MANAGER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BR2684_MANAGER, NMBr2684Manager))
+#define NM_BR2684_MANAGER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_BR2684_MANAGER, NMBr2684ManagerClass))
+#define NM_IS_BR2684_MANAGER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_BR2684_MANAGER))
+#define NM_IS_BR2684_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_BR2684_MANAGER))
+#define NM_BR2684_MANAGER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_BR2684_MANAGER, NMBr2684ManagerClass))
+
+typedef struct {
+	GObject parent;
+} NMBr2684Manager;
+
+typedef struct {
+	GObjectClass parent;
+
+	/* Signals */
+	void (*state_changed) (NMBr2684Manager *manager, guint state);
+} NMBr2684ManagerClass;
+
+GType nm_br2684_manager_get_type (void);
+
+NMBr2684Manager *nm_br2684_manager_new (void);
+
+gboolean nm_br2684_manager_start (NMBr2684Manager *manager,
+                                  NMActRequest *req,
+                                  guint32 timeout_secs,
+                                  GError **err);
+
+
+#define NM_BR2684_MANAGER_ERROR nm_br2684_manager_error_quark()
+#define NM_TYPE_BR2684_MANAGER_ERROR (nm_br2684_manager_error_get_type ())
+
+GQuark nm_br2684_manager_error_quark (void);
+
+#endif /* NM_BR2684_MANAGER_H */
diff --git a/src/logging/nm-logging.c b/src/logging/nm-logging.c
index 1e289d3..5b7637b 100644
--- a/src/logging/nm-logging.c
+++ b/src/logging/nm-logging.c
@@ -44,7 +44,7 @@ static guint32 log_domains = \
 	LOGD_DHCP4 | LOGD_DHCP6 | LOGD_PPP | LOGD_IP4 | LOGD_IP6 | LOGD_AUTOIP4 | \
 	LOGD_DNS | LOGD_VPN | LOGD_SHARING | LOGD_SUPPLICANT | LOGD_AGENTS | \
 	LOGD_SETTINGS | LOGD_SUSPEND | LOGD_CORE | LOGD_DEVICE | LOGD_OLPC_MESH | \
-	LOGD_WIMAX;
+	LOGD_WIMAX | LOGD_BR2684;
 
 typedef struct {
 	guint32 num;
@@ -85,6 +85,7 @@ static const LogDesc domain_descs[] = {
 	{ LOGD_DEVICE,    "DEVICE" },
 	{ LOGD_OLPC_MESH, "OLPC" },
 	{ LOGD_WIMAX,     "WIMAX" },
+	{ LOGD_BR2684,    "BR2684" },
 	{ 0, NULL }
 };
 
diff --git a/src/logging/nm-logging.h b/src/logging/nm-logging.h
index 44e49a7..cd05ada 100644
--- a/src/logging/nm-logging.h
+++ b/src/logging/nm-logging.h
@@ -52,6 +52,7 @@ enum {
 	LOGD_DEVICE     = 0x00200000, /* Device state and activation */
 	LOGD_OLPC_MESH  = 0x00400000,
 	LOGD_WIMAX      = 0x00800000,
+	LOGD_BR2684     = 0x01000000,
 };
 
 #define LOGD_DHCP (LOGD_DHCP4 | LOGD_DHCP6)
diff --git a/src/nm-device-adsl.c b/src/nm-device-adsl.c
index 77e4d0a..8850558 100644
--- a/src/nm-device-adsl.c
+++ b/src/nm-device-adsl.c
@@ -31,8 +31,10 @@
 #include "nm-glib-compat.h"
 #include "NetworkManagerUtils.h"
 #include "nm-logging.h"
+#include "nm-system.h"
 
 #include "ppp-manager/nm-ppp-manager.h"
+#include "br2684-manager/nm-br2684-manager.h"
 #include "nm-setting-adsl.h"
 
 #include "nm-device-adsl-glue.h"
@@ -68,6 +70,9 @@ typedef struct {
 	/* PPP */
 	NMPPPManager *ppp_manager;
 	NMIP4Config  *pending_ip4_config;
+
+	/* RFC 2684 bridging (PPPoE over ATM) */
+	NMBr2684Manager *br2684_manager;
 } NMDeviceAdslPrivate;
 
 enum {
@@ -222,7 +227,6 @@ dispose (GObject *object)
 		priv->carrier_poll_id = 0;
 	}
 
-
 	G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object);
 }
 
@@ -316,7 +320,7 @@ real_check_connection_compatible (NMDevice *device,
 	}
 
 	s_adsl = (NMSettingAdsl *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ADSL);
-	/* Wired setting is optional for PPPoE */
+
 	if (!s_adsl) {
 		g_set_error (error,
 		             NM_ADSL_ERROR, NM_ADSL_ERROR_CONNECTION_INVALID,
@@ -371,6 +375,11 @@ real_deactivate (NMDevice *device)
 		g_object_unref (priv->ppp_manager);
 		priv->ppp_manager = NULL;
 	}
+
+	if (priv->br2684_manager) {
+		g_object_unref (priv->br2684_manager);
+		priv->br2684_manager = NULL;
+	}
 }
 
 static NMConnection *
@@ -405,13 +414,29 @@ real_get_best_auto_connection (NMDevice *dev,
 	return NULL;
 }
 
+static void
+br2684_state_changed (NMBr2684Manager *manager, guint status, gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+
+	if (status) {
+		nm_system_device_set_up_down_with_iface ("nas0", TRUE, NULL);
+		nm_device_activate_schedule_stage2_device_config (device);
+	} else {
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BR2684_FAILED);
+	}
+}
+
 static NMActStageReturn
 real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 {
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
 	NMDeviceAdsl *self = NM_DEVICE_ADSL (dev);
+	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
 	NMActRequest *req;
 	NMSettingAdsl *s_adsl;
+	GError *err = NULL;
+	const char *protocol;
 
 	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
 
@@ -421,6 +446,22 @@ real_act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 	s_adsl = NM_SETTING_ADSL (device_get_setting (dev, NM_TYPE_SETTING_ADSL));
 	g_assert (s_adsl);
 
+	protocol = nm_setting_adsl_get_protocol (s_adsl);
+	if (!strcmp (protocol, "pppoe")) {
+		priv->br2684_manager = nm_br2684_manager_new();
+		if (!nm_br2684_manager_start (priv->br2684_manager, req, 30, &err)) {
+			nm_log_warn (LOGD_DEVICE, "(%s): RFC 2684 bridge failed to start: %s",
+					             nm_device_get_iface (NM_DEVICE (self)), err->message);
+			ret = NM_ACT_STAGE_RETURN_FAILURE;
+			goto out;
+		}
+		g_signal_connect (priv->br2684_manager, "state-changed",
+					   G_CALLBACK (br2684_state_changed),
+					   self);
+		ret = NM_ACT_STAGE_RETURN_POSTPONE;
+	}
+
+out:
 	return ret;
 }
 
@@ -494,7 +535,7 @@ pppoa_stage3_ip4_config_start (NMDeviceAdsl *self, NMDeviceStateReason *reason)
 					   self);
 		ret = NM_ACT_STAGE_RETURN_POSTPONE;
 	} else {
-		nm_log_warn (LOGD_DEVICE, "(%s): ADSL(PPPoA) failed to start: %s",
+		nm_log_warn (LOGD_DEVICE, "(%s): ADSL failed to start: %s",
 		             nm_device_get_iface (NM_DEVICE (self)), err->message);
 		g_error_free (err);
 
diff --git a/src/nm-device.c b/src/nm-device.c
index 34e1b3a..32897e2 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -3824,6 +3824,8 @@ reason_to_string (NMDeviceStateReason reason)
 		return "modem-not-found";
 	case NM_DEVICE_STATE_REASON_BT_FAILED:
 		return "bluetooth-failed";
+	case NM_DEVICE_STATE_REASON_BR2684_FAILED:
+		return "br2684 bridge failed";
 	default:
 		break;
 	}
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index 0704c3a..e4580c0 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -796,7 +796,7 @@ static NMCmdLine *
 create_pppd_cmd_line (NMPPPManager *self,
                       NMSettingPPP *setting, 
                       NMSettingPPPOE *pppoe,
-                      NMSettingAdsl  *adsl_pppoa,
+                      NMSettingAdsl  *adsl,
                       const char *ppp_name,
                       GError **err)
 {
@@ -849,27 +849,36 @@ create_pppd_cmd_line (NMPPPManager *self,
 			nm_cmd_line_add_string (cmd, "rp_pppoe_service");
 			nm_cmd_line_add_string (cmd, pppoe_service);
 		}
-	} else if (adsl_pppoa) {
-		const char *vpi;
-		const char *vci;
-		const gchar *encapsulation;
-		gchar *vpivci;
-
-		vpi = nm_setting_adsl_get_vpi (adsl_pppoa);
-		vci = nm_setting_adsl_get_vci (adsl_pppoa);
-		encapsulation = nm_setting_adsl_get_encapsulation (adsl_pppoa);
-		vpivci = g_strdup_printf("%s.%s", vpi, vci);
-
-		nm_cmd_line_add_string (cmd, "plugin");
-		nm_cmd_line_add_string (cmd, "pppoatm.so");
-		nm_cmd_line_add_string (cmd, vpivci);
-
-		if (!strcmp (encapsulation, "llc"))
-			nm_cmd_line_add_string (cmd, "llc-encaps");
+	} else if (adsl) {
+		const gchar *protocol = nm_setting_adsl_get_protocol (adsl);
+
+		if (!strcmp (protocol, "pppoa")) {
+			const char *vpi;
+			const char *vci;
+			const gchar *encapsulation;
+			gchar *vpivci;
+
+			vpi = nm_setting_adsl_get_vpi (adsl);
+			vci = nm_setting_adsl_get_vci (adsl);
+			encapsulation = nm_setting_adsl_get_encapsulation (adsl);
+			vpivci = g_strdup_printf("%s.%s", vpi, vci);
+
+			nm_cmd_line_add_string (cmd, "plugin");
+			nm_cmd_line_add_string (cmd, "pppoatm.so");
+			nm_cmd_line_add_string (cmd, vpivci);
+
+			if (!strcmp (encapsulation, "llc"))
+				nm_cmd_line_add_string (cmd, "llc-encaps");
+
+			g_free (vpivci);
+		} else if (!strcmp (protocol, "pppoe")) {
+			nm_cmd_line_add_string (cmd, "plugin");
+			nm_cmd_line_add_string (cmd, "rp-pppoe.so");
+			nm_cmd_line_add_string (cmd, "nas0");
+		}
 
 		nm_cmd_line_add_string (cmd, "noipdefault");
 
-		g_free (vpivci);
 	} else {
 		nm_cmd_line_add_string (cmd, priv->parent_iface);
 		/* Don't send some random address as the local address */
-- 
1.7.4.1



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]