aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Tan <samueltan@google.com>2015-08-13 17:14:37 -0700
committerSamuel Tan <samueltan@google.com>2015-08-18 13:47:25 -0700
commite942e091ac1efb0ee1916add2b12f64fdfd59476 (patch)
tree2df4f9148d7884d3156eb02e3a56f4fba8902870
parent24aa62eefd9284fb94820093f6088607d42c4249 (diff)
downloaddhcpcd-6.8.2-e942e091ac1efb0ee1916add2b12f64fdfd59476.tar.gz
[PATCH] Add DBus RPC support
Cherry-picked from https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/ master/net-misc/dhcpcd/files/patches/dhcpcd-6.8.2-Add-DBus-RPC-support.patch. 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. BUG: 22956197 Change-Id: Ic729dffc6b14fed0b27ed0731c11ef609434e03c 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
-rw-r--r--Makefile40
-rw-r--r--common.c2
-rwxr-xr-xconfigure12
-rw-r--r--dbus/dbus-dict.c250
-rw-r--r--dbus/dbus-dict.h43
-rw-r--r--dbus/dhcpcd-dbus.conf21
-rw-r--r--dbus/org.chromium.dhcpcd.in4
-rw-r--r--dbus/rpc-dbus.c654
-rwxr-xr-xdbus/test/introspection9
-rwxr-xr-xdbus/test/monitor19
-rw-r--r--dhcp-common.c31
-rw-r--r--dhcp.c9
-rw-r--r--dhcpcd-definitions.conf2
-rw-r--r--dhcpcd.c58
-rw-r--r--dhcpcd.conf24
-rw-r--r--dhcpcd.h5
16 files changed, 1136 insertions, 47 deletions
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);
+ exit(EXIT_FAILURE);
+ } else if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL,
+ "Disconnected")) {
+ dhcpcd_stop_interfaces(dhcpcd_ctx);
+ exit(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 flimflamd has died");
+ dhcpcd_stop_interfaces(dhcpcd_ctx);
+ exit(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 32bced4..5bb16b9 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