blob: 47ac3ffa3a0ecdd5b0c440412b1e9ba430ea9d65 [file] [log] [blame]
From 66dbce87f113ddc2f052dd611444992fdc882d76 Mon Sep 17 00:00:00 2001
From: Peter Qiu <zqiu@chromium.org>
Date: Thu, 14 May 2015 14:53:56 -0700
Subject: [PATCH] Add DBus RPC support
Porting the DBus support from version 5.1.4 and allow it to be
configurable through the package configuration. Removed the unused
and incomplete implemention for DBus method GetInterfaces and GetStatus.
Also: update the default lease file name to tailor around the
expectation of shill ("dhcpcd-%dev.lease).
Also: update the config file to meet shill's expectation.
Author: Sam Leffler <sleffler@google.com>
Author: Nathan Williams <njw@chromium.org>
Author: Jorge Lucangeli Obes <jorgelo@chromium.org>
Author: Paul Stewart <pstew@chromium.org>
Review URL: http://codereview.chromium.org/2428004
Review URL: http://codereview.chromium.org/2851022
Review URL: http://codereview.chromium.org/2851023
Review URL: http://codereview.chromium.org/2865017
Review URL: http://codereview.chromium.org/2965010
Review URL: http://codereview.chromium.org/2957010
Review URL: http://codereview.chromium.org/3060016
Reviewed-on: http://gerrit.chromium.org/gerrit/2228
Reviewed-on: https://gerrit.chromium.org/gerrit/22597
Reviewed-on: https://gerrit.chromium.org/gerrit/36716
Reviewed-on: https://gerrit.chromium.org/gerrit/38183
Reviewed-on: https://gerrit.chromium.org/gerrit/59967
Reviewed-on: https://chromium-review.googlesource.com/178462
Reviewed-on: https://chromium-review.googlesource.com/185086
Reviewed-on: https://chromium-review.googlesource.com/195269
Reviewed-on: https://chromium-review.googlesource.com/259072
---
Makefile | 40 ++-
common.c | 2 +-
configure | 12 +
dbus/dbus-dict.c | 250 +++++++++++++++++
dbus/dbus-dict.h | 43 +++
dbus/dhcpcd-dbus.conf | 21 ++
dbus/org.chromium.dhcpcd.in | 4 +
dbus/rpc-dbus.c | 654 ++++++++++++++++++++++++++++++++++++++++++++
dbus/test/introspection | 9 +
dbus/test/monitor | 19 ++
dhcp-common.c | 31 +--
dhcp.c | 9 +-
dhcpcd-definitions.conf | 2 +-
dhcpcd.c | 58 +++-
dhcpcd.conf | 24 +-
dhcpcd.h | 5 +
16 files changed, 1136 insertions(+), 47 deletions(-)
create mode 100644 dbus/dbus-dict.c
create mode 100644 dbus/dbus-dict.h
create mode 100644 dbus/dhcpcd-dbus.conf
create mode 100644 dbus/org.chromium.dhcpcd.in
create mode 100644 dbus/rpc-dbus.c
create mode 100755 dbus/test/introspection
create mode 100755 dbus/test/monitor
diff --git a/Makefile b/Makefile
index e52e7cc..d016c4b 100644
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,9 @@
PROG= dhcpcd
SRCS= common.c control.c dhcpcd.c duid.c eloop.c
-SRCS+= if.c if-options.c rpc-stub.c
+SRCS+= if.c if-options.c
SRCS+= dhcp-common.c
+PKG_CONFIG ?= pkg-config
CFLAGS?= -O2
MKDIRS=
@@ -30,10 +31,34 @@ MAN8= dhcpcd.8 dhcpcd-run-hooks.8
CLEANFILES= dhcpcd.conf.5 dhcpcd.8 dhcpcd-run-hooks.8
SCRIPTS= dhcpcd-run-hooks
+
+FILES= dhcpcd.conf
+
+ifeq ($(DBUS_SUPPORT),yes)
+FILES+= dbus/dhcpcd-dbus.conf
+
+_DBUSCFLAGS_SH= $(PKG_CONFIG) --cflags dbus-1
+_DBUSCFLAGS!= ${_DBUSCFLAGS_SH}
+DBUSCFLAGS= ${_DBUSCFLAGS}$(shell ${_DBUSCFLAGS_SH})
+
+_DBUSLIBS_SH= $(PKG_CONFIG) --libs dbus-1
+_DBUSLIBS!= ${_DBUSLIBS_SH}
+DBUSLIBS= ${_DBUSLIBS}$(shell ${_DBUSLIBS_SH})
+DBUSDIR= ${SYSCONFDIR}/dbus-1/system.d
+
+CFLAGS+= ${DBUSCFLAGS}
+LDADD+= ${DBUSLIBS}
+endif
+
+# Linux needs librt
+_LIBRT_SH= [ "$$(uname -s)" = "Linux" ] && echo "-lrt" || echo ""
+_LIBRT!= ${_LIBRT_SH}
+LIBRT?= ${_LIBRT} $(shell ${_LIBRT_SH})
+LDADD+= ${LIBRT}
+
SCRIPTSDIR= ${LIBEXECDIR}
CLEANFILES+= dhcpcd-run-hooks
-FILES= dhcpcd.conf
FILESDIR= ${SYSCONFDIR}
SUBDIRS= ${MKDIRS}
@@ -75,7 +100,7 @@ CLEANFILES+= *.tar.bz2
${SED_SERVICEEXISTS} ${SED_SERVICECMD} ${SED_SERVICESTATUS} \
$< > $@
-all: config.h ${PROG} ${SCRIPTS} ${MAN5} ${MAN8}
+all: config.h ${PROG} ${SCRIPTS} ${MAN5} ${MAN8} ${FILES}
for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@; cd ..; done
dev:
@@ -127,12 +152,17 @@ _maninstall: ${MAN5} ${MAN8}
${INSTALL} -d ${DESTDIR}${MANDIR}/man8
${INSTALL} -m ${MANMODE} ${MAN8} ${DESTDIR}${MANDIR}/man8
-_confinstall:
+_dbusinstall: dbus/dhcpcd-dbus.conf
+ ${INSTALL} -d ${DESTDIR}${DBUSDIR}
+ ${INSTALL} -m ${CONFMODE} dbus/dhcpcd-dbus.conf \
+ ${DESTDIR}${DBUSDIR}/dhcpcd.conf
+
+_confinstall: ${DBUSINSTALL}
${INSTALL} -d ${DESTDIR}${SYSCONFDIR}
test -e ${DESTDIR}${SYSCONFDIR}/dhcpcd.conf || \
${INSTALL} -m ${CONFMODE} dhcpcd.conf ${DESTDIR}${SYSCONFDIR}
-install: proginstall _maninstall _confinstall
+install: proginstall _confinstall
clean:
rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
diff --git a/common.c b/common.c
index f930ee0..ccad014 100644
--- a/common.c
+++ b/common.c
@@ -161,7 +161,7 @@ logger_open(struct dhcpcd_ctx *ctx)
}
#endif
} else
- openlog(PACKAGE, LOG_PID, LOG_DAEMON);
+ openlog(PACKAGE, LOG_PID | LOG_PERROR, LOG_DAEMON);
}
void
diff --git a/configure b/configure
index 0d80876..fe612d9 100755
--- a/configure
+++ b/configure
@@ -25,6 +25,7 @@ INCLUDEDIR=
DEVS=
EMBEDDED=
POLL=
+DBUS=
for x do
opt=${x%%=*}
@@ -45,6 +46,8 @@ for x do
--enable-ipv6) INET6=yes;;
--disable-embedded) EMBEDDED=no;;
--enable-embedded) EMBEDDED=yes;;
+ --enable-dbus) DBUS=yes;;
+ --disable-dbus) DBUS=no;;
--prefix) PREFIX=$var;;
--sysconfdir) SYSCONFDIR=$var;;
--bindir|--sbindir) SBINDIR=$var;;
@@ -406,6 +409,15 @@ if [ -z "$INET6" -o "$INET6" = yes ]; then
echo "DHCPCD_SRCS+= ipv6.c ipv6nd.c dhcp6.c" >>$CONFIG_MK
fi
+if [ "$DBUS" = yes ]; then
+ echo "DBUS_SUPPORT= yes" >>$CONFIG_MK
+ echo "DBUSINSTALL= _dbusinstall" >>$CONFIG_MK
+ echo "CPPFLAGS+= -DPASSIVE_MODE" >>$CONFIG_MK
+ echo "DHCPCD_SRCS+= dbus/dbus-dict.c dbus/rpc-dbus.c" >>$CONFIG_MK
+else
+ echo "DHCPCD_SRCS+= rpc-stub.c" >>$CONFIG_MK
+fi
+
if [ -z "$HOOKSCRIPTS" ]; then
echo "DHCPCD_SRCS+= script-stub.c" >>$CONFIG_MK
else
diff --git a/dbus/dbus-dict.c b/dbus/dbus-dict.c
new file mode 100644
index 0000000..aeee57c
--- /dev/null
+++ b/dbus/dbus-dict.c
@@ -0,0 +1,250 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+
+#include <dbus/dbus.h>
+
+#include "../config.h"
+#include "dbus-dict.h"
+
+static dbus_bool_t
+append_sanitized_string(DBusMessageIter *iter, const char *value)
+{
+ dbus_bool_t ret;
+ int len = strlen(value);
+ char *sanitized_value = NULL;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (isascii(value[i]) || isprint(value[i])) {
+ if (sanitized_value)
+ sanitized_value[i] = value[i];
+ } else {
+ if (sanitized_value == NULL) {
+ sanitized_value = malloc(len + 1);
+ if (sanitized_value == NULL) {
+ syslog(LOG_ERR, "DBus string parameter "
+ "sanitization failed due to "
+ "malloc failure");
+ return FALSE;
+ }
+ memcpy(sanitized_value, value, i);
+ }
+ sanitized_value[i] = '?';
+ }
+ }
+ if (sanitized_value) {
+ syslog(LOG_ERR, "DBus string parameter sanitization"
+ " was invoked");
+ sanitized_value[i] = '\0';
+ ret = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+ &sanitized_value);
+
+ free(sanitized_value);
+ } else {
+ ret = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+ &value);
+ }
+
+ return ret;
+}
+
+static int
+append_config_value(DBusMessageIter *entry, int type,
+ const char *data)
+{
+ int retval;
+ DBusMessageIter var;
+ unsigned char byte;
+ dbus_uint16_t u16;
+ dbus_uint32_t u32;
+ dbus_int16_t i16;
+ dbus_int32_t i32;
+ struct in_addr in;
+
+ retval = -1;
+ switch (type) {
+ case DBUS_TYPE_BOOLEAN:
+ if (*data == '0' || *data == '\0')
+ u32 = 0;
+ else
+ u32 = 1;
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BOOLEAN_AS_STRING, &var);
+ if (dbus_message_iter_append_basic(&var,
+ DBUS_TYPE_BOOLEAN, &u32))
+ retval = 0;
+ break;
+ case DBUS_TYPE_BYTE:
+ byte = strtoul(data, NULL, 0);
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_BYTE_AS_STRING, &var);
+ if (dbus_message_iter_append_basic(&var, DBUS_TYPE_BYTE,
+ &byte))
+ retval = 0;
+ break;
+ case DBUS_TYPE_STRING:
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_STRING_AS_STRING, &var);
+ if (append_sanitized_string(&var, data))
+ retval = 0;
+ break;
+ case DBUS_TYPE_INT16:
+ i16 = strtol(data, NULL, 0);
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_INT16_AS_STRING, &var);
+ if (dbus_message_iter_append_basic(&var,
+ DBUS_TYPE_INT16, &i16))
+ retval = 0;
+ break;
+ case DBUS_TYPE_UINT16:
+ u16 = strtoul(data, NULL, 0);
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_UINT16_AS_STRING, &var);
+ if (dbus_message_iter_append_basic(&var,
+ DBUS_TYPE_UINT16, &u16))
+ retval = 0;
+ break;
+ case DBUS_TYPE_INT32:
+ i32 = strtol(data, NULL, 0);
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_INT32_AS_STRING, &var);
+ if (dbus_message_iter_append_basic(&var,
+ DBUS_TYPE_INT32, &i32))
+ retval = 0;
+ break;
+ case DBUS_TYPE_UINT32:
+ if (strchr(data, '.') != NULL && inet_aton(data, &in) == 1)
+ u32 = in.s_addr;
+ else
+ u32 = strtoul(data, NULL, 0);
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT,
+ DBUS_TYPE_UINT32_AS_STRING, &var);
+ if (dbus_message_iter_append_basic(&var,
+ DBUS_TYPE_UINT32, &u32))
+ retval = 0;
+ break;
+ default:
+ retval = 1;
+ break;
+ }
+ if (retval == 0)
+ dbus_message_iter_close_container(entry, &var);
+ else if (retval == 1)
+ retval = 0;
+
+ return retval;
+}
+
+static int
+append_config_array(DBusMessageIter *entry, int type, const char *data)
+{
+ int retval;
+ char *ns, *p, *tok;
+ const char *tsa, *ts;
+ DBusMessageIter var, array;
+ dbus_bool_t ok;
+ dbus_uint32_t u32;
+ struct in_addr in;
+
+ switch (type) {
+ case DBUS_TYPE_STRING:
+ tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING;
+ ts = DBUS_TYPE_STRING_AS_STRING;
+ break;
+ case DBUS_TYPE_UINT32:
+ tsa = DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_UINT32_AS_STRING;
+ ts = DBUS_TYPE_UINT32_AS_STRING;
+ break;
+ default:
+ return -1;
+ }
+
+ ns = p = strdup(data);
+ if (ns == NULL)
+ return -1;
+ retval = 0;
+
+ dbus_message_iter_open_container(entry, DBUS_TYPE_VARIANT, tsa, &var);
+ dbus_message_iter_open_container(&var, DBUS_TYPE_ARRAY, ts, &array);
+ while ((tok = strsep(&p, " ")) != NULL) {
+ if (*tok == '\0')
+ continue;
+ switch(type) {
+ case DBUS_TYPE_STRING:
+ ok = append_sanitized_string(&array, tok);
+ break;
+ case DBUS_TYPE_UINT32:
+ if (strchr(tok, '.') != NULL &&
+ inet_aton(tok, &in) == 1)
+ u32 = in.s_addr;
+ else
+ u32 = strtoul(tok, NULL, 0);
+ ok = dbus_message_iter_append_basic(&array,
+ DBUS_TYPE_UINT32, &u32);
+ break;
+ default:
+ ok = FALSE;
+ break;
+ }
+ if (!ok)
+ break;
+ }
+ dbus_message_iter_close_container(&var, &array);
+ dbus_message_iter_close_container(entry, &var);
+ free(ns);
+ return retval;
+}
+
+int
+dict_append_config_item(DBusMessageIter *iter, const struct o_dbus *op,
+ const char *data)
+{
+ int retval;
+ DBusMessageIter entry;
+
+ retval = 0;
+ if (*data == '\0')
+ return retval;
+ dbus_message_iter_open_container(iter,
+ DBUS_TYPE_DICT_ENTRY,
+ NULL,
+ &entry);
+ append_sanitized_string(&entry, op->name);
+ if (op->type == DBUS_TYPE_ARRAY)
+ retval = append_config_array(&entry, op->sub_type, data);
+ else
+ retval = append_config_value(&entry, op->type, data);
+ dbus_message_iter_close_container(iter, &entry);
+ return retval;
+}
diff --git a/dbus/dbus-dict.h b/dbus/dbus-dict.h
new file mode 100644
index 0000000..5b558be
--- /dev/null
+++ b/dbus/dbus-dict.h
@@ -0,0 +1,43 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef DBUS_DICT_H
+#define DBUS_DICT_H
+
+#include <dbus/dbus.h>
+
+struct o_dbus {
+ const char *var;
+ int type;
+ int sub_type;
+ const char *name;
+};
+
+int dict_append_config_item(DBusMessageIter *,
+ const struct o_dbus *, const char *);
+
+#endif
diff --git a/dbus/dhcpcd-dbus.conf b/dbus/dhcpcd-dbus.conf
new file mode 100644
index 0000000..766cc59
--- /dev/null
+++ b/dbus/dhcpcd-dbus.conf
@@ -0,0 +1,21 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <!-- Both root and dhcp can own the dhcpcd service -->
+ <policy user="root">
+ <allow own="org.chromium.dhcpcd"/>
+ <allow send_interface="org.chromium.dhcpcd" />
+ <allow send_destination="org.chromium.dhcpcd" />
+ </policy>
+ <policy user="dhcp">
+ <allow own="org.chromium.dhcpcd"/>
+ <allow send_interface="org.chromium.dhcpcd" />
+ <allow send_destination="org.chromium.dhcpcd" />
+ </policy>
+
+ <policy context="default">
+ <allow send_interface="org.chromium.dhcpcd" />
+ <allow send_interface="org.freedesktop.DBus.Introspectable" />
+ <allow send_destination="org.chromium.dhcpcd" />
+</policy>
+</busconfig>
diff --git a/dbus/org.chromium.dhcpcd.in b/dbus/org.chromium.dhcpcd.in
new file mode 100644
index 0000000..f2b01f3
--- /dev/null
+++ b/dbus/org.chromium.dhcpcd.in
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.chromium.dhcpcd
+Exec=@BINDIR@/dhcpcd
+User=root
diff --git a/dbus/rpc-dbus.c b/dbus/rpc-dbus.c
new file mode 100644
index 0000000..cc88356
--- /dev/null
+++ b/dbus/rpc-dbus.c
@@ -0,0 +1,654 @@
+/*
+ * dhcpcd - DHCP client daemon
+ * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+
+#include "../config.h"
+#include "../eloop.h"
+#include "../dhcp.h"
+#include "../rpc-interface.h"
+#include "dbus-dict.h"
+
+#define SERVICE_NAME "org.chromium.dhcpcd"
+#define SERVICE_PATH "/org/chromium/dhcpcd"
+#define S_EINVAL SERVICE_NAME ".InvalidArgument"
+#define S_ARGS "Not enough arguments"
+
+static DBusConnection *connection;
+static struct dhcpcd_ctx *dhcpcd_ctx;
+
+static const char dhcpcd_introspection_xml[] =
+ " <method name=\"GetVersion\">\n"
+ " <arg name=\"version\" direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"Rebind\">\n"
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"Release\">\n"
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+ " <method name=\"Stop\">\n"
+ " <arg name=\"interface\" direction=\"in\" type=\"s\"/>\n"
+ " </method>\n"
+ " <signal name=\"Event\">\n"
+ " <arg name=\"configuration\" type=\"usa{sv}\"/>\n"
+ " </signal>\n"
+ " <signal name=\"StatusChanged\">\n"
+ " <arg name=\"status\" type=\"us\"/>\n"
+ " </signal>\n";
+
+static const char service_watch_rule[] = "interface=" DBUS_INTERFACE_DBUS
+ ",type=signal,member=NameOwnerChanged";
+
+static const char introspection_header_xml[] =
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//"
+ "DTD D-BUS Object Introspection 1.0//EN\"\n"
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+ "<node name=\"" SERVICE_PATH "\">\n"
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"data\" direction=\"out\" type=\"s\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ " <interface name=\"" SERVICE_NAME "\">\n";
+
+static const char introspection_footer_xml[] =
+ " </interface>\n"
+ "</node>\n";
+
+static const struct o_dbus dhos[] = {
+ { "ip_address=", DBUS_TYPE_UINT32, 0, "IPAddress" },
+ { "server_name=", DBUS_TYPE_STRING, 0, "ServerName"},
+ { "subnet_mask=", DBUS_TYPE_UINT32, 0, "SubnetMask" },
+ { "subnet_cidr=", DBUS_TYPE_BYTE, 0, "SubnetCIDR" },
+ { "network_number=", DBUS_TYPE_UINT32, 0, "NetworkNumber" },
+ { "classless_static_routes=", DBUS_TYPE_STRING, 0,
+ "ClasslessStaticRoutes" },
+ { "ms_classless_static_routes=", DBUS_TYPE_STRING, 0,
+ "MSClasslessStaticRoutes" },
+ { "static_routes=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "StaticRoutes"} ,
+ { "routers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "Routers" },
+ { "time_offset=", DBUS_TYPE_UINT32, 0, "TimeOffset" },
+ { "time_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "TimeServers" },
+ { "ien116_name_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "IEN116NameServers" },
+ { "domain_name_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "DomainNameServers" },
+ { "log_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "LogServers" },
+ { "cookie_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "CookieServers" },
+ { "lpr_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "LPRServers" },
+ { "impress_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "ImpressServers" },
+ { "resource_location_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "ResourceLocationServers" },
+ { "host_name=", DBUS_TYPE_STRING, 0, "Hostname" },
+ { "boot_size=", DBUS_TYPE_UINT16, 0, "BootSize" },
+ { "merit_dump=", DBUS_TYPE_STRING, 0, "MeritDump" },
+ { "domain_name=", DBUS_TYPE_STRING, 0, "DomainName" },
+ { "swap_server=", DBUS_TYPE_UINT32, 0, "SwapServer" },
+ { "root_path=", DBUS_TYPE_STRING, 0, "RootPath" },
+ { "extensions_path=", DBUS_TYPE_STRING, 0, "ExtensionsPath" },
+ { "ip_forwarding=", DBUS_TYPE_BOOLEAN, 0, "IPForwarding" },
+ { "non_local_source_routing=", DBUS_TYPE_BOOLEAN, 0,
+ "NonLocalSourceRouting" },
+ { "policy_filter=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "PolicyFilter" },
+ { "max_dgram_reassembly=", DBUS_TYPE_INT16, 0,
+ "MaxDatagramReassembly" },
+ { "default_ip_ttl=", DBUS_TYPE_UINT16, 0, "DefaultIPTTL" },
+ { "path_mtu_aging_timeout=", DBUS_TYPE_UINT32, 0,
+ "PathMTUAgingTimeout" },
+ { "path_mtu_plateau_table=" ,DBUS_TYPE_ARRAY, DBUS_TYPE_UINT16,
+ "PolicyFilter"} ,
+ { "interface_mtu=", DBUS_TYPE_UINT16, 0, "InterfaceMTU" },
+ { "all_subnets_local=", DBUS_TYPE_BOOLEAN, 0, "AllSubnetsLocal" },
+ { "broadcast_address=", DBUS_TYPE_UINT32, 0, "BroadcastAddress" },
+ { "perform_mask_discovery=", DBUS_TYPE_BOOLEAN, 0,
+ "PerformMaskDiscovery" },
+ { "mask_supplier=", DBUS_TYPE_BOOLEAN, 0, "MaskSupplier" },
+ { "router_discovery=", DBUS_TYPE_BOOLEAN, 0, "RouterDiscovery" },
+ { "router_solicitiation_address=", DBUS_TYPE_UINT32, 0,
+ "RouterSolicationAddress" },
+ { "trailer_encapsulation=", DBUS_TYPE_BOOLEAN, 0,
+ "TrailerEncapsulation" },
+ { "arp_cache_timeout=", DBUS_TYPE_UINT32, 0, "ARPCacheTimeout" },
+ { "ieee802_3_encapsulation=", DBUS_TYPE_UINT16, 0,
+ "IEEE8023Encapsulation" },
+ { "default_tcp_ttl=", DBUS_TYPE_BYTE, 0, "DefaultTCPTTL" },
+ { "tcp_keepalive_interval=", DBUS_TYPE_UINT32, 0,
+ "TCPKeepAliveInterval" },
+ { "tcp_keepalive_garbage=", DBUS_TYPE_BOOLEAN, 0,
+ "TCPKeepAliveGarbage" },
+ { "nis_domain=", DBUS_TYPE_STRING, 0, "NISDomain" },
+ { "nis_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NISServers" },
+ { "ntp_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NTPServers" },
+ { "vendor_encapsulated_options=", DBUS_TYPE_STRING, 0,
+ "VendorEncapsulatedOptions" },
+ { "netbios_name_servers=" ,DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "NetBIOSNameServers" },
+ { "netbios_dd_server=", DBUS_TYPE_UINT32, 0, "NetBIOSDDServer" },
+ { "netbios_node_type=", DBUS_TYPE_BYTE, 0, "NetBIOSNodeType" },
+ { "netbios_scope=", DBUS_TYPE_STRING, 0, "NetBIOSScope" },
+ { "font_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "FontServers" },
+ { "x_display_manager=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "XDisplayManager" },
+ { "dhcp_requested_address=", DBUS_TYPE_UINT32, 0,
+ "DHCPRequestedAddress" },
+ { "dhcp_lease_time=", DBUS_TYPE_UINT32, 0, "DHCPLeaseTime" },
+ { "dhcp_option_overload=", DBUS_TYPE_BOOLEAN, 0,
+ "DHCPOptionOverload" },
+ { "dhcp_message_type=", DBUS_TYPE_BYTE, 0, "DHCPMessageType" },
+ { "dhcp_server_identifier=", DBUS_TYPE_UINT32, 0,
+ "DHCPServerIdentifier" },
+ { "dhcp_message=", DBUS_TYPE_STRING, 0, "DHCPMessage" },
+ { "dhcp_max_message_size=", DBUS_TYPE_UINT16, 0,
+ "DHCPMaxMessageSize" },
+ { "dhcp_renewal_time=", DBUS_TYPE_UINT32, 0, "DHCPRenewalTime" },
+ { "dhcp_rebinding_time=", DBUS_TYPE_UINT32, 0, "DHCPRebindingTime" },
+ { "nisplus_domain=", DBUS_TYPE_STRING, 0, "NISPlusDomain" },
+ { "nisplus_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "NISPlusServers" },
+ { "tftp_server_name=", DBUS_TYPE_STRING, 0, "TFTPServerName" },
+ { "bootfile_name=", DBUS_TYPE_STRING, 0, "BootFileName" },
+ { "mobile_ip_home_agent=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "MobileIPHomeAgent" },
+ { "smtp_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "SMTPServer" },
+ { "pop_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "POPServer" },
+ { "nntp_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NNTPServer" },
+ { "www_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "WWWServer" },
+ { "finger_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "FingerServer" },
+ { "irc_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "IRCServer" },
+ { "streettalk_server=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "StreetTalkServer" },
+ { "streettalk_directory_assistance_server=", DBUS_TYPE_ARRAY,
+ DBUS_TYPE_UINT32, "StreetTalkDirectoryAssistanceServer" },
+ { "user_class=", DBUS_TYPE_STRING, 0, "UserClass" },
+ { "new_fqdn_name=", DBUS_TYPE_STRING, 0, "FQDNName" },
+ { "nds_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "NDSServers" },
+ { "nds_tree_name=", DBUS_TYPE_STRING, 0, "NDSTreeName" },
+ { "nds_context=", DBUS_TYPE_STRING, 0, "NDSContext" },
+ { "bcms_controller_names=", DBUS_TYPE_STRING, 0,
+ "BCMSControllerNames" },
+ { "client_last_transaction_time=", DBUS_TYPE_UINT32, 0,
+ "ClientLastTransactionTime" },
+ { "associated_ip=", DBUS_TYPE_UINT32, 0, "AssociatedIP" },
+ { "uap_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, "UAPServers" },
+ { "netinfo_server_address=", DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ "NetinfoServerAddress" },
+ { "netinfo_server_tag=", DBUS_TYPE_STRING, 0, "NetinfoServerTag" },
+ { "default_url=", DBUS_TYPE_STRING, 0, "DefaultURL" },
+ { "subnet_selection=", DBUS_TYPE_UINT32, 0, "SubnetSelection" },
+ { "domain_search=", DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ "DomainSearch" },
+ { "wpad_url=", DBUS_TYPE_STRING, 0, "WebProxyAutoDiscoveryUrl" },
+ { NULL, 0, 0, NULL }
+};
+
+static int
+append_config(DBusMessageIter *iter,
+ const char *prefix, char **env, ssize_t elen)
+{
+ char **eenv, *p;
+ const struct o_dbus *dhop;
+ size_t l, lp;
+ int retval;
+
+ retval = 0;
+ lp = strlen(prefix);
+ for (eenv = env + elen; env < eenv; env++) {
+ p = env[0];
+ for (dhop = dhos; dhop->var; dhop++) {
+ l = strlen(dhop->var);
+ if (strncmp(p, dhop->var, l) == 0) {
+ retval = dict_append_config_item(iter,
+ dhop, p + l);
+ break;
+ }
+ if (strncmp(p, prefix, lp) == 0 &&
+ strncmp(p + lp, dhop->var, l) == 0)
+ {
+ retval = dict_append_config_item(iter,
+ dhop, p + l + lp);
+ break;
+ }
+ }
+ if (retval == -1)
+ break;
+ }
+ return retval;
+}
+
+static DBusHandlerResult
+get_dbus_error(DBusConnection *con, DBusMessage *msg,
+ const char *name, const char *fmt, ...)
+{
+ char buffer[1024];
+ DBusMessage *reply;
+ va_list args;
+
+ va_start(args, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, args);
+ va_end(args);
+ reply = dbus_message_new_error(msg, name, buffer);
+ dbus_connection_send(con, reply, NULL);
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static dbus_bool_t
+dbus_send_message(const struct interface *ifp, const char *reason,
+ const char *prefix, struct dhcp_message *message)
+{
+ const struct if_options *ifo = ifp->options;
+ DBusMessage* msg;
+ DBusMessageIter args, dict;
+ int pid = getpid();
+ char **env = NULL;
+ ssize_t e, elen;
+ int retval;
+ int success = FALSE;
+
+ syslog(LOG_INFO, "event %s on interface %s", reason, ifp->name);
+
+ msg = dbus_message_new_signal(SERVICE_PATH, SERVICE_NAME, "Event");
+ if (msg == NULL) {
+ syslog(LOG_ERR, "failed to make a configure message");
+ return FALSE;
+ }
+ dbus_message_iter_init_append(msg, &args);
+ dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid);
+ dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &reason);
+ dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ &dict);
+ if (prefix == NULL || message == NULL)
+ retval = 0;
+ else {
+ e = dhcp_env(NULL, NULL, message, ifp);
+ if (e > 0) {
+ char *config_prefix = strdup(prefix);
+ if (config_prefix == NULL) {
+ logger(dhcpcd_ctx, LOG_ERR,
+ "Memory exhausted (strdup)");
+ eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+ }
+ char *p = config_prefix + strlen(config_prefix) - 1;
+ if (p >= config_prefix && *p == '_')
+ *p = '\0';
+ env = calloc(e + 1, sizeof(char *));
+ if (env == NULL) {
+ logger(dhcpcd_ctx, LOG_ERR,
+ "Memory exhausted (calloc)");
+ eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+ }
+ elen = dhcp_env(env, config_prefix, message, ifp);
+ free(config_prefix);
+ }
+ retval = append_config(&dict, prefix, env, elen);
+ }
+
+ /* Release memory allocated for env. */
+ if (env) {
+ char **current = env;
+ while (*current)
+ free(*current++);
+ free(env);
+ }
+
+ dbus_message_iter_close_container(&args, &dict);
+ if (retval == 0) {
+ success = dbus_connection_send(connection, msg, NULL);
+ if (!success)
+ syslog(LOG_ERR, "failed to send dhcp to dbus");
+ } else
+ syslog(LOG_ERR, "failed to construct dbus message");
+ dbus_message_unref(msg);
+
+ return success;
+}
+
+static DBusHandlerResult
+introspect(DBusConnection *con, DBusMessage *msg)
+{
+ DBusMessage *reply;
+ char *xml;
+ size_t len;
+
+ len = sizeof(introspection_header_xml) - 1
+ + sizeof(dhcpcd_introspection_xml) - 1
+ + sizeof(introspection_footer_xml) - 1
+ + 1; /* terminal \0 */
+ xml = malloc(len);
+ if (xml == NULL)
+ return DBUS_HANDLER_RESULT_HANDLED;
+ snprintf(xml, len, "%s%s%s",
+ introspection_header_xml,
+ dhcpcd_introspection_xml,
+ introspection_footer_xml);
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &xml,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(con, reply, NULL);
+ dbus_message_unref(reply);
+ free(xml);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+version(DBusConnection *con, DBusMessage *msg, const char *ver)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &ver,
+ DBUS_TYPE_INVALID);
+ dbus_connection_send(con, reply, NULL);
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+dbus_ack(DBusConnection *con, DBusMessage *msg)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ dbus_connection_send(con, reply, NULL);
+ dbus_message_unref(reply);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+msg_handler(DBusConnection *con, DBusMessage *msg, __unused void *data)
+{
+#define IsMethod(msg, method) \
+ dbus_message_is_method_call(msg, SERVICE_NAME, method)
+
+ if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE,
+ "Introspect")) {
+ return introspect(con, msg);
+ } else if (IsMethod(msg, "GetVersion")) {
+ return version(con, msg, VERSION);
+ } else if (IsMethod(msg, "Rebind")) {
+ const char *iface_name;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &iface_name,
+ DBUS_TYPE_INVALID)) {
+ logger(dhcpcd_ctx, LOG_ERR,
+ "Invalid arguments for Rebind");
+ return get_dbus_error(con, msg, S_EINVAL, S_ARGS);
+ }
+ dhcpcd_start_interface(dhcpcd_ctx, iface_name);
+ return dbus_ack(con, msg);
+ } else if (IsMethod(msg, "Release")) {
+ const char *iface_name;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &iface_name,
+ DBUS_TYPE_INVALID)) {
+ logger(dhcpcd_ctx, LOG_ERR,
+ "Invalid arguments for Release");
+ return get_dbus_error(con, msg, S_EINVAL, S_ARGS);
+ }
+ dhcpcd_release_ipv4(dhcpcd_ctx, iface_name);
+ return dbus_ack(con, msg);
+ } else if (IsMethod(msg, "Stop")) {
+ const char *iface_name;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &iface_name,
+ DBUS_TYPE_INVALID)) {
+ logger(dhcpcd_ctx, LOG_ERR,
+ "Invalid arguments for Stop");
+ return get_dbus_error(con, msg, S_EINVAL, S_ARGS);
+ }
+ dhcpcd_stop_interface(dhcpcd_ctx, iface_name);
+ (void) dbus_ack(con, msg);
+ eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+ } else if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL,
+ "Disconnected")) {
+ dhcpcd_stop_interfaces(dhcpcd_ctx);
+ eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+ }
+ return get_dbus_error(con, msg, S_EINVAL, S_ARGS);
+#undef IsMethod
+}
+
+static void
+dbus_handle_event(DBusWatch *watch, int flags)
+{
+ dbus_watch_handle((DBusWatch *)watch, flags);
+
+ if (connection != NULL) {
+ dbus_connection_ref(connection);
+ while (dbus_connection_dispatch(connection) ==
+ DBUS_DISPATCH_DATA_REMAINS)
+ ;
+ dbus_connection_unref(connection);
+ }
+}
+
+static void
+dbus_read_event(void *watch)
+{
+ dbus_handle_event((DBusWatch *)watch, DBUS_WATCH_READABLE);
+}
+
+static void
+dbus_write_event(void *watch)
+{
+ dbus_handle_event((DBusWatch *)watch, DBUS_WATCH_WRITABLE);
+}
+
+static dbus_bool_t
+add_watch(DBusWatch *watch, __unused void *data)
+{
+ int fd, flags;
+ void (*read_event)(void *) = NULL;
+ void *read_arg = NULL;
+ void (*write_event)(void *) = NULL;
+ void *write_arg = NULL;
+
+ fd = dbus_watch_get_unix_fd(watch);
+ flags = dbus_watch_get_flags(watch);
+ if (flags & DBUS_WATCH_READABLE) {
+ read_event = dbus_read_event;
+ read_arg = watch;
+ }
+ if (flags & DBUS_WATCH_WRITABLE) {
+ write_event = dbus_write_event;
+ write_arg = watch;
+ }
+
+ if (eloop_event_add(dhcpcd_ctx->eloop, fd, read_event, read_arg,
+ write_event, write_arg) == 0)
+ return TRUE;
+ return FALSE;
+}
+
+static void
+remove_watch(DBusWatch *watch, __unused void *data)
+{
+ int fd, flags;
+ int write_only = 0;
+ fd = dbus_watch_get_unix_fd(watch);
+ flags = dbus_watch_get_flags(watch);
+ if (!(flags & DBUS_WATCH_READABLE) && (flags & DBUS_WATCH_WRITABLE))
+ write_only = 1;
+ eloop_event_delete(dhcpcd_ctx->eloop, fd, write_only);
+}
+
+static DBusHandlerResult
+dhcpcd_dbus_filter(DBusConnection *conn, DBusMessage *msg, void *user_data)
+{
+ const char *service = NULL;
+ const char *old_owner = NULL;
+ const char *new_owner = NULL;
+
+ if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
+ "NameOwnerChanged"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &service,
+ DBUS_TYPE_STRING, &old_owner,
+ DBUS_TYPE_STRING, &new_owner,
+ DBUS_TYPE_INVALID)) {
+ syslog(LOG_ERR,
+ "Invalid arguments for NameOwnerChanged signal");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ if (strcmp(service, "org.chromium.flimflam") == 0 &&
+ strlen(new_owner) == 0) {
+ syslog(LOG_INFO, "exiting because shill has died");
+ dhcpcd_stop_interfaces(dhcpcd_ctx);
+ eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+ }
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+int
+rpc_init(struct dhcpcd_ctx *ctx)
+{
+ DBusObjectPathVTable vt = {
+ NULL, &msg_handler, NULL, NULL, NULL, NULL
+ };
+ DBusError err;
+ int ret;
+
+ dhcpcd_ctx = ctx;
+
+ dbus_error_init(&err);
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (connection == NULL) {
+ if (dbus_error_is_set(&err))
+ syslog(LOG_ERR, "%s", err.message);
+ else
+ syslog(LOG_ERR, "failed to get a dbus connection");
+ return -1;
+ }
+ atexit(rpc_close);
+
+ if (!dbus_connection_set_watch_functions(connection,
+ add_watch, remove_watch, NULL, NULL, NULL))
+ {
+ syslog(LOG_ERR, "dbus: failed to set watch functions");
+ return -1;
+ }
+ if (!dbus_connection_register_object_path(connection,
+ SERVICE_PATH, &vt, NULL))
+ {
+ syslog(LOG_ERR, "dbus: failed to register object path");
+ return -1;
+ }
+ dbus_connection_add_filter(connection, dhcpcd_dbus_filter, NULL, NULL);
+ dbus_bus_add_match(connection, service_watch_rule, &err);
+ if (dbus_error_is_set(&err)) {
+ syslog(LOG_ERR, "Cannot add rule: %s", err.message);
+ return -1;
+ }
+ return 0;
+}
+
+void
+rpc_close(void)
+{
+ if (connection) {
+ dbus_bus_remove_match(connection, service_watch_rule, NULL);
+ dbus_connection_remove_filter(connection,
+ dhcpcd_dbus_filter,
+ NULL);
+ dbus_connection_unref(connection);
+ connection = NULL;
+ }
+}
+
+void
+rpc_signal_status(const char *status)
+{
+ DBusMessage *msg;
+ DBusMessageIter args;
+ int pid = getpid();
+
+ syslog(LOG_INFO, "status changed to %s", status);
+
+ msg = dbus_message_new_signal(SERVICE_PATH, SERVICE_NAME,
+ "StatusChanged");
+ if (msg == NULL) {
+ syslog(LOG_ERR, "failed to make a status changed message");
+ return;
+ }
+ dbus_message_iter_init_append(msg, &args);
+ dbus_message_iter_append_basic(&args, DBUS_TYPE_UINT32, &pid);
+ dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &status);
+ if (!dbus_connection_send(connection, msg, NULL))
+ syslog(LOG_ERR, "failed to send status to dbus");
+ dbus_message_unref(msg);
+}
+
+
+int
+rpc_update_ipv4(struct interface *ifp)
+{
+ struct dhcp_state *state = D_STATE(ifp);
+ if (state->new != NULL) {
+ /* push state over d-bus */
+ dbus_send_message(ifp, state->reason, "new_", state->new);
+ rpc_signal_status("Bound");
+ } else {
+ rpc_signal_status("Release");
+ }
+ return 0;
+}
+
+int
+rpc_update_ipv6(struct interface *ifp)
+{
+ /* Currently not supported. */
+ return 0;
+}
+
+int
+rpc_notify_unicast_arp(struct interface *ifp) {
+ struct dhcp_state *state = D_STATE(ifp);
+ return dbus_send_message(ifp, "GATEWAY-ARP", "saved_", state->offer);
+}
diff --git a/dbus/test/introspection b/dbus/test/introspection
new file mode 100755
index 0000000..772a1db
--- /dev/null
+++ b/dbus/test/introspection
@@ -0,0 +1,9 @@
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+object = dbus.Interface(bus.get_object("org.chromium.dhcpcd", '/'),
+ "org.freedesktop.DBus.Introspectable")
+print object.Introspect()
diff --git a/dbus/test/monitor b/dbus/test/monitor
new file mode 100755
index 0000000..11d17b8
--- /dev/null
+++ b/dbus/test/monitor
@@ -0,0 +1,19 @@
+#!/usr/bin/python
+
+import gobject
+import dbus
+import dbus.mainloop.glib
+
+def event(pid, reason, value):
+ print "pid %s %s: %s" % (pid, reason, value)
+
+if __name__ == '__main__':
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ bus.add_signal_receiver(event, bus_name="org.chromium.dhcpcd",
+ signal_name = "Event")
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
diff --git a/dhcp-common.c b/dhcp-common.c
index 05d2cdb..70e76ce 100644
--- a/dhcp-common.c
+++ b/dhcp-common.c
@@ -734,6 +734,8 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
return bytes;
}
+/* Lease file name is formatted according to the expectation of the ChromiumOS's
+ * connection manager (shill). */
int
dhcp_set_leasefile(char *leasefile, size_t len, int family,
const struct interface *ifp, const char *extra)
@@ -746,32 +748,13 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family,
}
if (strlen(ifp->lease_identifier) > 0) {
- /* Only supports lease identifier for IPv4 for now. */
- if (family == AF_INET) {
- return snprintf(leasefile, len, LEASEFILE,
- ifp->lease_identifier, "", "");
- }
+ return snprintf(leasefile, len,
+ family == AF_INET ? LEASEFILE : LEASEFILE6,
+ ifp->lease_identifier, "", "");
}
-
- switch (family) {
- case AF_INET:
- case AF_INET6:
- break;
- default:
- errno = EINVAL;
- return -1;
- }
-
- if (ifp->wireless) {
- ssid[0] = '-';
- print_string(ssid + 1, sizeof(ssid) - 1,
- ESCFILE,
- (const uint8_t *)ifp->ssid, ifp->ssid_len);
- } else
- ssid[0] = '\0';
return snprintf(leasefile, len,
- family == AF_INET ? LEASEFILE : LEASEFILE6,
- ifp->name, ssid, extra);
+ family == AF_INET ? LEASEFILE : LEASEFILE,
+ ifp->name, "", "");
}
static size_t
diff --git a/dhcp.c b/dhcp.c
index f674ff2..9fd2b40 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -1660,11 +1660,11 @@ send_message(struct interface *ifp, uint8_t type,
state->xid);
else {
if (state->interval == 0)
- state->interval = 4;
+ state->interval = DHCP_BASE;
else {
state->interval *= 2;
- if (state->interval > 64)
- state->interval = 64;
+ if (state->interval > DHCP_MAX)
+ state->interval = DHCP_MAX;
}
tv.tv_sec = state->interval + DHCP_RAND_MIN;
tv.tv_nsec = (suseconds_t)arc4random_uniform(
@@ -2432,7 +2432,8 @@ dhcp_drop(struct interface *ifp, const char *reason)
dhcp_close(ifp);
}
- if (ifp->options->options & DHCPCD_RELEASE) {
+ if (ifp->options->options & DHCPCD_RELEASE ||
+ strcmp(reason, "RELEASE") == 0) {
unlink(state->leasefile);
if (ifp->carrier != LINK_DOWN &&
state->new != NULL &&
diff --git a/dhcpcd-definitions.conf b/dhcpcd-definitions.conf
index 0e5aa3b..ad37c2b 100644
--- a/dhcpcd-definitions.conf
+++ b/dhcpcd-definitions.conf
@@ -58,7 +58,7 @@ define 39 byte tcp_keepalive_garbage
define 40 string nis_domain
define 41 array ipaddress nis_servers
define 42 array ipaddress ntp_servers
-define 43 binhex vendor_encapsulated_options
+define 43 string vendor_encapsulated_options
define 44 array ipaddress netbios_name_servers
define 45 ipaddress netbios_dd_server
define 46 byte netbios_node_type
diff --git a/dhcpcd.c b/dhcpcd.c
index a486ac2..b36cdc7 100644
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -1031,6 +1031,58 @@ dhcpcd_handlehwaddr(struct dhcpcd_ctx *ctx, const char *ifname,
memcpy(ifp->hwaddr, hwaddr, hwlen);
}
+void
+dhcpcd_start_interface(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+ struct interface *ifp;
+ ifp = if_find(ctx->ifaces, ifname);
+ if (ifp == NULL)
+ {
+ logger(ctx, LOG_ERR, "start_interface: %s not found",
+ ifname);
+ return;
+ }
+ dhcpcd_startinterface(ifp);
+}
+
+void
+dhcpcd_stop_interface(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+ struct interface *ifp;
+ ifp = if_find(ctx->ifaces, ifname);
+ if (ifp == NULL)
+ {
+ logger(ctx, LOG_ERR, "stop_interface: %s not found",
+ ifname);
+ return;
+ }
+ stop_interface(ifp);
+}
+
+void
+dhcpcd_stop_interfaces(struct dhcpcd_ctx *ctx)
+{
+ struct interface *ifp;
+ TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+ stop_interface(ifp);
+ }
+}
+
+void
+dhcpcd_release_ipv4(struct dhcpcd_ctx *ctx, const char *ifname)
+{
+ struct interface *ifp;
+
+ ifp = if_find(ctx->ifaces, ifname);
+ if (ifp == NULL)
+ {
+ logger(ctx, LOG_ERR, "IPv4 release: %s not found",
+ ifname);
+ return;
+ }
+ dhcp_drop(ifp, "RELEASE");
+}
+
static void
if_reboot(struct interface *ifp, int argc, char **argv)
{
@@ -1264,13 +1316,13 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd,
* write callback on the fd */
if (strcmp(*argv, "--version") == 0) {
return control_queue(fd, UNCONST(VERSION),
- strlen(VERSION) + 1, 0);
+ strlen(VERSION) + 1, 0);
} else if (strcmp(*argv, "--getconfigfile") == 0) {
return control_queue(fd, UNCONST(fd->ctx->cffile),
- strlen(fd->ctx->cffile) + 1, 0);
+ strlen(fd->ctx->cffile) + 1, 0);
} else if (strcmp(*argv, "--getinterfaces") == 0) {
eloop_event_add(fd->ctx->eloop, fd->fd, NULL, NULL,
- dhcpcd_getinterfaces, fd);
+ dhcpcd_getinterfaces, fd);
return 0;
} else if (strcmp(*argv, "--listen") == 0) {
fd->flags |= FD_LISTEN;
diff --git a/dhcpcd.conf b/dhcpcd.conf
index e5a19cd..3837feb 100644
--- a/dhcpcd.conf
+++ b/dhcpcd.conf
@@ -1,6 +1,12 @@
# A sample configuration for dhcpcd.
# See dhcpcd.conf(5) for details.
+# Disabling ARP checking
+noarp
+
+# Disabling link state monitoring
+nolink
+
# Allow users of this group to interact with dhcpcd via the control socket.
#controlgroup wheel
@@ -8,36 +14,36 @@
hostname
# Use the hardware address of the interface for the Client ID.
-#clientid
+clientid
# or
# Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361.
# Some non-RFC compliant DHCP servers do not reply with this set.
# In this case, comment out duid and enable clientid above.
-duid
+#duid
# Persist interface configuration when dhcpcd exits.
-persistent
+#persistent
# Rapid commit support.
# Safe to enable by default because it requires the equivalent option set
# on the server to actually work.
-option rapid_commit
+#option rapid_commit
# A list of options to request from the DHCP server.
-option domain_name_servers, domain_name, domain_search, host_name
+option domain_name_servers, domain_name, domain_search, host_name, wpad_url
option classless_static_routes
# Most distributions have NTP support.
-option ntp_servers
+#option ntp_servers
# Respect the network MTU.
# Some interface drivers reset when changing the MTU so disabled by default.
-#option interface_mtu
+option interface_mtu
# A ServerID is required by RFC2131.
require dhcp_server_identifier
# Generate Stable Private IPv6 Addresses instead of hardware based ones
-slaac private
+#slaac private
# A hook script is provided to lookup the hostname if not set by the DHCP
# server, but it should not be run by default.
-nohook lookup-hostname
+#nohook lookup-hostname
diff --git a/dhcpcd.h b/dhcpcd.h
index ae2b0ce..b8c961e 100644
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -177,4 +177,9 @@ int dhcpcd_selectprofile(struct interface *, const char *);
void dhcpcd_startinterface(void *);
void dhcpcd_initstate(struct interface *, unsigned long long);
+void dhcpcd_start_interface(struct dhcpcd_ctx *, const char *);
+void dhcpcd_stop_interface(struct dhcpcd_ctx *, const char *);
+void dhcpcd_release_ipv4(struct dhcpcd_ctx *, const char *);
+void dhcpcd_stop_interfaces(struct dhcpcd_ctx *);
+
#endif
--
2.2.0.rc0.207.ga3a616c