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