1f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project/*
2f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * dhcpcd - DHCP client daemon
3e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt * Copyright (c) 2006-2010 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/ioctl.h>
29f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/param.h>
30e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <sys/socket.h>
31e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <sys/stat.h>
32e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <sys/sysctl.h>
33e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <sys/types.h>
34f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
35f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <arpa/inet.h>
36e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <net/if.h>
37f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <net/if_dl.h>
38f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <net/route.h>
39f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <netinet/in.h>
40e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#ifdef __DragonFly__
41e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#  include <netproto/802_11/ieee80211_ioctl.h>
42e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#elif __APPLE__
43e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt  /* FIXME: Add apple includes so we can work out SSID */
44e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#else
45e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#  include <net80211/ieee80211_ioctl.h>
46e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
47f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
48f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <errno.h>
49e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <fnmatch.h>
50f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stddef.h>
51f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stdio.h>
52f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stdlib.h>
53f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <string.h>
54e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <syslog.h>
55f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <unistd.h>
56f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
57f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "config.h"
58f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "common.h"
59e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include "configure.h"
60f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "dhcp.h"
61e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include "if-options.h"
62f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "net.h"
63f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
64e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#define ROUNDUP(a)							      \
65e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
66e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
67e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
68e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt/* FIXME: Why do we need to check for sa_family 255 */
69e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#define COPYOUT(sin, sa)						      \
70e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	sin.s_addr = ((sa) != NULL) ?					      \
71e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    (((struct sockaddr_in *)(void *)sa)->sin_addr).s_addr : 0
72e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
73e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic int r_fd = -1;
74e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic char *link_buf;
75e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic ssize_t link_buflen;
76e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
77e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
78e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtif_init(_unused struct interface *iface)
79e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
80e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* BSD promotes secondary address by default */
81e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return 0;
82e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
83e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
84e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
85e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtif_conf(_unused struct interface *iface)
86e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
87e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* No extra checks needed on BSD */
88e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return 0;
89e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
90e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
91e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
92e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtinit_sockets(void)
93e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
94e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
95e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return -1;
96e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	set_cloexec(socket_afnet);
97e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if ((r_fd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
98e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return -1;
99e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	set_cloexec(r_fd);
100e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return 0;
101e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
102e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
103e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
104e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtgetifssid(const char *ifname, char *ssid)
105e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
106e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int retval = -1;
107e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#if defined(SIOCG80211NWID)
108e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct ifreq ifr;
109e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct ieee80211_nwid nwid;
110e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#elif defined(IEEE80211_IOC_SSID)
111e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct ieee80211req ireq;
112e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char nwid[IEEE80211_NWID_LEN + 1];
113f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#endif
114f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
115e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#if defined(SIOCG80211NWID) /* NetBSD */
116e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	memset(&ifr, 0, sizeof(ifr));
117e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
118e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	memset(&nwid, 0, sizeof(nwid));
119e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ifr.ifr_data = (void *)&nwid;
120e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (ioctl(socket_afnet, SIOCG80211NWID, &ifr) == 0) {
121e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		retval = nwid.i_len;
122e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		memcpy(ssid, nwid.i_nwid, nwid.i_len);
123e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		ssid[nwid.i_len] = '\0';
124e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
125e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#elif defined(IEEE80211_IOC_SSID) /* FreeBSD */
126e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	memset(&ireq, 0, sizeof(ireq));
127e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	strlcpy(ireq.i_name, ifname, sizeof(ireq.i_name));
128e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ireq.i_type = IEEE80211_IOC_SSID;
129e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ireq.i_val = -1;
130e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ireq.i_data = &nwid;
131e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (ioctl(socket_afnet, SIOCG80211, &ireq) == 0) {
132e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		retval = ireq.i_len;
133e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		memcpy(ssid, nwid, ireq.i_len);
134e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		ssid[ireq.i_len] = '\0';
135e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
136e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
137e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return retval;
138e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
139e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
140f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
141e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtif_address(const struct interface *iface, const struct in_addr *address,
142e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    const struct in_addr *netmask, const struct in_addr *broadcast,
143e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    int action)
144f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
145f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int retval;
146f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct ifaliasreq ifa;
147f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	union {
148f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		struct sockaddr *sa;
149f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		struct sockaddr_in *sin;
150f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	} _s;
151f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
152f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memset(&ifa, 0, sizeof(ifa));
153e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
154f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
155e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#define ADDADDR(_var, _addr) {						      \
156e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		_s.sa = &_var;						      \
157e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		_s.sin->sin_family = AF_INET;				      \
158e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		_s.sin->sin_len = sizeof(*_s.sin);			      \
159e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		memcpy(&_s.sin->sin_addr, _addr, sizeof(_s.sin->sin_addr));   \
160e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
161f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
162f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	ADDADDR(ifa.ifra_addr, address);
163f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	ADDADDR(ifa.ifra_mask, netmask);
164e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (action >= 0 && broadcast) {
165f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		ADDADDR(ifa.ifra_broadaddr, broadcast);
166f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
167f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#undef ADDADDR
168f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
169f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (action < 0)
170e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		retval = ioctl(socket_afnet, SIOCDIFADDR, &ifa);
171f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else
172e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		retval = ioctl(socket_afnet, SIOCAIFADDR, &ifa);
173f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return retval;
174f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
175f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
176e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt/* ARGSUSED4 */
177f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
178938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidtif_route(const struct interface *iface, const struct in_addr *dest,
179e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    const struct in_addr *net, const struct in_addr *gate,
180e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    _unused int metric, int action)
181f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
182f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	union sockunion {
183f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		struct sockaddr sa;
184f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		struct sockaddr_in sin;
185f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#ifdef INET6
186f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		struct sockaddr_in6 sin6;
187f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#endif
188f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		struct sockaddr_dl sdl;
189f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		struct sockaddr_storage ss;
190f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	} su;
191f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtm
192f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	{
193f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		struct rt_msghdr hdr;
194938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		char buffer[sizeof(su) * 4];
195f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	} rtm;
196938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	char *bp = rtm.buffer, *p;
197f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	size_t l;
198f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int retval = 0;
199f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
200e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#define ADDSU(_su) {							      \
201e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		l = ROUNDUP(_su.sa.sa_len);				      \
202e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		memcpy(bp, &(_su), l);					      \
203e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		bp += l;						      \
204e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
205e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#define ADDADDR(_a) {							      \
206e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		memset (&su, 0, sizeof(su));				      \
207e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		su.sin.sin_family = AF_INET;				      \
208e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		su.sin.sin_len = sizeof(su.sin);			      \
209e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		memcpy (&su.sin.sin_addr, _a, sizeof(su.sin.sin_addr));	      \
210e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		ADDSU(su);						      \
211e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
212f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
213f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memset(&rtm, 0, sizeof(rtm));
214f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rtm.hdr.rtm_version = RTM_VERSION;
215938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	rtm.hdr.rtm_seq = 1;
216f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (action == 0)
217f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		rtm.hdr.rtm_type = RTM_CHANGE;
218f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else if (action > 0)
219f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		rtm.hdr.rtm_type = RTM_ADD;
220f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else
221f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		rtm.hdr.rtm_type = RTM_DELETE;
222938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	rtm.hdr.rtm_flags = RTF_UP;
223938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	/* None interface subnet routes are static. */
224938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (gate->s_addr != INADDR_ANY ||
225938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	    net->s_addr != iface->net.s_addr ||
226938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	    dest->s_addr != (iface->addr.s_addr & iface->net.s_addr))
227938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		rtm.hdr.rtm_flags |= RTF_STATIC;
228938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
229938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST)
230f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		rtm.hdr.rtm_flags |= RTF_HOST;
231938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	else {
232938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		rtm.hdr.rtm_addrs |= RTA_NETMASK;
233938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		if (rtm.hdr.rtm_flags & RTF_STATIC)
234938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			rtm.hdr.rtm_flags |= RTF_GATEWAY;
235938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		if (action >= 0)
236938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			rtm.hdr.rtm_addrs |= RTA_IFA;
237938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	}
238f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
239938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	ADDADDR(dest);
240938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (rtm.hdr.rtm_flags & RTF_HOST ||
241938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	    !(rtm.hdr.rtm_flags & RTF_STATIC))
242938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	{
243938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		/* Make us a link layer socket for the host gateway */
244f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		memset(&su, 0, sizeof(su));
245938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		su.sdl.sdl_len = sizeof(struct sockaddr_dl);
246938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		link_addr(iface->name, &su.sdl);
247938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		ADDSU(su);
248938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	} else
249938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		ADDADDR(gate);
250938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt
251938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
252938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		/* Ensure that netmask is set correctly */
253938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		memset(&su, 0, sizeof(su));
254938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		su.sin.sin_family = AF_INET;
255938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		su.sin.sin_len = sizeof(su.sin);
256938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr));
257938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		p = su.sa.sa_len + (char *)&su;
258938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		for (su.sa.sa_len = 0; p > (char *)&su;)
259938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			if (*--p != 0) {
260938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt				su.sa.sa_len = 1 + p - (char *)&su;
261938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt				break;
262938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			}
263938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		ADDSU(su);
264f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
265f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
266938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (rtm.hdr.rtm_addrs & RTA_IFA)
267938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		ADDADDR(&iface->addr);
268f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
269f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
270e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (write(r_fd, &rtm, l) == -1)
271f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		retval = -1;
272f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return retval;
273f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
274f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
275f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
276e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtopen_link_socket(void)
277f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
278f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int fd;
279f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
280f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	fd = socket(PF_ROUTE, SOCK_RAW, 0);
281e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (fd != -1) {
282e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		set_cloexec(fd);
283e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		set_nonblock(fd);
284e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
285e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return fd;
286e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
287e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
288e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic void
289e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtget_addrs(int type, char *cp, struct sockaddr **sa)
290e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
291e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int i;
292e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
293e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	for (i = 0; i < RTAX_MAX; i++) {
294e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (type & (1 << i)) {
295e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			sa[i] = (struct sockaddr *)cp;
296e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#ifdef DEBUG
297e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			printf ("got %d %d %s\n", i, sa[i]->sa_family,
298e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    inet_ntoa(((struct sockaddr_in *)sa[i])->
299e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				sin_addr));
300e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
301e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			ADVANCE(cp, sa[i]);
302e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		} else
303e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			sa[i] = NULL;
304e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
305f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
306f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
307f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
308e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtmanage_link(int fd)
309f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
310e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char *p, *e, *cp;
311e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char ifname[IF_NAMESIZE];
312f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	ssize_t bytes;
313f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rt_msghdr *rtm;
314e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct if_announcemsghdr *ifan;
315f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct if_msghdr *ifm;
316e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct ifa_msghdr *ifam;
317e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt rt;
318e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct sockaddr *sa, *rti_info[RTAX_MAX];
319e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int len;
320e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#ifdef RTM_CHGADDR
321e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct sockaddr_dl sdl;
322e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	unsigned char *hwaddr;
323e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
324f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
325f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	for (;;) {
326e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (ioctl(fd, FIONREAD, &len) == -1)
327e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			return -1;
328e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (link_buflen < len) {
329e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			p = realloc(link_buf, len);
330e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (p == NULL)
331e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				return -1;
332e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			link_buf = p;
333e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			link_buflen = len;
334e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
335e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		bytes = read(fd, link_buf, link_buflen);
336f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		if (bytes == -1) {
337f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (errno == EAGAIN)
338f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				return 0;
339f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (errno == EINTR)
340f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				continue;
341f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			return -1;
342f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
343e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		e = link_buf + bytes;
344e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		for (p = link_buf; p < e; p += rtm->rtm_msglen) {
345e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			rtm = (struct rt_msghdr *)(void *)p;
346e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			switch(rtm->rtm_type) {
347e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#ifdef RTM_IFANNOUNCE
348e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			case RTM_IFANNOUNCE:
349e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				ifan = (struct if_announcemsghdr *)(void *)p;
350e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				switch(ifan->ifan_what) {
351e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				case IFAN_ARRIVAL:
352e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					handle_interface(1, ifan->ifan_name);
353e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
354e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				case IFAN_DEPARTURE:
355e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					handle_interface(-1, ifan->ifan_name);
356e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
357e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				}
358e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				break;
359e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
360e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			case RTM_IFINFO:
361e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				ifm = (struct if_msghdr *)(void *)p;
362e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				memset(ifname, 0, sizeof(ifname));
363e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if (if_indextoname(ifm->ifm_index, ifname))
364e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					handle_interface(0, ifname);
365e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				break;
366e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			case RTM_DELETE:
367e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if (!(rtm->rtm_addrs & RTA_DST) ||
368e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				    !(rtm->rtm_addrs & RTA_GATEWAY) ||
369e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				    !(rtm->rtm_addrs & RTA_NETMASK))
370e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
371e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if (rtm->rtm_pid == getpid())
372e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
373e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				cp = (char *)(void *)(rtm + 1);
374e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				sa = (struct sockaddr *)(void *)cp;
375e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if (sa->sa_family != AF_INET)
376e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
377e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				get_addrs(rtm->rtm_addrs, cp, rti_info);
378e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				rt.iface = NULL;
379e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				rt.next = NULL;
380e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				COPYOUT(rt.dest, rti_info[RTAX_DST]);
381e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
382e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				COPYOUT(rt.gate, rti_info[RTAX_GATEWAY]);
383e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				route_deleted(&rt);
384e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				break;
385e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#ifdef RTM_CHGADDR
386e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			case RTM_CHGADDR:	/* FALLTHROUGH */
387e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
388e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			case RTM_DELADDR:	/* FALLTHROUGH */
389e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			case RTM_NEWADDR:
390e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				ifam = (struct ifa_msghdr *)(void *)p;
391e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if (!if_indextoname(ifam->ifam_index, ifname))
392e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
393e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				cp = (char *)(void *)(ifam + 1);
394e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				get_addrs(ifam->ifam_addrs, cp, rti_info);
395e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				if (rti_info[RTAX_IFA] == NULL)
396e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
397e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				switch (rti_info[RTAX_IFA]->sa_family) {
398e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#ifdef RTM_CHGADDR
399e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				case AF_LINK:
400e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					if (rtm->rtm_type != RTM_CHGADDR)
401e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt						break;
402e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					memcpy(&sdl, rti_info[RTAX_IFA],
403e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					    rti_info[RTAX_IFA]->sa_len);
404e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					hwaddr = xmalloc(sdl.sdl_alen);
405e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					memcpy(hwaddr, LLADDR(&sdl),
406e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					    sdl.sdl_alen);
407e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					handle_hwaddr(ifname, hwaddr,
408e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					    sdl.sdl_alen);
409e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
410e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
411e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				case AF_INET:
412e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				case 255: /* FIXME: Why 255? */
413e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					COPYOUT(rt.dest, rti_info[RTAX_IFA]);
414e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					COPYOUT(rt.net, rti_info[RTAX_NETMASK]);
415e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					COPYOUT(rt.gate, rti_info[RTAX_BRD]);
416e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					handle_ifa(rtm->rtm_type, ifname,
417e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					    &rt.dest, &rt.net, &rt.gate);
418e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt					break;
419e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				}
420e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				break;
421e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			}
422f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
423f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
424f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
425