1f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project/*
2f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * dhcpcd - DHCP client daemon
3a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt * Copyright (c) 2006-2011 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 <asm/types.h> /* Needed for 2.4 kernels */
29f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
30f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/types.h>
31f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/socket.h>
32f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/ioctl.h>
33f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/param.h>
34f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
35f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <linux/netlink.h>
36f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <linux/rtnetlink.h>
37e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
38e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt/* Support older kernels */
39e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#ifndef IFLA_WIRELESS
40e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt# define IFLA_WIRELESS (IFLA_MASTER + 1)
41e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#endif
42f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
43f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <errno.h>
44e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include <ctype.h>
45f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stddef.h>
46f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stdio.h>
47f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stdlib.h>
48f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <string.h>
49f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <unistd.h>
50f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
51f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "config.h"
52f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "common.h"
53e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#include "configure.h"
54f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "dhcp.h"
55f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "net.h"
56f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
570c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris/* ANDROID change, moved this below all includes. */
580c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris/* For some reason, glibc doesn't include newer flags from linux/if.h
590c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris * However, we cannot include linux/if.h directly as it conflicts
600c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris * with the glibc version. D'oh! */
610c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris#ifndef IFF_LOWER_UP
620c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris#define IFF_LOWER_UP	0x10000		/* driver signals L1 up		*/
630c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris#endif
640c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris/* End of ANDROID change */
650c9f91efb3e5d44a35a9d3559d8070520c55de08Christopher Ferris
66e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic int sock_fd;
67e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic struct sockaddr_nl sock_nl;
68e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
69e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
70e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtif_init(struct interface *iface)
71e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
72e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char path[PATH_MAX];
73e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	FILE *fp;
74e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int n;
75e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
76e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* We enable promote_secondaries so that we can do this
77e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * add 192.168.1.2/24
78e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * add 192.168.1.3/24
79e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * del 192.168.1.2/24
80e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * and the subnet mask moves onto 192.168.1.3/24
81e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * This matches the behaviour of BSD which makes coding dhcpcd
82e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	 * a little easier as there's just one behaviour. */
83e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(path, sizeof(path),
84e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    "/proc/sys/net/ipv4/conf/%s/promote_secondaries",
85e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    iface->name);
86e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
87e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	fp = fopen(path, "w");
88e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (fp == NULL)
89e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return errno == ENOENT ? 0 : -1;
90e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	n = fprintf(fp, "1");
91e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	fclose(fp);
92e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return n == -1 ? -1 : 0;
93e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
94f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
95f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
96e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtif_conf(struct interface *iface)
97e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
98e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char path[PATH_MAX], buf[1];
99e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	FILE *fp;
100e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
101e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	/* Some qeth setups require the use of the broadcast flag. */
102e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snprintf(path, sizeof(path),
103e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    "/sys/class/net/%s/device/layer2",
104e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    iface->name);
105e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
106e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	fp = fopen(path, "r");
107e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (fp == NULL)
108e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return errno == ENOENT ? 0 : -1;
109e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (fgets(buf, sizeof(buf), fp) != NULL && buf[0] == '0')
110e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		iface->state->options->options |= DHCPCD_BROADCAST;
111e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	fclose(fp);
112e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return 0;
113e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
114e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
115e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic int
116e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt_open_link_socket(struct sockaddr_nl *nl)
117f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
118f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int fd;
119f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
120f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
121f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
122e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	nl->nl_family = AF_NETLINK;
123e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1)
124f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
125f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	set_cloexec(fd);
126e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return fd;
127e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
128e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
129e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
130e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtinit_sockets(void)
131e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
132e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
133e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return -1;
134e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	set_cloexec(socket_afnet);
135e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	sock_fd = _open_link_socket(&sock_nl);
136e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	set_cloexec(sock_fd);
137e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return sock_fd;
138e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
139e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
140e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtint
141e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtopen_link_socket(void)
142e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
143e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct sockaddr_nl snl;
144e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
145e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	memset(&snl, 0, sizeof(snl));
146e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
147e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return _open_link_socket(&snl);
148f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
149f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
150f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
151f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectget_netlink(int fd, int flags,
152e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    int (*callback)(struct nlmsghdr *))
153f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
154e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char *buf = NULL, *nbuf;
155e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ssize_t buflen = 0, bytes;
156f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmsghdr *nlm;
157f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int r = -1;
158f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
159f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	for (;;) {
160e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		bytes = recv(fd, NULL, 0,
161e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
162f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		if (bytes == -1) {
163f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (errno == EAGAIN) {
164f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				r = 0;
165f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				goto eexit;
166f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			}
167f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (errno == EINTR)
168f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				continue;
169f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			goto eexit;
170e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		} else if (bytes == buflen) {
171e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			/* Support kernels older than 2.6.22 */
172e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (bytes == 0)
173e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				bytes = 512;
174e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			else
175e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				bytes *= 2;
176f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
177e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (buflen < bytes) {
178e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			/* Alloc 1 more so we work with older kernels */
179e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			buflen = bytes + 1;
180e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			nbuf = realloc(buf, buflen);
181e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (nbuf == NULL)
182e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				goto eexit;
183e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			buf = nbuf;
184e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
185e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		bytes = recv(fd, buf, buflen, flags);
186e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (bytes == -1) {
187e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (errno == EAGAIN) {
188e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				r = 0;
189e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				goto eexit;
190e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			}
191e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (errno == EINTR)
192e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				continue;
193e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			goto eexit;
194e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
195e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		for (nlm = (struct nlmsghdr *)buf;
196f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		     NLMSG_OK(nlm, (size_t)bytes);
197f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		     nlm = NLMSG_NEXT(nlm, bytes))
198f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		{
199e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			r = callback(nlm);
200f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (r != 0)
201f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				goto eexit;
202f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
203f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
204f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
205f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projecteexit:
206e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	free(buf);
207f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return r;
208f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
209f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
210f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
211e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidterr_netlink(struct nlmsghdr *nlm)
212f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
213f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmsgerr *err;
214f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int l;
215f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
216f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (nlm->nlmsg_type != NLMSG_ERROR)
217f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return 0;
218f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	l = nlm->nlmsg_len - sizeof(*nlm);
219f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if ((size_t)l < sizeof(*err)) {
220f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = EBADMSG;
221f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
222f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
223f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	err = (struct nlmsgerr *)NLMSG_DATA(nlm);
224f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (err->error == 0)
225f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return l;
226f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	errno = -err->error;
227f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return -1;
228f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
229f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
230f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
231e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtlink_route(struct nlmsghdr *nlm)
232e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
233e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int len, idx, metric;
234e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rtattr *rta;
235e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rtmsg *rtm;
236e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rt rt;
237e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char ifn[IF_NAMESIZE + 1];
238e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
239e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (nlm->nlmsg_type != RTM_DELROUTE)
240e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 0;
241e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
242e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	len = nlm->nlmsg_len - sizeof(*nlm);
243e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if ((size_t)len < sizeof(*rtm)) {
244e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		errno = EBADMSG;
245e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return -1;
246e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
247e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rtm = NLMSG_DATA(nlm);
248e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (rtm->rtm_type != RTN_UNICAST ||
249e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    rtm->rtm_table != RT_TABLE_MAIN ||
250e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    rtm->rtm_family != AF_INET ||
251e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    nlm->nlmsg_pid == (uint32_t)getpid())
252e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 1;
253e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rta = (struct rtattr *) ((char *)rtm + NLMSG_ALIGN(sizeof(*rtm)));
254e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
255e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt.iface = NULL;
256e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt.dest.s_addr = INADDR_ANY;
257e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt.net.s_addr = INADDR_ANY;
258e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt.gate.s_addr = INADDR_ANY;
259e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rt.next = NULL;
260e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	metric = 0;
261e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	while (RTA_OK(rta, len)) {
262e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		switch (rta->rta_type) {
263e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		case RTA_DST:
264e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			memcpy(&rt.dest.s_addr, RTA_DATA(rta),
265e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    sizeof(rt.dest.s_addr));
266e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			break;
267e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		case RTA_GATEWAY:
268e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			memcpy(&rt.gate.s_addr, RTA_DATA(rta),
269e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    sizeof(rt.gate.s_addr));
270e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			break;
271e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		case RTA_OIF:
272e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			idx = *(int *)RTA_DATA(rta);
273e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (if_indextoname(idx, ifn))
274e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				rt.iface = find_interface(ifn);
275e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			break;
276e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		case RTA_PRIORITY:
277e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			metric = *(int *)RTA_DATA(rta);
278e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			break;
279e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
280e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		rta = RTA_NEXT(rta, len);
281e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
282e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (rt.iface != NULL) {
283e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		if (metric == rt.iface->metric) {
284e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
285e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			route_deleted(&rt);
286e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
287e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
288e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return 1;
289e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
290e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
291e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic int
292e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtlink_addr(struct nlmsghdr *nlm)
293e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt{
294e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int len;
295e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct rtattr *rta;
296e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct ifaddrmsg *ifa;
297e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct in_addr addr, net, dest;
298e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	char ifn[IF_NAMESIZE + 1];
299e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	struct interface *iface;
300e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
301e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
302e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 0;
303e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
304e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	len = nlm->nlmsg_len - sizeof(*nlm);
305e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if ((size_t)len < sizeof(*ifa)) {
306e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		errno = EBADMSG;
307e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return -1;
308e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
309e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (nlm->nlmsg_pid == (uint32_t)getpid())
310e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 1;
311e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	ifa = NLMSG_DATA(nlm);
312e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (if_indextoname(ifa->ifa_index, ifn) == NULL)
313e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return -1;
314e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	iface = find_interface(ifn);
315e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (iface == NULL)
316e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 1;
317e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	rta = (struct rtattr *) IFA_RTA(ifa);
318e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
319e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	addr.s_addr = dest.s_addr = INADDR_ANY;
320e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	dest.s_addr = INADDR_ANY;
321e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
322e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	while (RTA_OK(rta, len)) {
323e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		switch (rta->rta_type) {
324e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		case IFA_ADDRESS:
325e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			if (iface->flags & IFF_POINTOPOINT) {
326e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				memcpy(&dest.s_addr, RTA_DATA(rta),
327e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				    sizeof(addr.s_addr));
328e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			}
329e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			break;
330e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		case IFA_LOCAL:
331e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			memcpy(&addr.s_addr, RTA_DATA(rta),
332e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    sizeof(addr.s_addr));
333e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			break;
334e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		}
335e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		rta = RTA_NEXT(rta, len);
336e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	}
337e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	handle_ifa(nlm->nlmsg_type, ifn, &addr, &net, &dest);
338e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return 1;
339e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt}
340e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
341e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtstatic int
342e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtlink_netlink(struct nlmsghdr *nlm)
343f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
344f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int len;
345f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtattr *rta;
346f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct ifinfomsg *ifi;
347f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	char ifn[IF_NAMESIZE + 1];
348f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
349e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	len = link_route(nlm);
350e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (len != 0)
351e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return len;
352e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	len = link_addr(nlm);
353e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (len != 0)
354e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return len;
355e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt
356f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
357f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return 0;
358f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	len = nlm->nlmsg_len - sizeof(*nlm);
359f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if ((size_t)len < sizeof(*ifi)) {
360f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = EBADMSG;
361f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
362f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
363f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	ifi = NLMSG_DATA(nlm);
364f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (ifi->ifi_flags & IFF_LOOPBACK)
365e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		return 1;
366f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
367f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
368f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	*ifn = '\0';
369f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	while (RTA_OK(rta, len)) {
370f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		switch (rta->rta_type) {
371f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		case IFLA_WIRELESS:
372f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			/* Ignore wireless messages */
373f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (nlm->nlmsg_type == RTM_NEWLINK &&
374e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt			    ifi->ifi_change == 0)
375e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt				return 1;
376f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			break;
377f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		case IFLA_IFNAME:
378f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
379f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			break;
380f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
381f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		rta = RTA_NEXT(rta, len);
382f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
383a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
384a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (nlm->nlmsg_type == RTM_DELLINK) {
385a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		handle_interface(-1, ifn);
386a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		return 1;
387a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	}
388a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
389a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	/* Bridge interfaces set IFF_LOWER_UP when they have a valid
390a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	 * hardware address. To trigger a valid hardware address pickup
391a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	 * we need to pretend that that don't exist until they have
392a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	 * IFF_LOWER_UP set. */
393a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (ifi->ifi_flags & IFF_MASTER && !(ifi->ifi_flags & IFF_LOWER_UP)) {
394a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		handle_interface(-1, ifn);
395a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		return 1;
396a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	}
397a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt
398a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	handle_carrier(ifi->ifi_flags & IFF_RUNNING ? 1 : -1,
399a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	    ifi->ifi_flags, ifn);
400e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return 1;
401f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
402f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
403f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
404e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtmanage_link(int fd)
405f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
406e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	return get_netlink(fd, MSG_DONTWAIT, &link_netlink);
407f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
408f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
409f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
410f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectsend_netlink(struct nlmsghdr *hdr)
411f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
412e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	int r;
413f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct iovec iov;
414f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct msghdr msg;
415f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	static unsigned int seq;
416f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
417f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memset(&iov, 0, sizeof(iov));
418f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	iov.iov_base = hdr;
419f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	iov.iov_len = hdr->nlmsg_len;
420f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memset(&msg, 0, sizeof(msg));
421e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	msg.msg_name = &sock_nl;
422e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	msg.msg_namelen = sizeof(sock_nl);
423f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	msg.msg_iov = &iov;
424f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	msg.msg_iovlen = 1;
425f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* Request a reply */
426f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	hdr->nlmsg_flags |= NLM_F_ACK;
427f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	hdr->nlmsg_seq = ++seq;
428f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
429e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (sendmsg(sock_fd, &msg, 0) != -1)
430e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		r = get_netlink(sock_fd, 0, &err_netlink);
431f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else
432f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		r = -1;
433f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return r;
434f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
435f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
436e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt#define NLMSG_TAIL(nmsg)						\
437f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len)))
438f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
439f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
440f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectadd_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
441e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    const void *data, int alen)
442f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
443f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int len = RTA_LENGTH(alen);
444f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtattr *rta;
445f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
446f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
447f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = ENOBUFS;
448f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
449f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
450f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
451f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta = NLMSG_TAIL(n);
452f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta->rta_type = type;
453f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta->rta_len = len;
454f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memcpy(RTA_DATA(rta), data, alen);
455f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
456f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
457f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return 0;
458f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
459f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
460f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
461f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectadd_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, uint32_t data)
462f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
463f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int len = RTA_LENGTH(sizeof(data));
464f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtattr *rta;
465f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
466f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
467f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = ENOBUFS;
468f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
469f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
470f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
471f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta = NLMSG_TAIL(n);
472f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta->rta_type = type;
473f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta->rta_len = len;
474f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memcpy(RTA_DATA(rta), &data, sizeof(data));
475f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
476f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
477f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return 0;
478f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
479f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
480f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstruct nlma
481f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
482f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmsghdr hdr;
483f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct ifaddrmsg ifa;
484f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	char buffer[64];
485f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project};
486f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
487f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstruct nlmr
488f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
489f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmsghdr hdr;
490f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtmsg rt;
491f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	char buffer[256];
492f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project};
493f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
494f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
495e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidtif_address(const struct interface *iface,
496e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    const struct in_addr *address, const struct in_addr *netmask,
497e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt    const struct in_addr *broadcast, int action)
498f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
499f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlma *nlm;
500f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int retval = 0;
501f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
502f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm = xzalloc(sizeof(*nlm));
503f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
504f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
505f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (action >= 0) {
506f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
507f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_type = RTM_NEWADDR;
508f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	} else
509f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_type = RTM_DELADDR;
510e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (!(nlm->ifa.ifa_index = if_nametoindex(iface->name))) {
511f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		free(nlm);
512f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = ENODEV;
513f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
514f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
515f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->ifa.ifa_family = AF_INET;
516f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask);
517f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* This creates the aliased interface */
518f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
519e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    iface->name, strlen(iface->name) + 1);
520f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
521e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	    &address->s_addr, sizeof(address->s_addr));
522e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt	if (action >= 0 && broadcast)
523f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST,
524e86eee143ed21592f88a46623a81f71002430459Dmitry Shmidt		    &broadcast->s_addr, sizeof(broadcast->s_addr));
525f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
526f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (send_netlink(&nlm->hdr) == -1)
527f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		retval = -1;
528f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	free(nlm);
529f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return retval;
530f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
531f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
532f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
533a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidtif_route(const struct rt *rt, int action)
534f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
535f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmr *nlm;
536f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	unsigned int ifindex;
537f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int retval = 0;
538f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
539a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (!(ifindex = if_nametoindex(rt->iface->name))) {
540f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = ENODEV;
541f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
542f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
543f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
544f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm = xzalloc(sizeof(*nlm));
545f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
546f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_type = RTM_NEWROUTE;
547f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (action == 0)
548938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
549938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	else if (action == 1)
5500545fad98723550607287a86bfee3807c7d26e91Dmitry Shmidt		nlm->hdr.nlmsg_flags = NLM_F_CREATE /*| NLM_F_EXCL*/;
551f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else
552f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_type = RTM_DELROUTE;
553f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
554f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->rt.rtm_family = AF_INET;
555f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->rt.rtm_table = RT_TABLE_MAIN;
556f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
557938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (action == -1 || action == -2)
558f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
559f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else {
5600545fad98723550607287a86bfee3807c7d26e91Dmitry Shmidt		nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/;
561938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		/* We only change route metrics for kernel routes */
562a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		if (rt->dest.s_addr ==
563a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		    (rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
564a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		    rt->net.s_addr == rt->iface->net.s_addr)
565938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			nlm->rt.rtm_protocol = RTPROT_KERNEL;
566938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		else
567938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			nlm->rt.rtm_protocol = RTPROT_BOOT;
568a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		if (rt->gate.s_addr == INADDR_ANY ||
569a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		    (rt->gate.s_addr == rt->dest.s_addr &&
570a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt			rt->net.s_addr == INADDR_BROADCAST))
571f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			nlm->rt.rtm_scope = RT_SCOPE_LINK;
572f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		else
573f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
574f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->rt.rtm_type = RTN_UNICAST;
575f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
576f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
577a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	nlm->rt.rtm_dst_len = inet_ntocidr(rt->net);
578f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
579a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	    &rt->dest.s_addr, sizeof(rt->dest.s_addr));
580938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
581938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
582a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		    &rt->iface->addr.s_addr, sizeof(rt->iface->addr.s_addr));
583938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	}
584938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	/* If destination == gateway then don't add the gateway */
585a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	if (rt->dest.s_addr != rt->gate.s_addr ||
586a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	    rt->net.s_addr != INADDR_BROADCAST)
587938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
588a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt		    &rt->gate.s_addr, sizeof(rt->gate.s_addr));
589f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
590f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
591a3a2260384a906e1674c7498c2f479e9f37bc503Dmitry Shmidt	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
592f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
593f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (send_netlink(&nlm->hdr) == -1)
594f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		retval = -1;
595f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	free(nlm);
596f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return retval;
597f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
598