blob: dc9f5bb571ad64a1a01789b6998d2fb3031b47e4 [file] [log] [blame]
From 98f89ca39060eb3bffb9140f7dacad69d7a9a432 Mon Sep 17 00:00:00 2001
From: Peter Qiu <zqiu@chromium.org>
Date: Fri, 11 Jun 2021 13:14:35 +0000
Subject: [PATCH 13/19] 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
---
configure | 12 +
src/Makefile | 25 +-
src/dbus/dbus-dict.c | 249 ++++++++++++
src/dbus/dbus-dict.h | 43 +++
src/dbus/dhcpcd-dbus.conf | 21 ++
src/dbus/org.chromium.dhcpcd.in | 4 +
src/dbus/rpc-dbus.c | 649 ++++++++++++++++++++++++++++++++
src/dbus/test/introspection | 9 +
src/dbus/test/monitor | 19 +
src/dhcp-common.c | 32 +-
src/dhcp.c | 9 +-
src/dhcpcd-definitions.conf | 2 +-
src/dhcpcd.c | 55 ++-
src/dhcpcd.conf | 18 +-
src/dhcpcd.h | 5 +
src/if-linux.c | 3 +
src/logerr.c | 2 +-
17 files changed, 1113 insertions(+), 44 deletions(-)
create mode 100644 src/dbus/dbus-dict.c
create mode 100644 src/dbus/dbus-dict.h
create mode 100644 src/dbus/dhcpcd-dbus.conf
create mode 100644 src/dbus/org.chromium.dhcpcd.in
create mode 100644 src/dbus/rpc-dbus.c
create mode 100755 src/dbus/test/introspection
create mode 100755 src/dbus/test/monitor
diff --git a/configure b/configure
index 66a96040..76a33788 100755
--- a/configure
+++ b/configure
@@ -31,6 +31,7 @@ AUTH=
POLL=
SMALL=
STATUSARG=
+DBUS=
DHCPCD_DEFS=dhcpcd-definitions.conf
@@ -63,6 +64,8 @@ for x do
--enable-embedded) EMBEDDED=yes;;
--disable-auth) AUTH=no;;
--enable-auth) AUTH=yes;;
+ --enable-dbus) DBUS=yes;;
+ --disable-dbus) DBUS=no;;
--prefix) PREFIX=$var;;
--sysconfdir) SYSCONFDIR=$var;;
--bindir|--sbindir) SBINDIR=$var;;
@@ -503,6 +506,15 @@ if [ -z "$INET6" -o "$INET6" = yes -o -z "$AUTH" -o "$AUTH" = yes ]; then
echo "CRYPT_SRCS+= \${MD5_SRC} \${SHA256_SRC}" >>$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
+
echo "Using compiler .. $CC"
# Add CPPFLAGS and CFLAGS to CC for testing features
XCC="$CC `$SED -n -e 's/CPPFLAGS+=*\(.*\)/\1/p' $CONFIG_MK`"
diff --git a/src/Makefile b/src/Makefile
index d5b100a8..4b280ea0 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -3,7 +3,8 @@
PROG= dhcpcd
SRCS= common.c control.c dhcpcd.c duid.c eloop.c logerr.c
SRCS+= if.c if-options.c sa.c route.c
-SRCS+= dhcp-common.c rpc-stub.c
+SRCS+= dhcp-common.c
+PKG_CONFIG ?= pkg-config
CFLAGS?= -O2
SUBDIRS+= ${MKDIRS}
@@ -29,6 +30,17 @@ CLEANFILES= dhcpcd.conf.5 dhcpcd.8
FILES= dhcpcd.conf
FILESDIR= ${SYSCONFDIR}
+ifeq ($(DBUS_SUPPORT),yes)
+FILES+= dbus/dhcpcd-dbus.conf
+
+DBUSCFLAGS := $(shell $(PKG_CONFIG) --cflags dbus-1)
+DBUSLIBS := $(shell $(PKG_CONFIG) --libs dbus-1)
+DBUSDIR= ${SYSCONFDIR}/dbus-1/system.d
+
+CFLAGS+= ${DBUSCFLAGS}
+LDADD+= ${DBUSLIBS}
+endif
+
DEPEND!= test -e .depend && echo ".depend" || echo ""
CLEANFILES+= *.tar.xz
@@ -44,7 +56,7 @@ CLEANFILES+= *.tar.xz
${SED_STATUSARG} \
$< > $@
-all: ${TOP}/config.h ${PROG} ${SCRIPTS} ${MAN5} ${MAN8}
+all: ${TOP}/config.h ${PROG} ${SCRIPTS} ${MAN5} ${MAN8} ${FILES}
for x in ${SUBDIRS}; do cd $$x; ${MAKE} $@ || exit $$?; cd ..; done
dev:
@@ -92,7 +104,12 @@ _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}
# Install a new default config if not present
test -e ${DESTDIR}${SYSCONFDIR}/dhcpcd.conf || \
@@ -126,7 +143,7 @@ _confinstall:
eginstall:
-install: proginstall _maninstall _confinstall eginstall
+install: proginstall _confinstall eginstall
clean:
rm -f ${OBJS} ${PROG} ${PROG}.core ${CLEANFILES}
diff --git a/src/dbus/dbus-dict.c b/src/dbus/dbus-dict.c
new file mode 100644
index 00000000..8e3cf4e4
--- /dev/null
+++ b/src/dbus/dbus-dict.c
@@ -0,0 +1,249 @@
+/*
+ * 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;
+ size_t i, len = strlen(value);
+ char *sanitized_value = NULL;
+
+ 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/src/dbus/dbus-dict.h b/src/dbus/dbus-dict.h
new file mode 100644
index 00000000..735f2592
--- /dev/null
+++ b/src/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/src/dbus/dhcpcd-dbus.conf b/src/dbus/dhcpcd-dbus.conf
new file mode 100644
index 00000000..766cc598
--- /dev/null
+++ b/src/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/src/dbus/org.chromium.dhcpcd.in b/src/dbus/org.chromium.dhcpcd.in
new file mode 100644
index 00000000..f2b01f38
--- /dev/null
+++ b/src/dbus/org.chromium.dhcpcd.in
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.chromium.dhcpcd
+Exec=@BINDIR@/dhcpcd
+User=root
diff --git a/src/dbus/rpc-dbus.c b/src/dbus/rpc-dbus.c
new file mode 100644
index 00000000..bea71b22
--- /dev/null
+++ b/src/dbus/rpc-dbus.c
@@ -0,0 +1,649 @@
+/*
+ * 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 <unistd.h>
+
+#include <dbus/dbus.h>
+
+#include "../config.h"
+#include "../eloop.h"
+#include "../dhcp.h"
+#include "../logerr.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 bootp *bootp, size_t bootp_len)
+{
+ DBusMessage* msg;
+ DBusMessageIter args, dict;
+ int pid = getpid();
+ char **env = NULL;
+ ssize_t e, elen = 0;
+ int retval;
+ int success = FALSE;
+
+ loginfox("event %s on interface %s", reason, ifp->name);
+
+ msg = dbus_message_new_signal(SERVICE_PATH, SERVICE_NAME, "Event");
+ if (msg == NULL) {
+ logerrx("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 || bootp == NULL)
+ retval = 0;
+ else {
+ e = dhcp_env(NULL, NULL, bootp, bootp_len, ifp);
+ if (e > 0) {
+ char *config_prefix = strdup(prefix);
+ if (config_prefix == NULL) {
+ logerrx("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) {
+ logerrx("Memory exhausted (calloc)");
+ eloop_exit(dhcpcd_ctx->eloop, EXIT_FAILURE);
+ }
+ elen = dhcp_env(env, config_prefix,
+ bootp, bootp_len, 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)
+ logerrx("failed to send dhcp to dbus");
+ } else
+ logerrx("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)) {
+ logerrx("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)) {
+ logerrx("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)) {
+ logerrx("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_rw(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_write(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)) {
+ logerrx("Invalid arguments for NameOwnerChanged signal");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ if (strcmp(service, "org.chromium.flimflam") == 0 &&
+ strlen(new_owner) == 0) {
+ loginfox("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;
+
+ dhcpcd_ctx = ctx;
+
+ dbus_error_init(&err);
+ connection = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (connection == NULL) {
+ if (dbus_error_is_set(&err))
+ logerrx("%s", err.message);
+ else
+ logerrx("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))
+ {
+ logerrx("dbus: failed to set watch functions");
+ return -1;
+ }
+ if (!dbus_connection_register_object_path(connection,
+ SERVICE_PATH, &vt, NULL))
+ {
+ logerrx("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)) {
+ logerrx("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();
+
+ loginfox("status changed to %s", status);
+
+ msg = dbus_message_new_signal(SERVICE_PATH, SERVICE_NAME,
+ "StatusChanged");
+ if (msg == NULL) {
+ logerrx("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))
+ logerrx("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, state->new_len);
+ 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, state->offer_len);
+}
diff --git a/src/dbus/test/introspection b/src/dbus/test/introspection
new file mode 100755
index 00000000..772a1db7
--- /dev/null
+++ b/src/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/src/dbus/test/monitor b/src/dbus/test/monitor
new file mode 100755
index 00000000..11d17b83
--- /dev/null
+++ b/src/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/src/dhcp-common.c b/src/dhcp-common.c
index b9b6fbbb..2c062afe 100644
--- a/src/dhcp-common.c
+++ b/src/dhcp-common.c
@@ -831,44 +831,26 @@ print_option(char *s, size_t len, const struct dhcp_opt *opt,
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)
{
- char ssid[1 + (IF_SSIDLEN * 4) + 1]; /* - prefix and NUL terminated. */
-
if (ifp->name[0] == '\0') {
strlcpy(leasefile, ifp->ctx->pidfile, len);
return 0;
}
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,
- OT_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);
+ family == AF_INET ? LEASEFILE : LEASEFILE6,
+ ifp->name, "");
}
static size_t
diff --git a/src/dhcp.c b/src/dhcp.c
index c03c0904..c8ec40da 100644
--- a/src/dhcp.c
+++ b/src/dhcp.c
@@ -1841,11 +1841,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(
@@ -3079,7 +3079,8 @@ dhcp_drop(struct interface *ifp, const char *reason)
#ifdef ARPING
state->arping_index = -1;
#endif
- if (ifp->options->options & DHCPCD_RELEASE &&
+ if ((ifp->options->options & DHCPCD_RELEASE ||
+ strcmp(reason, "RELEASE") == 0) &&
!(ifp->options->options & DHCPCD_INFORM))
{
/* Failure to send the release may cause this function to
diff --git a/src/dhcpcd-definitions.conf b/src/dhcpcd-definitions.conf
index df4075e8..f9205956 100644
--- a/src/dhcpcd-definitions.conf
+++ b/src/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/src/dhcpcd.c b/src/dhcpcd.c
index bba72a3d..a0bd69dd 100644
--- a/src/dhcpcd.c
+++ b/src/dhcpcd.c
@@ -1178,6 +1178,55 @@ 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)
+ {
+ logerrx("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)
+ {
+ logerrx("stop_interface: %s not found", ifname);
+ return;
+ }
+ stop_interface(ifp);
+}
+
+void
+dhcpcd_stop_interfaces(struct dhcpcd_ctx *ctx)
+{
+ struct interface *ifp, *ifn;
+ TAILQ_FOREACH_SAFE(ifp, ctx->ifaces, next, ifn) {
+ 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)
+ {
+ logerrx("IPv4 release: %s not found", ifname);
+ return;
+ }
+ dhcp_drop(ifp, "RELEASE");
+}
+
static void
if_reboot(struct interface *ifp, int argc, char **argv)
{
@@ -1409,13 +1458,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_w(fd->ctx->eloop, fd->fd,
- dhcpcd_getinterfaces, fd);
+ dhcpcd_getinterfaces, fd);
return 0;
} else if (strcmp(*argv, "--listen") == 0) {
fd->flags |= FD_LISTEN;
diff --git a/src/dhcpcd.conf b/src/dhcpcd.conf
index 537ed77b..d7ba8c9a 100644
--- a/src/dhcpcd.conf
+++ b/src/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,23 +14,23 @@
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
# Respect the network MTU. This is applied to DHCP routes.
option interface_mtu
@@ -38,4 +44,4 @@ require dhcp_server_identifier
# Generate SLAAC address using the Hardware Address of the interface
#slaac hwaddr
# OR generate Stable Private IPv6 Addresses based from the DUID
-slaac private
+#slaac private
diff --git a/src/dhcpcd.h b/src/dhcpcd.h
index 5adafc68..263102f3 100644
--- a/src/dhcpcd.h
+++ b/src/dhcpcd.h
@@ -229,4 +229,9 @@ int dhcpcd_selectprofile(struct interface *, const char *);
void dhcpcd_startinterface(void *);
void dhcpcd_activateinterface(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
diff --git a/src/if-linux.c b/src/if-linux.c
index f4437859..e3cc257e 100644
--- a/src/if-linux.c
+++ b/src/if-linux.c
@@ -1698,6 +1698,9 @@ static const char *prefix = "/proc/sys/net/ipv6/conf";
void
if_setup_inet6(const struct interface *ifp)
{
+#ifdef PASSIVE_MODE
+ return;
+#endif
int ra;
char path[256];
diff --git a/src/logerr.c b/src/logerr.c
index afef8d1b..9e543cc9 100644
--- a/src/logerr.c
+++ b/src/logerr.c
@@ -329,7 +329,7 @@ logopen(const char *path)
struct logctx *ctx = &_logctx;
if (path == NULL) {
- int opts = 0;
+ int opts = LOG_PERROR;
if (ctx->log_opts & LOGERR_LOG_PID)
opts |= LOG_PID;
--
2.33.0.800.g4c38ced690-goog