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]
[email protected]
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 [email protected] 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="[email protected]" 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 <[email protected]>
---
 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 <[email protected]>
+ */
+
+#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 <[email protected]>
+ */
+
+#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

_______________________________________________
networkmanager-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to