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