diff options
author | Samuel Tan <samueltan@google.com> | 2015-08-13 17:19:52 -0700 |
---|---|---|
committer | Samuel Tan <samueltan@google.com> | 2015-08-18 13:47:29 -0700 |
commit | 8e603a0d0354b88712f1a81cc48dbd9936244fd5 (patch) | |
tree | ee6f293bdc8768105d44442e6d1a27c8c58d15a3 | |
parent | e942e091ac1efb0ee1916add2b12f64fdfd59476 (diff) | |
download | dhcpcd-6.8.2-8e603a0d0354b88712f1a81cc48dbd9936244fd5.tar.gz |
[PATCH] ChromiumOS DHCPv6 support
Cherry-picked from
https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/
master/net-misc/dhcpcd/files/patches/dhcpcd-6.8.2-ChromiumOS-DHCPv6-
support.patch.
Add support to emit DHCPv6 configuration/status updates through
DBus, and prevent the daemon from updating IPv6 system configurations.
Add command line option "-a" to enable ia options for shill usage,
since ia options can only be specified through the config file by
default. When "-a" option is enabled, the daemon will request ia_na
(Non-temporary Address) and ia_pd (Prefix Delegation) options from
the DHCPv6 server.
BUG: 22956197
Change-Id: I12ba8e72ec4f2e8aa1cede6c717f477be2df20ea
Reviewed-on: https://chromium-review.googlesource.com/275700
-rw-r--r-- | dbus/rpc-dbus.c | 109 | ||||
-rw-r--r-- | dhcp-common.c | 2 | ||||
-rw-r--r-- | dhcp6.c | 12 | ||||
-rw-r--r-- | dhcpcd.conf | 3 | ||||
-rw-r--r-- | if-options.c | 39 | ||||
-rw-r--r-- | if-options.h | 2 | ||||
-rw-r--r-- | ipv6.c | 6 | ||||
-rw-r--r-- | rpc-interface.h | 2 | ||||
-rw-r--r-- | rpc-stub.c | 2 |
9 files changed, 174 insertions, 3 deletions
diff --git a/dbus/rpc-dbus.c b/dbus/rpc-dbus.c index cc88356..ea380c4 100644 --- a/dbus/rpc-dbus.c +++ b/dbus/rpc-dbus.c @@ -39,6 +39,9 @@ #include "../config.h" #include "../eloop.h" #include "../dhcp.h" +#ifdef INET6 +#include "../dhcp6.h" +#endif #include "../rpc-interface.h" #include "dbus-dict.h" @@ -217,6 +220,23 @@ static const struct o_dbus dhos[] = { { "domain_search=", DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, "DomainSearch" }, { "wpad_url=", DBUS_TYPE_STRING, 0, "WebProxyAutoDiscoveryUrl" }, +#ifdef INET6 + { "dhcp6_server_id=", DBUS_TYPE_STRING, 0, + "DHCPv6ServerIdentifier" }, + { "dhcp6_ia_na1_ia_addr1=", DBUS_TYPE_STRING, 0, "DHCPv6Address" }, + { "dhcp6_ia_na1_ia_addr1_vltime=", DBUS_TYPE_UINT32, 0, + "DHCPv6AddressLeaseTime" }, + { "dhcp6_name_servers=", DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, + "DHCPv6NameServers" }, + { "dhcp6_domain_search=", DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, + "DHCPv6DomainSearch" }, + { "dhcp6_ia_pd1_prefix1=", DBUS_TYPE_STRING, 0, + "DHCPv6DelegatedPrefix" }, + { "dhcp6_ia_pd1_prefix1_length=", DBUS_TYPE_UINT32, 0, + "DHCPv6DelegatedPrefixLength" }, + { "dhcp6_ia_pd1_prefix1_vltime=", DBUS_TYPE_UINT32, 0, + "DHCPv6DelegatedPrefixLeaseTime" }, +#endif { NULL, 0, 0, NULL } }; @@ -346,6 +366,83 @@ dbus_send_message(const struct interface *ifp, const char *reason, return success; } +#ifdef INET6 +static dbus_bool_t +dbus_send_dhcpv6_message(const struct interface *ifp, const char *reason, + const char *prefix, struct dhcp6_message *message, size_t length) +{ + 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 = dhcp6_env(NULL, NULL, ifp, message, length); + 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 = dhcp6_env(env, "new", ifp, message, length); + 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 dhcpv6 to dbus"); + } else + syslog(LOG_ERR, "failed to construct dbus message"); + dbus_message_unref(msg); + + return success; +} +#endif + static DBusHandlerResult introspect(DBusConnection *con, DBusMessage *msg) { @@ -640,12 +737,22 @@ rpc_update_ipv4(struct interface *ifp) return 0; } +#ifdef INET6 int rpc_update_ipv6(struct interface *ifp) { - /* Currently not supported. */ + struct dhcp6_state *state = D6_STATE(ifp); + if (state->new != NULL) { + /* push state over d-bus */ + dbus_send_dhcpv6_message(ifp, state->reason, "new_", + state->new, state->new_len); + rpc_signal_status("Bound6"); + } else { + rpc_signal_status("Release6"); + } return 0; } +#endif int rpc_notify_unicast_arp(struct interface *ifp) { diff --git a/dhcp-common.c b/dhcp-common.c index 70e76ce..b0a2012 100644 --- a/dhcp-common.c +++ b/dhcp-common.c @@ -753,7 +753,7 @@ dhcp_set_leasefile(char *leasefile, size_t len, int family, ifp->lease_identifier, "", ""); } return snprintf(leasefile, len, - family == AF_INET ? LEASEFILE : LEASEFILE, + family == AF_INET ? LEASEFILE : LEASEFILE6, ifp->name, "", ""); } @@ -50,6 +50,7 @@ #include "if.h" #include "if-options.h" #include "ipv6nd.h" +#include "rpc-interface.h" #include "script.h" #ifndef __UNCONST @@ -1373,6 +1374,7 @@ dhcp6_startdiscover(void *arg) struct interface *ifp; struct dhcp6_state *state; + rpc_signal_status("Discover6"); ifp = arg; dhcp6_delete_delegates(ifp); logger(ifp->ctx, LOG_INFO, "%s: soliciting a DHCPv6 lease", ifp->name); @@ -1474,6 +1476,7 @@ dhcp6_startrebind(void *arg) struct dhcp6_state *state; int pd; + rpc_signal_status("Rebind6"); ifp = arg; eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrenew, ifp); state = D6_STATE(ifp); @@ -1516,6 +1519,7 @@ dhcp6_startrequest(struct interface *ifp) { struct dhcp6_state *state; + rpc_signal_status("Request6"); eloop_timeout_delete(ifp->ctx->eloop, dhcp6_senddiscover, ifp); state = D6_STATE(ifp); state->state = DH6S_REQUEST; @@ -1539,6 +1543,7 @@ dhcp6_startconfirm(struct interface *ifp) { struct dhcp6_state *state; + rpc_signal_status("Confirm6"); state = D6_STATE(ifp); state->state = DH6S_CONFIRM; state->start_uptime = uptime(); @@ -1566,6 +1571,7 @@ dhcp6_startinform(void *arg) struct interface *ifp; struct dhcp6_state *state; + rpc_signal_status("Inform6"); ifp = arg; state = D6_STATE(ifp); if (state->new == NULL || ifp->options->options & DHCPCD_DEBUG) @@ -1591,6 +1597,7 @@ dhcp6_startexpire(void *arg) { struct interface *ifp; + rpc_signal_status("Expire6"); ifp = arg; eloop_timeout_delete(ifp->ctx->eloop, dhcp6_sendrebind, ifp); @@ -1614,6 +1621,7 @@ dhcp6_startrelease(struct interface *ifp) if (state->state != DH6S_BOUND) return; + rpc_signal_status("Release6"); state->state = DH6S_RELEASE; state->start_uptime = uptime(); state->RTC = 0; @@ -3039,9 +3047,13 @@ recv: eloop_timeout_add_sec(ifp->ctx->eloop, (time_t)state->expire, dhcp6_startexpire, ifp); +#ifndef PASSIVE_MODE ipv6nd_runignoredra(ifp); ipv6_addaddrs(&state->addrs); dhcp6_delegate_prefix(ifp); +#else + rpc_update_ipv6(ifp); +#endif /* PASSIVE_MODE */ if (state->state == DH6S_INFORMED) logger(ifp->ctx, has_new ? LOG_INFO : LOG_DEBUG, diff --git a/dhcpcd.conf b/dhcpcd.conf index 3837feb..833c5b6 100644 --- a/dhcpcd.conf +++ b/dhcpcd.conf @@ -47,3 +47,6 @@ require dhcp_server_identifier # 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 + +# Disable IPv6 router solicitation +noipv6rs diff --git a/if-options.c b/if-options.c index 8680b5b..5d32811 100644 --- a/if-options.c +++ b/if-options.c @@ -102,6 +102,7 @@ #define O_BOOTP O_BASE + 42 const struct option cf_options[] = { + {"shill-ipv6", no_argument, NULL, 'a'}, {"background", no_argument, NULL, 'b'}, {"script", required_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, @@ -671,6 +672,44 @@ parse_option(struct dhcpcd_ctx *ctx, const char *ifname, struct if_options *ifo, case 'U': /* FALLTHROUGH */ case 'V': /* We need to handle non interface options */ break; +#ifdef INET6 + case 'a': + /* Chromeos hack: configure DHCPv6 option for shill. */ + + /* Reallocate ia to add both ia_na and ia_pd. */ + ia = realloc(ifo->ia, sizeof(*ifo->ia) * (ifo->ia_len + 2)); + if (ia == NULL) { + logger(ctx, LOG_ERR, "%s: %m", __func__); + return -1; + } + ifo->ia = ia; + + /* Setup ia_na option with iaid of 0. */ + ia = &ifo->ia[ifo->ia_len++]; + ia->ia_type = D6_OPTION_IA_NA; + parse_iaid(ia->iaid, "0", sizeof(ia->iaid)); + ia->iaid_set = 1; + memset(&ia->addr, 0, sizeof(ia->addr)); + ia->prefix_len = 0; + ia->sla_max = 0; + ia->sla_len = 0; + ia->sla = NULL; + + /* Setup ia_pd option with iaid of 1. */ + ia = &ifo->ia[ifo->ia_len++]; + ia->ia_type = D6_OPTION_IA_PD; + parse_iaid(ia->iaid, "1", sizeof(ia->iaid)); + ia->iaid_set = 1; + memset(&ia->addr, 0, sizeof(ia->addr)); + ia->prefix_len = 0; + ia->sla_max = 0; + ia->sla_len = 0; + ia->sla = NULL; + + /* Enable ia option. */ + ifo->options |= DHCPCD_IA_FORCED; + break; +#endif case 'b': ifo->options |= DHCPCD_BACKGROUND; break; diff --git a/if-options.h b/if-options.h index f1c45b8..78c4358 100644 --- a/if-options.h +++ b/if-options.h @@ -41,7 +41,7 @@ /* Don't set any optional arguments here so we retain POSIX * compatibility with getopt */ -#define IF_OPTS "46bc:de:f:gh:i:j:kl:m:no:pqr:s:t:u:v:wxy:z:" \ +#define IF_OPTS "46abc:de:f:gh:i:j:kl:m:no:pqr:s:t:u:v:wxy:z:" \ "ABC:DEF:GHI:JKLMO:PQ:RS:TUVW:X:Z:" #define DEFAULT_TIMEOUT 30 @@ -609,6 +609,7 @@ ipv6_checkaddrflags(void *arg) static void ipv6_deleteaddr(struct ipv6_addr *ia) { +#ifndef PASSIVE_MODE struct ipv6_state *state; struct ipv6_addr *ap; @@ -626,11 +627,13 @@ ipv6_deleteaddr(struct ipv6_addr *ia) break; } } +#endif } int ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now) { +#ifndef PASSIVE_MODE struct interface *ifp; struct ipv6_state *state; struct ipv6_addr *nap; @@ -741,6 +744,7 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now) &tv, ipv6_checkaddrflags, ap); } #endif +#endif return 0; } @@ -2016,6 +2020,7 @@ ipv6_build_dhcp_routes(struct dhcpcd_ctx *ctx, void ipv6_buildroutes(struct dhcpcd_ctx *ctx) { +#ifndef PASSIVE_MODE struct rt6_head dnr, *nrs; struct rt6 *rt, *rtn, *or; uint8_t have_default; @@ -2119,4 +2124,5 @@ ipv6_buildroutes(struct dhcpcd_ctx *ctx) free(ctx->ipv6->routes); ctx->ipv6->routes = nrs; +#endif } diff --git a/rpc-interface.h b/rpc-interface.h index 6e1e7e0..cf4da46 100644 --- a/rpc-interface.h +++ b/rpc-interface.h @@ -42,8 +42,10 @@ void rpc_signal_status(const char *); /* Update IPv4 configuration. Return 0 on success. */ int rpc_update_ipv4(struct interface *ifp); +#ifdef INET6 /* Update IPv6 configuration. Return 0 on success. */ int rpc_update_ipv6(struct interface *ifp); +#endif /* Emit notification for successful unicast ARP. Return 0 on success. */ int rpc_notify_unicast_arp(struct interface *ifp); @@ -53,12 +53,14 @@ rpc_update_ipv4(struct interface *ifp) return 0; } +#ifdef INET6 int rpc_update_ipv6(struct interface *ifp) { /* Stub implementation. */ return 0; } +#endif int rpc_notify_unicast_arp(struct interface *ifp) |