1f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project/*
2f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * dhcpcd - DHCP client daemon
3a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * Copyright (c) 2006-2012 Roy Marples <roy@marples.name>
4f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * All rights reserved
5f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
6f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * Redistribution and use in source and binary forms, with or without
7f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * modification, are permitted provided that the following conditions
8f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * are met:
9f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
10f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
11f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
12f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
13f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project *    documentation and/or other materials provided with the distribution.
14f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project *
15f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * SUCH DAMAGE.
26f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project */
27f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
28f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/stat.h>
29e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <sys/uio.h>
30f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/wait.h>
31f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
32f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <netinet/in.h>
33f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <arpa/inet.h>
34f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
35f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <ctype.h>
36f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <errno.h>
37f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <signal.h>
38f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stdlib.h>
39e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <string.h>
40e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <syslog.h>
41f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <unistd.h>
42f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
43f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "config.h"
44f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "common.h"
45f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "configure.h"
46f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "dhcp.h"
47e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include "if-options.h"
48e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include "if-pref.h"
49a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt#include "ipv6rs.h"
50f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "net.h"
51f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "signals.h"
52f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
53f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#define DEFAULT_PATH	"PATH=/usr/bin:/usr/sbin:/bin:/sbin"
54f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
55e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt/* Some systems have route metrics */
56e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#ifndef HAVE_ROUTE_METRIC
57e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt# ifdef __linux__
58e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#  define HAVE_ROUTE_METRIC 1
59e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt# endif
60e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt# ifndef HAVE_ROUTE_METRIC
61e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#  define HAVE_ROUTE_METRIC 0
62e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt# endif
63e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
64e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
65e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic struct rt *routes;
66e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
67f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
68f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectexec_script(char *const *argv, char *const *env)
69f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
70f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	pid_t pid;
71f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	sigset_t full;
72f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	sigset_t old;
73f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
74f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* OK, we need to block signals */
75f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	sigfillset(&full);
76f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	sigprocmask(SIG_SETMASK, &full, &old);
77f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	signal_reset();
78f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
79f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	switch (pid = vfork()) {
80f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	case -1:
81e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_ERR, "vfork: %m");
82f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		break;
83f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	case 0:
84f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		sigprocmask(SIG_SETMASK, &old, NULL);
85f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		execve(argv[0], argv, env);
86e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_ERR, "%s: %m", argv[0]);
87f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		_exit(127);
88f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		/* NOTREACHED */
89f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
90f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
91f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* Restore our signals */
92f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	signal_setup();
93f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	sigprocmask(SIG_SETMASK, &old, NULL);
94f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return pid;
95f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
96f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
97e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic char *
98e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtmake_var(const char *prefix, const char *var)
99f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
100e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	size_t len;
101e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char *v;
102e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
103e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	len = strlen(prefix) + strlen(var) + 2;
104e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	v = xmalloc(len);
105e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(v, len, "%s_%s", prefix, var);
106e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return v;
107e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
108e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
109f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
110e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic void
111e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtappend_config(char ***env, ssize_t *len,
112e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    const char *prefix, const char *const *config)
113e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
114e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ssize_t i, j, e1;
115e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char **ne, *eq;
116e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
117e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (config == NULL)
118e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return;
119e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
120e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ne = *env;
121e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (i = 0; config[i] != NULL; i++) {
122e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		eq = strchr(config[i], '=');
123e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e1 = eq - config[i] + 1;
124e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		for (j = 0; j < *len; j++) {
125e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (strncmp(ne[j] + strlen(prefix) + 1,
126e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				config[i], e1) == 0)
127e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			{
128e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				free(ne[j]);
129e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				ne[j] = make_var(prefix, config[i]);
130e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				break;
131e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			}
132e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
133e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (j == *len) {
134e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			j++;
135e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			ne = xrealloc(ne, sizeof(char *) * (j + 1));
136e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			ne[j - 1] = make_var(prefix, config[i]);
137e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			*len = j;
138e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
139e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
140e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	*env = ne;
141e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
142e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
143e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic size_t
144e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtarraytostr(const char *const *argv, char **s)
145e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
146e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	const char *const *ap;
147e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char *p;
148e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	size_t len, l;
149e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
150e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	len = 0;
151e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ap = argv;
152e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	while (*ap)
153e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		len += strlen(*ap++) + 1;
154e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	*s = p = xmalloc(len);
155e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ap = argv;
156e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	while (*ap) {
157e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		l = strlen(*ap) + 1;
158e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		memcpy(p, *ap, l);
159e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		p += l;
160e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		ap++;
161e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
162e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return len;
163e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
164e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
165e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic ssize_t
166a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtmake_env(const struct interface *iface, const char *reason, char ***argv)
167e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
168e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char **env, *p;
169e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ssize_t e, elen, l;
170e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	const struct if_options *ifo = iface->state->options;
171e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	const struct interface *ifp;
172a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	int dhcp, ra;
173a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
174a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	dhcp = ra = 0;
175a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (strcmp(reason, "ROUTERADVERT") == 0)
176a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		ra = 1;
177a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	else
178a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		dhcp = 1;
179a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
180a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	/* When dumping the lease, we only want to report interface and
181a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	   reason - the other interface variables are meaningless */
182a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (options & DHCPCD_DUMPLEASE)
183a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		elen = 2;
184a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	else
185a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		elen = 10;
186f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
187f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* Make our env */
188f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	env = xmalloc(sizeof(char *) * (elen + 1));
189e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	e = strlen("interface") + strlen(iface->name) + 2;
190e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	env[0] = xmalloc(e);
191e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(env[0], e, "interface=%s", iface->name);
192a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	e = strlen("reason") + strlen(reason) + 2;
193f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	env[1] = xmalloc(e);
194a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	snprintf(env[1], e, "reason=%s", reason);
195a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (options & DHCPCD_DUMPLEASE)
196a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		goto dumplease;
197a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
198a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt 	e = 20;
199e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	env[2] = xmalloc(e);
200e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(env[2], e, "pid=%d", getpid());
201f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	env[3] = xmalloc(e);
202e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(env[3], e, "ifmetric=%d", iface->metric);
203f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	env[4] = xmalloc(e);
204e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(env[4], e, "ifwireless=%d", iface->wireless);
205e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	env[5] = xmalloc(e);
206e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(env[5], e, "ifflags=%u", iface->flags);
207e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	env[6] = xmalloc(e);
208e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(env[6], e, "ifmtu=%d", get_mtu(iface->name));
209e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	l = e = strlen("interface_order=");
210e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (ifp = ifaces; ifp; ifp = ifp->next)
211e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e += strlen(ifp->name) + 1;
212e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	p = env[7] = xmalloc(e);
213e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	strlcpy(p, "interface_order=", e);
214e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	e -= l;
215e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	p += l;
216e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (ifp = ifaces; ifp; ifp = ifp->next) {
217e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		l = strlcpy(p, ifp->name, e);
218e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		p += l;
219e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e -= l;
220e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		*p++ = ' ';
221e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e--;
222e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
223e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	*--p = '\0';
224a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if ((dhcp && iface->state->new) || (ra && iface->ras)) {
225a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		env[8] = strdup("if_up=true");
226a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		env[9] = strdup("if_down=false");
227a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	} else {
228a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		env[8] = strdup("if_up=false");
229a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		env[9] = strdup("if_down=true");
230a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	}
231e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (*iface->state->profile) {
232e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e = strlen("profile=") + strlen(iface->state->profile) + 2;
233e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		env[elen] = xmalloc(e);
234e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		snprintf(env[elen++], e, "profile=%s", iface->state->profile);
235e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
236e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (iface->wireless) {
237e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e = strlen("new_ssid=") + strlen(iface->ssid) + 2;
238e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (iface->state->new != NULL ||
239e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    strcmp(iface->state->reason, "CARRIER") == 0)
240e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		{
241e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			env = xrealloc(env, sizeof(char *) * (elen + 2));
242e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			env[elen] = xmalloc(e);
243e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			snprintf(env[elen++], e, "new_ssid=%s", iface->ssid);
244e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
245e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (iface->state->old != NULL ||
246e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    strcmp(iface->state->reason, "NOCARRIER") == 0)
247e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		{
248e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			env = xrealloc(env, sizeof(char *) * (elen + 2));
249e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			env[elen] = xmalloc(e);
250e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			snprintf(env[elen++], e, "old_ssid=%s", iface->ssid);
251e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
252e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
253a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (dhcp && iface->state->old) {
254e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e = configure_env(NULL, NULL, iface->state->old, ifo);
255f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		if (e > 0) {
256f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
257e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			elen += configure_env(env + elen, "old",
258e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    iface->state->old, ifo);
259f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
260e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		append_config(&env, &elen, "old",
261e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    (const char *const *)ifo->config);
262f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
263a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
264a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtdumplease:
265a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (dhcp && iface->state->new) {
266e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e = configure_env(NULL, NULL, iface->state->new, ifo);
267f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		if (e > 0) {
268f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
269e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			elen += configure_env(env + elen, "new",
270e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    iface->state->new, ifo);
271f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
272e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		append_config(&env, &elen, "new",
273e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    (const char *const *)ifo->config);
274f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
275a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (ra) {
276a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		e = ipv6rs_env(NULL, NULL, iface);
277a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		if (e > 0) {
278a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			env = xrealloc(env, sizeof(char *) * (elen + e + 1));
279a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			elen += ipv6rs_env(env + elen, NULL, iface);
280a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		}
281a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	}
282e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
283f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* Add our base environment */
284e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (ifo->environ) {
285f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		e = 0;
286e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		while (ifo->environ[e++])
287f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			;
288f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		env = xrealloc(env, sizeof(char *) * (elen + e + 1));
289f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		e = 0;
290e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		while (ifo->environ[e]) {
291e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			env[elen + e] = xstrdup(ifo->environ[e]);
292f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			e++;
293f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
294f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		elen += e;
295f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
296f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	env[elen] = '\0';
297f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
298e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	*argv = env;
299e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return elen;
300e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
301e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
302a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtstatic int
303a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtsend_interface1(int fd, const struct interface *iface, const char *reason)
304e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
305e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char **env, **ep, *s;
306e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ssize_t elen;
307e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct iovec iov[2];
308e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int retval;
309e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
310e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	retval = 0;
311a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	make_env(iface, reason, &env);
312e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	elen = arraytostr((const char *const *)env, &s);
313e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	iov[0].iov_base = &elen;
314e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	iov[0].iov_len = sizeof(ssize_t);
315e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	iov[1].iov_base = s;
316e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	iov[1].iov_len = elen;
317e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	retval = writev(fd, iov, 2);
318e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ep = env;
319e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	while (*ep)
320e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		free(*ep++);
321e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	free(env);
322e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	free(s);
323e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return retval;
324e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
325e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
326e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
327a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtsend_interface(int fd, const struct interface *iface)
328a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt{
329a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	int retval = 0;
330a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (send_interface1(fd, iface, iface->state->reason) == -1)
331a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		retval = -1;
332a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (iface->ras) {
333a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		if (send_interface1(fd, iface, "ROUTERADVERT") == -1)
334a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			retval = -1;
335a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	}
336a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	return retval;
337a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt}
338a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
339a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtint
340a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtrun_script_reason(const struct interface *iface, const char *reason)
341e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
342e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
343e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char **env = NULL, **ep;
344e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char *path, *bigenv;
345e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ssize_t e, elen = 0;
346e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	pid_t pid;
347e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int status = 0;
348e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	const struct fd_list *fd;
349e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct iovec iov[2];
350e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
351a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (iface->state->options->script == NULL ||
352a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	    iface->state->options->script[0] == '\0' ||
353a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	    strcmp(iface->state->options->script, "/dev/null") == 0)
354a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		return 0;
355a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
356a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (reason == NULL)
357a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		reason = iface->state->reason;
358e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
359a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	    iface->name, argv[0], reason);
360e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
361e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* Make our env */
362a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	elen = make_env(iface, reason, &env);
363e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	env = xrealloc(env, sizeof(char *) * (elen + 2));
364e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* Add path to it */
365e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	path = getenv("PATH");
366e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (path) {
367e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e = strlen("PATH") + strlen(path) + 2;
368e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		env[elen] = xmalloc(e);
369e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		snprintf(env[elen], e, "PATH=%s", path);
370e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	} else
371e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		env[elen] = xstrdup(DEFAULT_PATH);
372e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	env[++elen] = '\0';
373e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
374f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	pid = exec_script(argv, env);
375f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (pid == -1)
376f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		status = -1;
377f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else if (pid != 0) {
378f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		/* Wait for the script to finish */
379f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		while (waitpid(pid, &status, 0) == -1) {
380f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (errno != EINTR) {
381e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				syslog(LOG_ERR, "waitpid: %m");
382f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				status = -1;
383f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				break;
384f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			}
385f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
386f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
387f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
388e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* Send to our listeners */
389e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	bigenv = NULL;
390e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (fd = fds; fd != NULL; fd = fd->next) {
391e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (fd->listener) {
392e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (bigenv == NULL) {
393e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				elen = arraytostr((const char *const *)env,
394e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				    &bigenv);
395e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				iov[0].iov_base = &elen;
396e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				iov[0].iov_len = sizeof(ssize_t);
397e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				iov[1].iov_base = bigenv;
398e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				iov[1].iov_len = elen;
399e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			}
400e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (writev(fd->fd, iov, 2) == -1)
401e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				syslog(LOG_ERR, "writev: %m");
402e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
403e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
404e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	free(bigenv);
405e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
406f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* Cleanup */
407f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	ep = env;
408f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	while (*ep)
409f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		free(*ep++);
410f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	free(env);
411f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return status;
412f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
413f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
414f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic struct rt *
415e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtfind_route(struct rt *rts, const struct rt *r, struct rt **lrt,
416e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    const struct rt *srt)
417f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
418f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rt *rt;
419e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
420e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (lrt)
421e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		*lrt = NULL;
422e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (rt = rts; rt; rt = rt->next) {
423e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (rt->dest.s_addr == r->dest.s_addr &&
424e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#if HAVE_ROUTE_METRIC
425e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    (srt || (!rt->iface ||
426e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			rt->iface->metric == r->iface->metric)) &&
427e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
428e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt                    (!srt || srt != rt) &&
429e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    rt->net.s_addr == r->net.s_addr)
430e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			return rt;
431e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (lrt)
432e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			*lrt = rt;
433e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
434e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return NULL;
435e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
436e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
437e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic void
438a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtdesc_route(const char *cmd, const struct rt *rt)
439e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
440e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char addr[sizeof("000.000.000.000") + 1];
441a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	const char *ifname = rt->iface->name;
442e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
443e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	strlcpy(addr, inet_ntoa(rt->dest), sizeof(addr));
444e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (rt->gate.s_addr == INADDR_ANY)
445e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_DEBUG, "%s: %s route to %s/%d", ifname, cmd,
446e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    addr, inet_ntocidr(rt->net));
447e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	else if (rt->gate.s_addr == rt->dest.s_addr &&
448e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    rt->net.s_addr == INADDR_BROADCAST)
449e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_DEBUG, "%s: %s host route to %s", ifname, cmd,
450e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    addr);
451e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	else if (rt->dest.s_addr == INADDR_ANY && rt->net.s_addr == INADDR_ANY)
452e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_DEBUG, "%s: %s default route via %s", ifname, cmd,
453e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    inet_ntoa(rt->gate));
454e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	else
455e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_DEBUG, "%s: %s route to %s/%d via %s", ifname, cmd,
456e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    addr, inet_ntocidr(rt->net), inet_ntoa(rt->gate));
457e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
458e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
459e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt/* If something other than dhcpcd removes a route,
460e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * we need to remove it from our internal table. */
461e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
462e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtroute_deleted(const struct rt *rt)
463e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
464e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt *f, *l;
465e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
466e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	f = find_route(routes, rt, &l, NULL);
467e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (f == NULL)
468e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 0;
469a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	desc_route("removing", f);
470e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (l)
471e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		l->next = f->next;
472e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	else
473e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		routes = f->next;
474e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	free(f);
475e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return 1;
476e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
477e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
478e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic int
479a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtn_route(struct rt *rt)
480e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
481e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* Don't set default routes if not asked to */
482e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (rt->dest.s_addr == 0 &&
483e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    rt->net.s_addr == 0 &&
484a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	    !(rt->iface->state->options->options & DHCPCD_GATEWAY))
485e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return -1;
486e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
487a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	desc_route("adding", rt);
488a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (!add_route(rt))
489e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 0;
490e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (errno == EEXIST) {
491e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		/* Pretend we added the subnet route */
492a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		if (rt->dest.s_addr ==
493a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		    (rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
494a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		    rt->net.s_addr == rt->iface->net.s_addr &&
495e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    rt->gate.s_addr == 0)
496e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			return 0;
497e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		else
498e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			return -1;
499f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
500a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	syslog(LOG_ERR, "%s: add_route: %m", rt->iface->name);
501e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return -1;
502f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
503f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
504f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
505a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtc_route(struct rt *ort, struct rt *nrt)
506e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
507e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* Don't set default routes if not asked to */
508e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (nrt->dest.s_addr == 0 &&
509e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    nrt->net.s_addr == 0 &&
510a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	    !(nrt->iface->state->options->options & DHCPCD_GATEWAY))
511e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return -1;
512e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
513a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	desc_route("changing", nrt);
514e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* We delete and add the route so that we can change metric.
515e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * This also has the nice side effect of flushing ARP entries so
516e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * we don't have to do that manually. */
517a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	del_route(ort);
518a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (!add_route(nrt))
519e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 0;
520a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	syslog(LOG_ERR, "%s: add_route: %m", nrt->iface->name);
521e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return -1;
522e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
523e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
524e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic int
525a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtd_route(struct rt *rt)
526f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
527f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int retval;
528f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
529a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	desc_route("deleting", rt);
530a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	retval = del_route(rt);
531f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (retval != 0 && errno != ENOENT && errno != ESRCH)
532a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		syslog(LOG_ERR,"%s: del_route: %m", rt->iface->name);
533f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return retval;
534f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
535f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
536e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic struct rt *
537e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtget_subnet_route(struct dhcp_message *dhcp)
538f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
539e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	in_addr_t addr;
540e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct in_addr net;
541f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rt *rt;
542f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
543e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	addr = dhcp->yiaddr;
544e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (addr == 0)
545e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		addr = dhcp->ciaddr;
546e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* Ensure we have all the needed values */
547e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (get_option_addr(&net, dhcp, DHO_SUBNETMASK) == -1)
548e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		net.s_addr = get_netmask(addr);
549e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (net.s_addr == INADDR_BROADCAST || net.s_addr == INADDR_ANY)
550e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return NULL;
551e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt = malloc(sizeof(*rt));
552e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt->dest.s_addr = addr & net.s_addr;
553e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt->net.s_addr = net.s_addr;
554e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt->gate.s_addr = 0;
555e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return rt;
556e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
557f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
558e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic struct rt *
559e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtadd_subnet_route(struct rt *rt, const struct interface *iface)
560e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
561e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt *r;
562e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
563e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (iface->net.s_addr == INADDR_BROADCAST ||
564e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    iface->net.s_addr == INADDR_ANY ||
565e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    (iface->state->options->options &
566e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	     (DHCPCD_INFORM | DHCPCD_STATIC) &&
567e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	     iface->state->options->req_addr.s_addr == INADDR_ANY))
568e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return rt;
569e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
570e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r = xmalloc(sizeof(*r));
571e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r->dest.s_addr = iface->addr.s_addr & iface->net.s_addr;
572e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r->net.s_addr = iface->net.s_addr;
573e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r->gate.s_addr = 0;
574e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r->next = rt;
575e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return r;
576f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
577f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
578e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic struct rt *
579e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtget_routes(const struct interface *iface)
580f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
581e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt *rt, *nrt = NULL, *r = NULL;
582e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
583e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (iface->state->options->routes != NULL) {
584e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		for (rt = iface->state->options->routes;
585e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		     rt != NULL;
586e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		     rt = rt->next)
587e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		{
588e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (rt->gate.s_addr == 0)
589e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				break;
590e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (r == NULL)
591e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				r = nrt = xmalloc(sizeof(*r));
592e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			else {
593e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				r->next = xmalloc(sizeof(*r));
594e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				r = r->next;
595e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			}
596e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			memcpy(r, rt, sizeof(*r));
597e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			r->next = NULL;
598e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
599e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return nrt;
600f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
601e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
602e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return get_option_routes(iface->state->new,
603e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    iface->name, &iface->state->options->options);
604f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
605f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
606e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt/* Some DHCP servers add set host routes by setting the gateway
607e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * to the assinged IP address. This differs from our notion of a host route
608e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * where the gateway is the destination address, so we fix it. */
609e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic struct rt *
610e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtmassage_host_routes(struct rt *rt, const struct interface *iface)
611f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
612e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt *r;
613f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
614e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (r = rt; r; r = r->next)
615e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (r->gate.s_addr == iface->addr.s_addr &&
616e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    r->net.s_addr == INADDR_BROADCAST)
617e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			r->gate.s_addr = r->dest.s_addr;
618e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return rt;
619e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
620f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
621e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic struct rt *
622e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtadd_destination_route(struct rt *rt, const struct interface *iface)
623e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
624e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt *r;
625e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
626e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (!(iface->flags & IFF_POINTOPOINT) ||
627e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    !has_option_mask(iface->state->options->dstmask, DHO_ROUTER))
628e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return rt;
629e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r = xmalloc(sizeof(*r));
630e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r->dest.s_addr = INADDR_ANY;
631e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r->net.s_addr = INADDR_ANY;
632e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r->gate.s_addr = iface->dst.s_addr;
633e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	r->next = rt;
634e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return r;
635e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
636e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
637e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt/* We should check to ensure the routers are on the same subnet
638e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * OR supply a host route. If not, warn and add a host route. */
639e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic struct rt *
640e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtadd_router_host_route(struct rt *rt, const struct interface *ifp)
641e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
642e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt *rtp, *rtl, *rtn;
643e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	const char *cp, *cp2, *cp3, *cplim;
644e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
645e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (rtp = rt, rtl = NULL; rtp; rtl = rtp, rtp = rtp->next) {
646e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (rtp->dest.s_addr != INADDR_ANY)
647e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			continue;
648e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		/* Scan for a route to match */
649e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		for (rtn = rt; rtn != rtp; rtn = rtn->next) {
650e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			/* match host */
651e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (rtn->dest.s_addr == rtp->gate.s_addr)
652e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				break;
653e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			/* match subnet */
654e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			cp = (const char *)&rtp->gate.s_addr;
655e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			cp2 = (const char *)&rtn->dest.s_addr;
656e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			cp3 = (const char *)&rtn->net.s_addr;
657e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			cplim = cp3 + sizeof(rtn->net.s_addr);
658e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			while (cp3 < cplim) {
659e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if ((*cp++ ^ *cp2++) & *cp3++)
660e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
661e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			}
662e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (cp3 == cplim)
663f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				break;
664f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
665e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (rtn != rtp)
666e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			continue;
667e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (ifp->flags & IFF_NOARP) {
668e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			syslog(LOG_WARNING,
669e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    "%s: forcing router %s through interface",
670e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    ifp->name, inet_ntoa(rtp->gate));
671e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			rtp->gate.s_addr = 0;
672e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			continue;
673f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
674e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_WARNING, "%s: router %s requires a host route",
675e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    ifp->name, inet_ntoa(rtp->gate));
676e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		rtn = xmalloc(sizeof(*rtn));
677e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		rtn->dest.s_addr = rtp->gate.s_addr;
678e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		rtn->net.s_addr = INADDR_BROADCAST;
679e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		rtn->gate.s_addr = rtp->gate.s_addr;
680e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		rtn->next = rtp;
681e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (rtl == NULL)
682e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			rt = rtn;
683e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		else
684e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			rtl->next = rtn;
685f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
686e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return rt;
687e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
688f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
689e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtvoid
690e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtbuild_routes(void)
691e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
692e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
693e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	const struct interface *ifp;
694f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
6950d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync	if (avoid_routes) return;
6960d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync
697e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (ifp = ifaces; ifp; ifp = ifp->next) {
698e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (ifp->state->new == NULL)
699e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			continue;
700e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		dnr = get_routes(ifp);
701e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		dnr = massage_host_routes(dnr, ifp);
702e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		dnr = add_subnet_route(dnr, ifp);
703e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		dnr = add_router_host_route(dnr, ifp);
704e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		dnr = add_destination_route(dnr, ifp);
705e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
706e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			rt->iface = ifp;
707a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			rt->metric = ifp->metric;
708e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			/* Is this route already in our table? */
709e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if ((find_route(nrs, rt, NULL, NULL)) != NULL)
710e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				continue;
711a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			rt->src.s_addr = ifp->addr.s_addr;
712e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			/* Do we already manage it? */
713e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if ((or = find_route(routes, rt, &rtl, NULL))) {
714e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if (or->iface != ifp ||
715a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt				    or->src.s_addr != ifp->addr.s_addr ||
716a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt				    rt->gate.s_addr != or->gate.s_addr ||
717a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt				    rt->metric != or->metric)
718e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				{
719a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt					if (c_route(or, rt) != 0)
720e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt						continue;
721e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				}
722e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if (rtl != NULL)
723e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					rtl->next = or->next;
724e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				else
725e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					routes = or->next;
726e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				free(or);
727f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			} else {
728a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt				if (n_route(rt) != 0)
729e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					continue;
730f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			}
731e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (dnr == rt)
732e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				dnr = rtn;
733e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			else if (lrt)
734e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				lrt->next = rtn;
735e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			rt->next = nrs;
736e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			nrs = rt;
737a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			rt = lrt; /* When we loop this makes lrt correct */
738f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
739e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		free_routes(dnr);
740f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
741e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
742e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* Remove old routes we used to manage */
743e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (rt = routes; rt; rt = rt->next) {
744e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (find_route(nrs, rt, NULL, NULL) == NULL)
745a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			d_route(rt);
746e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
747e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
748e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	free_routes(routes);
749e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	routes = nrs;
750f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
751f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
752f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
753f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectdelete_address(struct interface *iface)
754f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
755f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int retval;
756e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct if_options *ifo;
757e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
758e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ifo = iface->state->options;
759e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (ifo->options & DHCPCD_INFORM ||
760e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    (ifo->options & DHCPCD_STATIC && ifo->req_addr.s_addr == 0))
761e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 0;
762e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	syslog(LOG_DEBUG, "%s: deleting IP address %s/%d",
763e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    iface->name,
764e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    inet_ntoa(iface->addr),
765e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    inet_ntocidr(iface->net));
766e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	retval = del_address(iface, &iface->addr, &iface->net);
767f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (retval == -1 && errno != EADDRNOTAVAIL)
768e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_ERR, "del_address: %m");
769f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	iface->addr.s_addr = 0;
770f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	iface->net.s_addr = 0;
771f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return retval;
772f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
773f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
774f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
775e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtconfigure(struct interface *iface)
776f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
777e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct dhcp_message *dhcp = iface->state->new;
778e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct dhcp_lease *lease = &iface->state->lease;
779e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct if_options *ifo = iface->state->options;
780e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt *rt;
781f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
782e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* As we are now adjusting an interface, we need to ensure
783e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * we have them in the right order for routing and configuration. */
784e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	sort_interfaces();
785f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
786e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (dhcp == NULL) {
787e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (!(ifo->options & DHCPCD_PERSISTENT)) {
788e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			build_routes();
789e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (iface->addr.s_addr != 0)
790e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				delete_address(iface);
791e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			run_script(iface);
792f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
793f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return 0;
794f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
795f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
796f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* This also changes netmask */
797e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (!(ifo->options & DHCPCD_INFORM) ||
798e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    !has_address(iface->name, &lease->addr, &lease->net))
799e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	{
800e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		syslog(LOG_DEBUG, "%s: adding IP address %s/%d",
801e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    iface->name, inet_ntoa(lease->addr),
802e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    inet_ntocidr(lease->net));
803e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (add_address(iface,
804e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			&lease->addr, &lease->net, &lease->brd) == -1 &&
805f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		    errno != EEXIST)
806f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		{
807e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			syslog(LOG_ERR, "add_address: %m");
808f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			return -1;
809f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
810f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
811f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
812f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* Now delete the old address if different */
813e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (iface->addr.s_addr != lease->addr.s_addr &&
814f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	    iface->addr.s_addr != 0)
815f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		delete_address(iface);
816f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
817e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	iface->addr.s_addr = lease->addr.s_addr;
818e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	iface->net.s_addr = lease->net.s_addr;
819e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
8200d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync	if (!avoid_routes) {
8210d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync		/* We need to delete the subnet route to have our metric or
8220d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync		 * prefer the interface. */
8230d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync		rt = get_subnet_route(dhcp);
8240d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync		if (rt != NULL) {
8250d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync			rt->iface = iface;
826a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			rt->metric = 0;
8270d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync			if (!find_route(routes, rt, NULL, NULL))
828a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt				del_route(rt);
8290d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync			free(rt);
8300d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync		}
8310d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync
8320d3a47d979ac35a49b2a2da9e80e16bd37aab877repo sync		build_routes();
833f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
834f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
835e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (!iface->state->lease.frominfo &&
836e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    !(ifo->options & (DHCPCD_INFORM | DHCPCD_STATIC)))
837f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		if (write_lease(iface, dhcp) == -1)
838e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			syslog(LOG_ERR, "write_lease: %m");
839e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	run_script(iface);
840f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return 0;
841f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
842