adsl: talk ADSL ioctls directly and kill usage of br2684ctl

The code to set up ATM interfaces is actually pretty simple,
so don't bother spawning br2684ctl at all.  Just do the
necessary communication with the kernel directly and save
a bunch of code.

Note: this isn't very likely to work as I don't have an
ADSL connection to test with.  Testing help appreciated.
This commit is contained in:
Dan Williams 2011-12-08 23:43:41 -06:00
parent f8243e45c9
commit e048b8e013
7 changed files with 331 additions and 586 deletions

View file

@ -743,7 +743,6 @@ 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

View file

@ -7,7 +7,6 @@ SUBDIRS= \
ip6-manager \
supplicant-manager \
ppp-manager \
br2684-manager \
backends \
dnsmasq-manager \
modem-manager \
@ -312,7 +311,6 @@ 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 \
./wifi/libwifi-utils.la \

View file

@ -1,25 +0,0 @@
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)

View file

@ -1,428 +0,0 @@
/* -*- 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;
guint32 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 ("%d.%d", 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);
}

View file

@ -1,64 +0,0 @@
/* -*- 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 */

View file

@ -18,12 +18,22 @@
* Pantelis Koukousoulas <pktoss@gmail.com>
*/
#include <config.h>
#include <sys/socket.h>
#include <linux/atmdev.h>
#include <linux/atmbr2684.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <unistd.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <stdlib.h>
#include <string.h>
#include "nm-glib-compat.h"
#include "nm-device-adsl.h"
#include "nm-device-private.h"
#include "nm-properties-changed-signal.h"
@ -34,7 +44,6 @@
#include "nm-netlink-monitor.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"
@ -60,12 +69,19 @@ typedef struct {
gboolean disposed;
gboolean carrier;
guint carrier_poll_id;
int atm_index;
/* Watch for 'nas' interfaces going away */
NMNetlinkMonitor *monitor;
guint netlink_id;
/* PPP */
NMPPPManager *ppp_manager;
/* RFC 2684 bridging (PPPoE over ATM) */
NMBr2684Manager *br2684_manager;
int brfd;
int nas_ifindex;
char * nas_ifname;
} NMDeviceAdslPrivate;
enum {
@ -193,19 +209,16 @@ real_get_best_auto_connection (NMDevice *dev,
NMConnection *connection = NM_CONNECTION (iter->data);
NMSettingConnection *s_con;
NMSettingAdsl *s_adsl;
const char *connection_type;
s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
connection_type = nm_setting_connection_get_connection_type (s_con);
if (strcmp (connection_type, NM_SETTING_ADSL_SETTING_NAME))
if (!nm_connection_is_type (connection, NM_SETTING_ADSL_SETTING_NAME))
continue;
s_adsl = nm_connection_get_setting_adsl (connection);
if (!s_adsl)
continue;
s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
if (!nm_setting_connection_get_autoconnect (s_con))
continue;
@ -217,65 +230,245 @@ real_get_best_auto_connection (NMDevice *dev,
/**************************************************************/
static void
br2684_state_changed (NMBr2684Manager *manager, guint status, gpointer user_data)
set_nas_iface (NMDeviceAdsl *self, int idx, const char *name)
{
NMDevice *device = NM_DEVICE (user_data);
int ifindex;
NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
if (status) {
ifindex = nm_netlink_iface_to_index ("nas0");
if (ifindex > 0)
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BR2684_FAILED);
else {
nm_system_iface_set_up (ifindex, TRUE, NULL);
nm_device_activate_schedule_stage2_device_config (device);
g_return_if_fail (name != NULL);
g_warn_if_fail (priv->nas_ifindex <= 0);
if (idx > 0)
priv->nas_ifindex = idx;
else
priv->nas_ifindex = nm_netlink_iface_to_index (name);
g_warn_if_fail (priv->nas_ifindex > 0);
g_warn_if_fail (priv->nas_ifname == NULL);
priv->nas_ifname = g_strdup (name);
}
static gboolean
br2684_create_iface (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
{
NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
const char *iface = nm_device_get_iface (NM_DEVICE (self));
struct atm_newif_br2684 ni;
int err, fd;
gboolean success = FALSE;
guint num = 0;
g_return_val_if_fail (s_adsl != NULL, FALSE);
fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
if (fd < 0) {
nm_log_err (LOGD_ADSL, "(%s): failed to open ATM control socket (%d)",
iface, errno);
return FALSE;
}
memset (&ni, 0, sizeof (ni));
ni.backend_num = ATM_BACKEND_BR2684;
ni.media = BR2684_MEDIA_ETHERNET;
ni.mtu = 1500;
/* Loop attempting to create an interface that doesn't exist yet. The
* kernel can create one for us automatically, but due to API issues it
* cannot return that name to us. Since we want to know the name right
* away, just brute-force it.
*/
while (num < 10000) {
memset (&ni.ifname, 0, sizeof (ni.ifname));
snprintf (ni.ifname, sizeof (ni.ifname), "nas%d", num);
err = ioctl (fd, ATM_NEWBACKENDIF, &ni);
if (err == 0) {
set_nas_iface (self, -1, ni.ifname);
nm_log_info (LOGD_ADSL, "(%s): using NAS interface %s (%d)",
iface, priv->nas_ifname, priv->nas_ifindex);
success = TRUE;
break;
} else if (errno == -EEXIST) {
/* Try again */
num++;
} else {
nm_log_warn (LOGD_ADSL, "(%s): failed to create br2684 interface (%d)",
iface, errno);
break;
}
} else
nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BR2684_FAILED);
}
close (fd);
return success;
}
static gboolean
br2684_assign_vcc (NMDeviceAdsl *self, NMSettingAdsl *s_adsl)
{
NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
const char *iface = nm_device_get_iface (NM_DEVICE (self));
struct sockaddr_atmpvc addr;
struct atm_backend_br2684 be;
struct atm_qos qos;
int err, bufsize = 8192;
const char *encapsulation;
gboolean is_llc;
g_return_val_if_fail (priv->brfd == -1, FALSE);
g_return_val_if_fail (priv->nas_ifname != NULL, FALSE);
priv->brfd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
if (priv->brfd < 0) {
nm_log_err (LOGD_ADSL, "(%s): failed to open ATM control socket (%d)",
iface, errno);
return FALSE;
}
err = setsockopt (priv->brfd, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof (bufsize));
if (err != 0) {
nm_log_err (LOGD_ADSL, "(%s): failed to set SNDBUF option (%d)",
iface, errno);
goto error;
}
/* QoS */
memset (&qos, 0, sizeof (qos));
qos.aal = ATM_AAL5;
qos.txtp.traffic_class = ATM_UBR;
qos.txtp.max_sdu = 1524;
qos.txtp.pcr = ATM_MAX_PCR;
qos.rxtp = qos.txtp;
err = setsockopt (priv->brfd, SOL_ATM, SO_ATMQOS, &qos, sizeof (qos));
if (err != 0) {
nm_log_err (LOGD_ADSL, "(%s): failed to set QoS (%d)",
iface, errno);
goto error;
}
encapsulation = nm_setting_adsl_get_encapsulation (s_adsl);
/* VPI/VCI */
memset (&addr, 0, sizeof (addr));
addr.sap_family = AF_ATMPVC;
addr.sap_addr.itf = priv->atm_index;
addr.sap_addr.vpi = (guint16) nm_setting_adsl_get_vpi (s_adsl);
addr.sap_addr.vci = (int) nm_setting_adsl_get_vci (s_adsl);
nm_log_dbg (LOGD_ADSL, "(%s): assigning address %d.%d.%d encapsulation %s",
nm_device_get_iface (NM_DEVICE (self)),
priv->atm_index, addr.sap_addr.vpi, addr.sap_addr.vci,
encapsulation);
err = connect (priv->brfd, (struct sockaddr*) &addr, sizeof (addr));
if (err != 0) {
nm_log_err (LOGD_ADSL, "(%s): failed to set VPI/VCI (%d)",
iface, errno);
goto error;
}
/* And last attach the VCC to the interface */
is_llc = (g_strcmp0 (encapsulation, "llc") == 0);
memset (&be, 0, sizeof (be));
be.backend_num = ATM_BACKEND_BR2684;
be.ifspec.method = BR2684_FIND_BYIFNAME;
strcpy (be.ifspec.spec.ifname, priv->nas_ifname);
be.fcs_in = BR2684_FCSIN_NO;
be.fcs_out = BR2684_FCSOUT_NO;
be.encaps = is_llc ? BR2684_ENCAPS_LLC : BR2684_ENCAPS_VC;
err = ioctl (priv->brfd, ATM_SETBACKEND, &be);
if (err != 0) {
nm_log_err (LOGD_ADSL, "(%s): failed to attach VCC (%d)",
iface, errno);
goto error;
}
return TRUE;
error:
close (priv->brfd);
priv->brfd = -1;
return FALSE;
}
static void
netlink_notification (NMNetlinkMonitor *monitor,
struct nl_msg *msg,
gpointer user_data)
{
NMDeviceAdsl *self = NM_DEVICE_ADSL (user_data);
NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
NMDevice *device = NM_DEVICE (user_data);
struct nlmsghdr *hdr = nlmsg_hdr (msg);
const char *iface = nm_device_get_iface (device);
/* This only gets called for PPPoE connections and "nas" interfaces */
if ((hdr->nlmsg_type == RTM_DELLINK) && (priv->nas_ifindex >= 0)) {
struct ifinfomsg *ifi = nlmsg_data (hdr);
if (ifi->ifi_index == priv->nas_ifindex) {
/* NAS device went away for some reason; kill the connection */
nm_log_dbg (LOGD_ADSL, "(%s): NAS interface disappeared", iface);
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)
real_act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason)
{
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
NMDeviceAdsl *self = NM_DEVICE_ADSL (dev);
NMDeviceAdsl *self = NM_DEVICE_ADSL (device);
NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
NMActRequest *req;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
NMSettingAdsl *s_adsl;
GError *err = NULL;
const char *protocol;
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
g_assert (out_reason);
req = nm_device_get_act_request (NM_DEVICE (self));
g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
s_adsl = nm_connection_get_setting_adsl (nm_device_get_connection (dev));
s_adsl = nm_connection_get_setting_adsl (nm_device_get_connection (device));
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;
nm_log_dbg (LOGD_ADSL, "(%s): using ADSL protocol '%s'",
nm_device_get_iface (device), protocol);
if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) {
/* PPPoE needs RFC2684 bridging before we can do PPP over it */
if (!br2684_create_iface (self, s_adsl)) {
*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
goto done;
}
g_signal_connect (priv->br2684_manager, "state-changed",
G_CALLBACK (br2684_state_changed),
self);
ret = NM_ACT_STAGE_RETURN_POSTPONE;
/* Set up the VCC */
if (!br2684_assign_vcc (self, s_adsl)) {
*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
goto done;
}
/* Watch for the 'nas' interface going away */
priv->netlink_id = g_signal_connect (priv->monitor, "notification",
G_CALLBACK (netlink_notification),
self);
nm_log_dbg (LOGD_ADSL, "(%s): ATM setup successful", nm_device_get_iface (device));
/* otherwise we're good for stage3 */
nm_system_iface_set_up (priv->nas_ifindex, TRUE, NULL);
ret = NM_ACT_STAGE_RETURN_SUCCESS;
} else if (g_strcmp0 (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOA) == 0) {
/* PPPoA doesn't need anything special */
ret = NM_ACT_STAGE_RETURN_SUCCESS;
} else {
nm_log_warn (LOGD_ADSL, "(%s): unhandled ADSL protocol '%s'",
nm_device_get_iface (device), protocol);
}
out:
return ret;
}
static NMActStageReturn
real_act_stage2_config (NMDevice *device, NMDeviceStateReason *reason)
{
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
done:
return ret;
}
@ -324,6 +517,7 @@ real_act_stage3_ip4_config_start (NMDevice *device,
GError *err = NULL;
NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
const char *iface = nm_device_get_iface (device);
const char *ppp_iface;
req = nm_device_get_act_request (device);
g_assert (req);
@ -334,7 +528,19 @@ real_act_stage3_ip4_config_start (NMDevice *device,
s_adsl = nm_connection_get_setting_adsl (connection);
g_assert (s_adsl);
priv->ppp_manager = nm_ppp_manager_new (iface);
/* PPPoE uses the NAS inteface, not the ATM interface */
if (g_strcmp0 (nm_setting_adsl_get_protocol (s_adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE) == 0) {
g_assert (priv->nas_ifname);
ppp_iface = priv->nas_ifname;
nm_log_dbg (LOGD_ADSL, "(%s): starting PPPoE on NAS interface %s",
iface, priv->nas_ifname);
} else {
ppp_iface = iface;
nm_log_dbg (LOGD_ADSL, "(%s): starting PPPoA", iface);
}
priv->ppp_manager = nm_ppp_manager_new (ppp_iface);
if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), 30, &err)) {
g_signal_connect (priv->ppp_manager, "state-changed",
G_CALLBACK (ppp_state_changed),
@ -344,7 +550,7 @@ real_act_stage3_ip4_config_start (NMDevice *device,
self);
ret = NM_ACT_STAGE_RETURN_POSTPONE;
} else {
nm_log_warn (LOGD_DEVICE, "(%s): PPP failed to start: %s", iface, err->message);
nm_log_warn (LOGD_ADSL, "(%s): PPP failed to start: %s", iface, err->message);
g_error_free (err);
g_object_unref (priv->ppp_manager);
@ -367,10 +573,24 @@ real_deactivate (NMDevice *device)
priv->ppp_manager = NULL;
}
if (priv->br2684_manager) {
g_object_unref (priv->br2684_manager);
priv->br2684_manager = NULL;
if (priv->netlink_id) {
g_signal_handler_disconnect (priv->monitor, priv->netlink_id);
priv->netlink_id = 0;
}
if (priv->brfd >= 0) {
close (priv->brfd);
priv->brfd = -1;
}
/* FIXME: kernel has no way of explicitly deleting the 'nasX' interface yet,
* so it gets leaked. It does get destroyed when it's no longer in use,
* but we have no control over that.
*/
if (priv->nas_ifindex >= 0)
priv->nas_ifindex = -1;
g_free (priv->nas_ifname);
priv->nas_ifname = NULL;
}
/**************************************************************/
@ -419,11 +639,11 @@ carrier_update_cb (gpointer user_data)
iface = nm_device_get_iface (NM_DEVICE (self));
path = g_strdup_printf ("/sys/class/atm/%s/carrier", iface);
success = g_file_get_contents(path, &contents, NULL, &error);
success = g_file_get_contents (path, &contents, NULL, &error);
g_free (path);
if (!success) {
nm_log_dbg (LOGD_DEVICE, "error reading %s: (%d) %s",
nm_log_dbg (LOGD_ADSL, "error reading %s: (%d) %s",
path,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
@ -455,6 +675,20 @@ nm_device_adsl_new (const char *udi,
NULL);
}
static int
get_atm_index (const char *iface, GError **error)
{
char *path, *contents;
int idx = -1;
path = g_strdup_printf ("/sys/class/atm/%s/atmindex", iface);
if (g_file_get_contents (path, &contents, NULL, error))
idx = atoi (contents);
g_free (path);
g_free (contents);
return idx;
}
static GObject*
constructor (GType type,
guint n_construct_params,
@ -462,15 +696,32 @@ constructor (GType type,
{
GObject *object;
NMDeviceAdslPrivate *priv;
GError *error = NULL;
object = G_OBJECT_CLASS (nm_device_adsl_parent_class)->constructor (type,
n_construct_params,
construct_params);
if (object) {
priv = NM_DEVICE_ADSL_GET_PRIVATE (object);
priv->carrier_poll_id = g_timeout_add_seconds (5, carrier_update_cb, object);
if (!object)
return NULL;
priv = NM_DEVICE_ADSL_GET_PRIVATE (object);
priv->atm_index = get_atm_index (nm_device_get_iface (NM_DEVICE (object)), &error);
if (priv->atm_index < 0) {
nm_log_dbg (LOGD_ADSL, "error reading ATM device index: (%d) %s",
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
g_object_unref (object);
return NULL;
} else {
nm_log_dbg (LOGD_ADSL, "(%s): ATM device index %d",
nm_device_get_iface (NM_DEVICE (object)), priv->atm_index);
}
/* Poll the carrier */
priv->carrier_poll_id = g_timeout_add_seconds (5, carrier_update_cb, object);
return object;
}
@ -492,6 +743,20 @@ dispose (GObject *object)
priv->carrier_poll_id = 0;
}
if (priv->netlink_id) {
g_source_remove (priv->netlink_id);
priv->netlink_id = 0;
}
if (priv->monitor) {
nm_netlink_monitor_unsubscribe (priv->monitor, RTNLGRP_LINK);
g_object_unref (priv->monitor);
priv->monitor = NULL;
}
g_free (priv->nas_ifname);
priv->nas_ifname = NULL;
G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object);
}
@ -524,8 +789,12 @@ set_property (GObject *object, guint prop_id,
}
static void
nm_device_adsl_init (NMDeviceAdsl * self)
nm_device_adsl_init (NMDeviceAdsl *self)
{
NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
priv->monitor = nm_netlink_monitor_get ();
nm_netlink_monitor_subscribe (priv->monitor, RTNLGRP_LINK, NULL);
}
static void
@ -549,7 +818,6 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass)
parent_class->get_best_auto_connection = real_get_best_auto_connection;
parent_class->complete_connection = real_complete_connection;
parent_class->act_stage1_prepare = real_act_stage1_prepare;
parent_class->act_stage2_config = real_act_stage2_config;
parent_class->act_stage3_ip4_config_start = real_act_stage3_ip4_config_start;
parent_class->deactivate = real_deactivate;

View file

@ -879,10 +879,7 @@ create_pppd_cmd_line (NMPPPManager *self,
} else if (!strcmp (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE)) {
nm_cmd_line_add_string (cmd, "plugin");
nm_cmd_line_add_string (cmd, "rp-pppoe.so");
/* FIXME: dynamically figure out the NAS interface name so we can
* do more than one br2684 PPPoE connection at the same time.
*/
nm_cmd_line_add_string (cmd, "nas0");
nm_cmd_line_add_string (cmd, priv->parent_iface);
}
nm_cmd_line_add_string (cmd, "noipdefault");