1f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project/*
2f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * dhcpcd - DHCP client daemon
3f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project * Copyright 2006-2008 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/stat.h>
33f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/ioctl.h>
34f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <sys/param.h>
35f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
36f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <arpa/inet.h>
37f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <linux/netlink.h>
38f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <linux/rtnetlink.h>
39f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <netinet/ether.h>
40f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <netpacket/packet.h>
41f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
42f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <errno.h>
43f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stddef.h>
44f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stdio.h>
45f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <stdlib.h>
46f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <string.h>
47f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include <unistd.h>
48f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
49f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project/* Support older kernels */
50f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#ifndef IFLA_WIRELESS
51f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project# define IFLA_WIRELSSS (IFLFA_MASTER + 1)
52f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#endif
53f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
54f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "config.h"
55f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "common.h"
56f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "dhcp.h"
57f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#include "net.h"
58f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
59f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#define BUFFERLEN 256
60f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
61f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
62f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectopen_link_socket(struct interface *iface)
63f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
64f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int fd;
65f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct sockaddr_nl nl;
66f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
67f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
68f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
69f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memset(&nl, 0, sizeof(nl));
70f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nl.nl_family = AF_NETLINK;
71f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nl.nl_groups = RTMGRP_LINK;
72f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1)
73f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
74f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	set_cloexec(fd);
75f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (iface->link_fd != -1)
76f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		close(iface->link_fd);
77f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	iface->link_fd = fd;
78f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return 0;
79f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
80f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
81f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
82f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectget_netlink(int fd, int flags,
83f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	    int (*callback)(struct nlmsghdr *, const char *),
84f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	    const char *ifname)
85f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
86f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	char *buffer = NULL;
87f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	ssize_t bytes;
88f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmsghdr *nlm;
89f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int r = -1;
90f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
91f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	buffer = xzalloc(sizeof(char) * BUFFERLEN);
92f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	for (;;) {
93f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		bytes = recv(fd, buffer, BUFFERLEN, flags);
94f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		if (bytes == -1) {
95f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (errno == EAGAIN) {
96f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				r = 0;
97f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				goto eexit;
98f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			}
99f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (errno == EINTR)
100f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				continue;
101f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			goto eexit;
102f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
103f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		for (nlm = (struct nlmsghdr *)buffer;
104f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		     NLMSG_OK(nlm, (size_t)bytes);
105f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		     nlm = NLMSG_NEXT(nlm, bytes))
106f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		{
107f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			r = callback(nlm, ifname);
108f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (r != 0)
109f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				goto eexit;
110f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
111f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
112f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
113f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projecteexit:
114f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	free(buffer);
115f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return r;
116f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
117f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
118f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
119f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projecterr_netlink(struct nlmsghdr *nlm, _unused const char *ifname)
120f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
121f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmsgerr *err;
122f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int l;
123f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
124f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (nlm->nlmsg_type != NLMSG_ERROR)
125f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return 0;
126f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	l = nlm->nlmsg_len - sizeof(*nlm);
127f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if ((size_t)l < sizeof(*err)) {
128f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = EBADMSG;
129f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
130f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
131f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	err = (struct nlmsgerr *)NLMSG_DATA(nlm);
132f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (err->error == 0)
133f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return l;
134f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	errno = -err->error;
135f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return -1;
136f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
137f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
138f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
139f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectlink_netlink(struct nlmsghdr *nlm, const char *ifname)
140f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
141f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int len;
142f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtattr *rta;
143f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct ifinfomsg *ifi;
144f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	char ifn[IF_NAMESIZE + 1];
145f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
146f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
147f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return 0;
148f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	len = nlm->nlmsg_len - sizeof(*nlm);
149f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if ((size_t)len < sizeof(*ifi)) {
150f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = EBADMSG;
151f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
152f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
153f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	ifi = NLMSG_DATA(nlm);
154f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (ifi->ifi_flags & IFF_LOOPBACK)
155f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return 0;
156f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
157f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
158f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	*ifn = '\0';
159f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	while (RTA_OK(rta, len)) {
160f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		switch (rta->rta_type) {
161f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		case IFLA_WIRELESS:
162f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			/* Ignore wireless messages */
163f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			if (nlm->nlmsg_type == RTM_NEWLINK &&
164f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			    ifi->ifi_change  == 0)
165f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project				return 0;
166f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			break;
167f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		case IFLA_IFNAME:
168f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
169f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			break;
170f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		}
171f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		rta = RTA_NEXT(rta, len);
172f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
173f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
174f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (strncmp(ifname, ifn, sizeof(ifn)) == 0)
175f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return 1;
176f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return 0;
177f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
178f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
179f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
180f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectlink_changed(struct interface *iface)
181f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
182f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return get_netlink(iface->link_fd, MSG_DONTWAIT,
183f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			   &link_netlink, iface->name);
184f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
185f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
186f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
187f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectsend_netlink(struct nlmsghdr *hdr)
188f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
189f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int fd, r;
190f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct sockaddr_nl nl;
191f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct iovec iov;
192f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct msghdr msg;
193f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	static unsigned int seq;
194f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
195f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
196f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
197f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memset(&nl, 0, sizeof(nl));
198f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nl.nl_family = AF_NETLINK;
199f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1) {
200f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		close(fd);
201f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
202f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
203f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memset(&iov, 0, sizeof(iov));
204f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	iov.iov_base = hdr;
205f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	iov.iov_len = hdr->nlmsg_len;
206f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memset(&msg, 0, sizeof(msg));
207f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	msg.msg_name = &nl;
208f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	msg.msg_namelen = sizeof(nl);
209f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	msg.msg_iov = &iov;
210f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	msg.msg_iovlen = 1;
211f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* Request a reply */
212f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	hdr->nlmsg_flags |= NLM_F_ACK;
213f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	hdr->nlmsg_seq = ++seq;
214f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
215f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (sendmsg(fd, &msg, 0) != -1)
216f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		r = get_netlink(fd, 0, &err_netlink, NULL);
217f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else
218f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		r = -1;
219f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	close(fd);
220f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return r;
221f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
222f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
223f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project#define NLMSG_TAIL(nmsg) \
224f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len)))
225f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
226f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
227f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectadd_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
228f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	   const void *data, int alen)
229f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
230f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int len = RTA_LENGTH(alen);
231f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtattr *rta;
232f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
233f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
234f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = ENOBUFS;
235f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
236f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
237f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
238f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta = NLMSG_TAIL(n);
239f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta->rta_type = type;
240f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta->rta_len = len;
241f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memcpy(RTA_DATA(rta), data, alen);
242f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
243f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
244f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return 0;
245f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
246f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
247f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstatic int
248f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectadd_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, uint32_t data)
249f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
250f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int len = RTA_LENGTH(sizeof(data));
251f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtattr *rta;
252f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
253f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
254f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = ENOBUFS;
255f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
256f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
257f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
258f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta = NLMSG_TAIL(n);
259f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta->rta_type = type;
260f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	rta->rta_len = len;
261f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	memcpy(RTA_DATA(rta), &data, sizeof(data));
262f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
263f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
264f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return 0;
265f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
266f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
267f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstruct nlma
268f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
269f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmsghdr hdr;
270f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct ifaddrmsg ifa;
271f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	char buffer[64];
272f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project};
273f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
274f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectstruct nlmr
275f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
276f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmsghdr hdr;
277f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct rtmsg rt;
278f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	char buffer[256];
279f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project};
280f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
281f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
282f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectif_address(const char *ifname,
283f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	   const struct in_addr *address, const struct in_addr *netmask,
284f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	   const struct in_addr *broadcast, int action)
285f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
286f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlma *nlm;
287f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int retval = 0;
288f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
289f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm = xzalloc(sizeof(*nlm));
290f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
291f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
292f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (action >= 0) {
293f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
294f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_type = RTM_NEWADDR;
295f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	} else
296f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_type = RTM_DELADDR;
297f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (!(nlm->ifa.ifa_index = if_nametoindex(ifname))) {
298f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		free(nlm);
299f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = ENODEV;
300f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
301f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
302f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->ifa.ifa_family = AF_INET;
303f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask);
304f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	/* This creates the aliased interface */
305f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
306f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		   ifname, strlen(ifname) + 1);
307f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
308f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		   &address->s_addr, sizeof(address->s_addr));
309f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (action >= 0)
310f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST,
311f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			   &broadcast->s_addr, sizeof(broadcast->s_addr));
312f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
313f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (send_netlink(&nlm->hdr) == -1)
314f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		retval = -1;
315f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	free(nlm);
316f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return retval;
317f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
318f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
319f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Projectint
320938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidtif_route(const struct interface *iface,
321f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	 const struct in_addr *destination, const struct in_addr *netmask,
322f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	 const struct in_addr *gateway, int metric, int action)
323f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project{
324f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	struct nlmr *nlm;
325f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	unsigned int ifindex;
326f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	int retval = 0;
327f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
328938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (!(ifindex = if_nametoindex(iface->name))) {
329f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		errno = ENODEV;
330f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		return -1;
331f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
332f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
333f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm = xzalloc(sizeof(*nlm));
334f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
335f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_type = RTM_NEWROUTE;
336f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (action == 0)
337938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
338938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	else if (action == 1)
339f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		/*
340f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		 * ers@google:
341f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		 * commented out NLM_F_EXCL here and below. We
342f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		 * sometimes keep one interface up while we are
343f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		 * configuring the other one, and this flag
344f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		 * causes route addition to fail.
345f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		 */
346f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_flags = NLM_F_CREATE /* | NLM_F_EXCL */;
347f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else
348f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_type = RTM_DELROUTE;
349f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
350f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->rt.rtm_family = AF_INET;
351f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->rt.rtm_table = RT_TABLE_MAIN;
352f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
353938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (action == -1 || action == -2)
354f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
355f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	else {
356f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/;
357938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		/* We only change route metrics for kernel routes */
358938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		if (destination->s_addr ==
359938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		    (iface->addr.s_addr & iface->net.s_addr) &&
360938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		    netmask->s_addr == iface->net.s_addr)
361938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			nlm->rt.rtm_protocol = RTPROT_KERNEL;
362938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		else
363938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			nlm->rt.rtm_protocol = RTPROT_BOOT;
364938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		if (gateway->s_addr == INADDR_ANY ||
365938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		    (gateway->s_addr == destination->s_addr &&
366938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		     netmask->s_addr == INADDR_BROADCAST))
367f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			nlm->rt.rtm_scope = RT_SCOPE_LINK;
368f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		else
369f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project			nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
370f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		nlm->rt.rtm_type = RTN_UNICAST;
371f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	}
372f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
373f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	nlm->rt.rtm_dst_len = inet_ntocidr(*netmask);
374f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
375f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		   &destination->s_addr, sizeof(destination->s_addr));
376938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
377938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
378938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			   &iface->addr.s_addr, sizeof(iface->addr.s_addr));
379938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	}
380938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	/* If destination == gateway then don't add the gateway */
381938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	if (destination->s_addr != gateway->s_addr ||
382938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt	    netmask->s_addr != INADDR_BROADCAST)
383938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
384938bc384f44031877543765a9ae18c764f5da9c8Dmitry Shmidt			   &gateway->s_addr, sizeof(gateway->s_addr));
385f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
386f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
387f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, metric);
388f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project
389f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	if (send_netlink(&nlm->hdr) == -1)
390f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project		retval = -1;
391f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	free(nlm);
392f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project	return retval;
393f7c5421560640d23fc10803b9d59a9ff1d83e467The Android Open Source Project}
394