diff options
author | Samuel Tan <samueltan@google.com> | 2015-08-13 17:14:37 -0700 |
---|---|---|
committer | Samuel Tan <samueltan@google.com> | 2015-08-18 13:47:25 -0700 |
commit | e942e091ac1efb0ee1916add2b12f64fdfd59476 (patch) | |
tree | 2df4f9148d7884d3156eb02e3a56f4fba8902870 | |
parent | 24aa62eefd9284fb94820093f6088607d42c4249 (diff) | |
download | dhcpcd-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-- | Makefile | 40 | ||||
-rw-r--r-- | common.c | 2 | ||||
-rwxr-xr-x | configure | 12 | ||||
-rw-r--r-- | dbus/dbus-dict.c | 250 | ||||
-rw-r--r-- | dbus/dbus-dict.h | 43 | ||||
-rw-r--r-- | dbus/dhcpcd-dbus.conf | 21 | ||||
-rw-r--r-- | dbus/org.chromium.dhcpcd.in | 4 | ||||
-rw-r--r-- | dbus/rpc-dbus.c | 654 | ||||
-rwxr-xr-x | dbus/test/introspection | 9 | ||||
-rwxr-xr-x | dbus/test/monitor | 19 | ||||
-rw-r--r-- | dhcp-common.c | 31 | ||||
-rw-r--r-- | dhcp.c | 9 | ||||
-rw-r--r-- | dhcpcd-definitions.conf | 2 | ||||
-rw-r--r-- | dhcpcd.c | 58 | ||||
-rw-r--r-- | dhcpcd.conf | 24 | ||||
-rw-r--r-- | dhcpcd.h | 5 |
16 files changed, 1136 insertions, 47 deletions
@@ -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} @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 |