blob: 3d0bcadcdd34368ca9fa779c4f13f4962ebeaca4 [file] [log] [blame]
The Android Open Source Projectf7c54212009-03-03 19:29:22 -08001/*
2 * dhcpcd - DHCP client daemon
Dmitry Shmidta3a22602012-07-23 16:45:46 -07003 * Copyright (c) 2006-2011 Roy Marples <roy@marples.name>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -08004 * All rights reserved
5
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <asm/types.h> /* Needed for 2.4 kernels */
29
30#include <sys/types.h>
31#include <sys/socket.h>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080032#include <sys/ioctl.h>
33#include <sys/param.h>
34
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080035#include <linux/netlink.h>
36#include <linux/rtnetlink.h>
Dmitry Shmidte86eee12011-01-24 16:27:51 -080037
38/* Support older kernels */
39#ifndef IFLA_WIRELESS
40# define IFLA_WIRELESS (IFLA_MASTER + 1)
41#endif
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080042
43#include <errno.h>
Dmitry Shmidte86eee12011-01-24 16:27:51 -080044#include <ctype.h>
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080045#include <stddef.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080051#include "config.h"
52#include "common.h"
Dmitry Shmidte86eee12011-01-24 16:27:51 -080053#include "configure.h"
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080054#include "dhcp.h"
55#include "net.h"
56
Christopher Ferris0c9f91e2014-09-03 20:17:53 -070057/* ANDROID change, moved this below all includes. */
58/* For some reason, glibc doesn't include newer flags from linux/if.h
59 * However, we cannot include linux/if.h directly as it conflicts
60 * with the glibc version. D'oh! */
61#ifndef IFF_LOWER_UP
62#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
63#endif
64/* End of ANDROID change */
65
Dmitry Shmidte86eee12011-01-24 16:27:51 -080066static int sock_fd;
67static struct sockaddr_nl sock_nl;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080068
69int
Dmitry Shmidte86eee12011-01-24 16:27:51 -080070if_init(struct interface *iface)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080071{
Dmitry Shmidte86eee12011-01-24 16:27:51 -080072 char path[PATH_MAX];
73 FILE *fp;
74 int n;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080075
Dmitry Shmidte86eee12011-01-24 16:27:51 -080076 /* We enable promote_secondaries so that we can do this
77 * add 192.168.1.2/24
78 * add 192.168.1.3/24
79 * del 192.168.1.2/24
80 * and the subnet mask moves onto 192.168.1.3/24
81 * This matches the behaviour of BSD which makes coding dhcpcd
82 * a little easier as there's just one behaviour. */
83 snprintf(path, sizeof(path),
84 "/proc/sys/net/ipv4/conf/%s/promote_secondaries",
85 iface->name);
86
87 fp = fopen(path, "w");
88 if (fp == NULL)
89 return errno == ENOENT ? 0 : -1;
90 n = fprintf(fp, "1");
91 fclose(fp);
92 return n == -1 ? -1 : 0;
93}
94
95int
96if_conf(struct interface *iface)
97{
98 char path[PATH_MAX], buf[1];
99 FILE *fp;
100
101 /* Some qeth setups require the use of the broadcast flag. */
102 snprintf(path, sizeof(path),
103 "/sys/class/net/%s/device/layer2",
104 iface->name);
105
106 fp = fopen(path, "r");
107 if (fp == NULL)
108 return errno == ENOENT ? 0 : -1;
109 if (fgets(buf, sizeof(buf), fp) != NULL && buf[0] == '0')
110 iface->state->options->options |= DHCPCD_BROADCAST;
111 fclose(fp);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800112 return 0;
113}
114
115static int
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800116_open_link_socket(struct sockaddr_nl *nl)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800117{
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800118 int fd;
119
120 if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
121 return -1;
122 nl->nl_family = AF_NETLINK;
123 if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1)
124 return -1;
125 set_cloexec(fd);
126 return fd;
127}
128
129int
130init_sockets(void)
131{
132 if ((socket_afnet = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
133 return -1;
134 set_cloexec(socket_afnet);
135 sock_fd = _open_link_socket(&sock_nl);
136 set_cloexec(sock_fd);
137 return sock_fd;
138}
139
140int
141open_link_socket(void)
142{
143 struct sockaddr_nl snl;
144
145 memset(&snl, 0, sizeof(snl));
146 snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE | RTMGRP_IPV4_IFADDR;
147 return _open_link_socket(&snl);
148}
149
150static int
151get_netlink(int fd, int flags,
152 int (*callback)(struct nlmsghdr *))
153{
154 char *buf = NULL, *nbuf;
155 ssize_t buflen = 0, bytes;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800156 struct nlmsghdr *nlm;
157 int r = -1;
158
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800159 for (;;) {
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800160 bytes = recv(fd, NULL, 0,
161 flags | MSG_PEEK | MSG_DONTWAIT | MSG_TRUNC);
162 if (bytes == -1) {
163 if (errno == EAGAIN) {
164 r = 0;
165 goto eexit;
166 }
167 if (errno == EINTR)
168 continue;
169 goto eexit;
170 } else if (bytes == buflen) {
171 /* Support kernels older than 2.6.22 */
172 if (bytes == 0)
173 bytes = 512;
174 else
175 bytes *= 2;
176 }
177 if (buflen < bytes) {
178 /* Alloc 1 more so we work with older kernels */
179 buflen = bytes + 1;
180 nbuf = realloc(buf, buflen);
181 if (nbuf == NULL)
182 goto eexit;
183 buf = nbuf;
184 }
185 bytes = recv(fd, buf, buflen, flags);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800186 if (bytes == -1) {
187 if (errno == EAGAIN) {
188 r = 0;
189 goto eexit;
190 }
191 if (errno == EINTR)
192 continue;
193 goto eexit;
194 }
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800195 for (nlm = (struct nlmsghdr *)buf;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800196 NLMSG_OK(nlm, (size_t)bytes);
197 nlm = NLMSG_NEXT(nlm, bytes))
198 {
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800199 r = callback(nlm);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800200 if (r != 0)
201 goto eexit;
202 }
203 }
204
205eexit:
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800206 free(buf);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800207 return r;
208}
209
210static int
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800211err_netlink(struct nlmsghdr *nlm)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800212{
213 struct nlmsgerr *err;
214 int l;
215
216 if (nlm->nlmsg_type != NLMSG_ERROR)
217 return 0;
218 l = nlm->nlmsg_len - sizeof(*nlm);
219 if ((size_t)l < sizeof(*err)) {
220 errno = EBADMSG;
221 return -1;
222 }
223 err = (struct nlmsgerr *)NLMSG_DATA(nlm);
224 if (err->error == 0)
225 return l;
226 errno = -err->error;
227 return -1;
228}
229
230static int
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800231link_route(struct nlmsghdr *nlm)
232{
233 int len, idx, metric;
234 struct rtattr *rta;
235 struct rtmsg *rtm;
236 struct rt rt;
237 char ifn[IF_NAMESIZE + 1];
238
239 if (nlm->nlmsg_type != RTM_DELROUTE)
240 return 0;
241
242 len = nlm->nlmsg_len - sizeof(*nlm);
243 if ((size_t)len < sizeof(*rtm)) {
244 errno = EBADMSG;
245 return -1;
246 }
247 rtm = NLMSG_DATA(nlm);
248 if (rtm->rtm_type != RTN_UNICAST ||
249 rtm->rtm_table != RT_TABLE_MAIN ||
250 rtm->rtm_family != AF_INET ||
251 nlm->nlmsg_pid == (uint32_t)getpid())
252 return 1;
253 rta = (struct rtattr *) ((char *)rtm + NLMSG_ALIGN(sizeof(*rtm)));
254 len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
255 rt.iface = NULL;
256 rt.dest.s_addr = INADDR_ANY;
257 rt.net.s_addr = INADDR_ANY;
258 rt.gate.s_addr = INADDR_ANY;
259 rt.next = NULL;
260 metric = 0;
261 while (RTA_OK(rta, len)) {
262 switch (rta->rta_type) {
263 case RTA_DST:
264 memcpy(&rt.dest.s_addr, RTA_DATA(rta),
265 sizeof(rt.dest.s_addr));
266 break;
267 case RTA_GATEWAY:
268 memcpy(&rt.gate.s_addr, RTA_DATA(rta),
269 sizeof(rt.gate.s_addr));
270 break;
271 case RTA_OIF:
272 idx = *(int *)RTA_DATA(rta);
273 if (if_indextoname(idx, ifn))
274 rt.iface = find_interface(ifn);
275 break;
276 case RTA_PRIORITY:
277 metric = *(int *)RTA_DATA(rta);
278 break;
279 }
280 rta = RTA_NEXT(rta, len);
281 }
282 if (rt.iface != NULL) {
283 if (metric == rt.iface->metric) {
284 inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
285 route_deleted(&rt);
286 }
287 }
288 return 1;
289}
290
291static int
292link_addr(struct nlmsghdr *nlm)
293{
294 int len;
295 struct rtattr *rta;
296 struct ifaddrmsg *ifa;
297 struct in_addr addr, net, dest;
298 char ifn[IF_NAMESIZE + 1];
299 struct interface *iface;
300
301 if (nlm->nlmsg_type != RTM_DELADDR && nlm->nlmsg_type != RTM_NEWADDR)
302 return 0;
303
304 len = nlm->nlmsg_len - sizeof(*nlm);
305 if ((size_t)len < sizeof(*ifa)) {
306 errno = EBADMSG;
307 return -1;
308 }
309 if (nlm->nlmsg_pid == (uint32_t)getpid())
310 return 1;
311 ifa = NLMSG_DATA(nlm);
312 if (if_indextoname(ifa->ifa_index, ifn) == NULL)
313 return -1;
314 iface = find_interface(ifn);
315 if (iface == NULL)
316 return 1;
317 rta = (struct rtattr *) IFA_RTA(ifa);
318 len = NLMSG_PAYLOAD(nlm, sizeof(*ifa));
319 addr.s_addr = dest.s_addr = INADDR_ANY;
320 dest.s_addr = INADDR_ANY;
321 inet_cidrtoaddr(ifa->ifa_prefixlen, &net);
322 while (RTA_OK(rta, len)) {
323 switch (rta->rta_type) {
324 case IFA_ADDRESS:
325 if (iface->flags & IFF_POINTOPOINT) {
326 memcpy(&dest.s_addr, RTA_DATA(rta),
327 sizeof(addr.s_addr));
328 }
329 break;
330 case IFA_LOCAL:
331 memcpy(&addr.s_addr, RTA_DATA(rta),
332 sizeof(addr.s_addr));
333 break;
334 }
335 rta = RTA_NEXT(rta, len);
336 }
337 handle_ifa(nlm->nlmsg_type, ifn, &addr, &net, &dest);
338 return 1;
339}
340
341static int
342link_netlink(struct nlmsghdr *nlm)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800343{
344 int len;
345 struct rtattr *rta;
346 struct ifinfomsg *ifi;
347 char ifn[IF_NAMESIZE + 1];
348
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800349 len = link_route(nlm);
350 if (len != 0)
351 return len;
352 len = link_addr(nlm);
353 if (len != 0)
354 return len;
355
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800356 if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
357 return 0;
358 len = nlm->nlmsg_len - sizeof(*nlm);
359 if ((size_t)len < sizeof(*ifi)) {
360 errno = EBADMSG;
361 return -1;
362 }
363 ifi = NLMSG_DATA(nlm);
364 if (ifi->ifi_flags & IFF_LOOPBACK)
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800365 return 1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800366 rta = (struct rtattr *) ((char *)ifi + NLMSG_ALIGN(sizeof(*ifi)));
367 len = NLMSG_PAYLOAD(nlm, sizeof(*ifi));
368 *ifn = '\0';
369 while (RTA_OK(rta, len)) {
370 switch (rta->rta_type) {
371 case IFLA_WIRELESS:
372 /* Ignore wireless messages */
373 if (nlm->nlmsg_type == RTM_NEWLINK &&
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800374 ifi->ifi_change == 0)
375 return 1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800376 break;
377 case IFLA_IFNAME:
378 strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
379 break;
380 }
381 rta = RTA_NEXT(rta, len);
382 }
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700383
384 if (nlm->nlmsg_type == RTM_DELLINK) {
385 handle_interface(-1, ifn);
386 return 1;
387 }
388
389 /* Bridge interfaces set IFF_LOWER_UP when they have a valid
390 * hardware address. To trigger a valid hardware address pickup
391 * we need to pretend that that don't exist until they have
392 * IFF_LOWER_UP set. */
393 if (ifi->ifi_flags & IFF_MASTER && !(ifi->ifi_flags & IFF_LOWER_UP)) {
394 handle_interface(-1, ifn);
395 return 1;
396 }
397
398 handle_carrier(ifi->ifi_flags & IFF_RUNNING ? 1 : -1,
399 ifi->ifi_flags, ifn);
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800400 return 1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800401}
402
403int
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800404manage_link(int fd)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800405{
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800406 return get_netlink(fd, MSG_DONTWAIT, &link_netlink);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800407}
408
409static int
410send_netlink(struct nlmsghdr *hdr)
411{
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800412 int r;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800413 struct iovec iov;
414 struct msghdr msg;
415 static unsigned int seq;
416
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800417 memset(&iov, 0, sizeof(iov));
418 iov.iov_base = hdr;
419 iov.iov_len = hdr->nlmsg_len;
420 memset(&msg, 0, sizeof(msg));
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800421 msg.msg_name = &sock_nl;
422 msg.msg_namelen = sizeof(sock_nl);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800423 msg.msg_iov = &iov;
424 msg.msg_iovlen = 1;
425 /* Request a reply */
426 hdr->nlmsg_flags |= NLM_F_ACK;
427 hdr->nlmsg_seq = ++seq;
428
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800429 if (sendmsg(sock_fd, &msg, 0) != -1)
430 r = get_netlink(sock_fd, 0, &err_netlink);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800431 else
432 r = -1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800433 return r;
434}
435
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800436#define NLMSG_TAIL(nmsg) \
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800437 ((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len)))
438
439static int
440add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800441 const void *data, int alen)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800442{
443 int len = RTA_LENGTH(alen);
444 struct rtattr *rta;
445
446 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
447 errno = ENOBUFS;
448 return -1;
449 }
450
451 rta = NLMSG_TAIL(n);
452 rta->rta_type = type;
453 rta->rta_len = len;
454 memcpy(RTA_DATA(rta), data, alen);
455 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
456
457 return 0;
458}
459
460static int
461add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, uint32_t data)
462{
463 int len = RTA_LENGTH(sizeof(data));
464 struct rtattr *rta;
465
466 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
467 errno = ENOBUFS;
468 return -1;
469 }
470
471 rta = NLMSG_TAIL(n);
472 rta->rta_type = type;
473 rta->rta_len = len;
474 memcpy(RTA_DATA(rta), &data, sizeof(data));
475 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
476
477 return 0;
478}
479
480struct nlma
481{
482 struct nlmsghdr hdr;
483 struct ifaddrmsg ifa;
484 char buffer[64];
485};
486
487struct nlmr
488{
489 struct nlmsghdr hdr;
490 struct rtmsg rt;
491 char buffer[256];
492};
493
494int
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800495if_address(const struct interface *iface,
496 const struct in_addr *address, const struct in_addr *netmask,
497 const struct in_addr *broadcast, int action)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800498{
499 struct nlma *nlm;
500 int retval = 0;
501
502 nlm = xzalloc(sizeof(*nlm));
503 nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
504 nlm->hdr.nlmsg_flags = NLM_F_REQUEST;
505 if (action >= 0) {
506 nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
507 nlm->hdr.nlmsg_type = RTM_NEWADDR;
508 } else
509 nlm->hdr.nlmsg_type = RTM_DELADDR;
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800510 if (!(nlm->ifa.ifa_index = if_nametoindex(iface->name))) {
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800511 free(nlm);
512 errno = ENODEV;
513 return -1;
514 }
515 nlm->ifa.ifa_family = AF_INET;
516 nlm->ifa.ifa_prefixlen = inet_ntocidr(*netmask);
517 /* This creates the aliased interface */
518 add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LABEL,
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800519 iface->name, strlen(iface->name) + 1);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800520 add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800521 &address->s_addr, sizeof(address->s_addr));
522 if (action >= 0 && broadcast)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800523 add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST,
Dmitry Shmidte86eee12011-01-24 16:27:51 -0800524 &broadcast->s_addr, sizeof(broadcast->s_addr));
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800525
526 if (send_netlink(&nlm->hdr) == -1)
527 retval = -1;
528 free(nlm);
529 return retval;
530}
531
532int
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700533if_route(const struct rt *rt, int action)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800534{
535 struct nlmr *nlm;
536 unsigned int ifindex;
537 int retval = 0;
538
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700539 if (!(ifindex = if_nametoindex(rt->iface->name))) {
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800540 errno = ENODEV;
541 return -1;
542 }
543
544 nlm = xzalloc(sizeof(*nlm));
545 nlm->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
546 nlm->hdr.nlmsg_type = RTM_NEWROUTE;
547 if (action == 0)
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800548 nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
549 else if (action == 1)
Dmitry Shmidt0545fad2011-01-24 16:42:36 -0800550 nlm->hdr.nlmsg_flags = NLM_F_CREATE /*| NLM_F_EXCL*/;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800551 else
552 nlm->hdr.nlmsg_type = RTM_DELROUTE;
553 nlm->hdr.nlmsg_flags |= NLM_F_REQUEST;
554 nlm->rt.rtm_family = AF_INET;
555 nlm->rt.rtm_table = RT_TABLE_MAIN;
556
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800557 if (action == -1 || action == -2)
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800558 nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
559 else {
Dmitry Shmidt0545fad2011-01-24 16:42:36 -0800560 nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800561 /* We only change route metrics for kernel routes */
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700562 if (rt->dest.s_addr ==
563 (rt->iface->addr.s_addr & rt->iface->net.s_addr) &&
564 rt->net.s_addr == rt->iface->net.s_addr)
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800565 nlm->rt.rtm_protocol = RTPROT_KERNEL;
566 else
567 nlm->rt.rtm_protocol = RTPROT_BOOT;
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700568 if (rt->gate.s_addr == INADDR_ANY ||
569 (rt->gate.s_addr == rt->dest.s_addr &&
570 rt->net.s_addr == INADDR_BROADCAST))
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800571 nlm->rt.rtm_scope = RT_SCOPE_LINK;
572 else
573 nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE;
574 nlm->rt.rtm_type = RTN_UNICAST;
575 }
576
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700577 nlm->rt.rtm_dst_len = inet_ntocidr(rt->net);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800578 add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700579 &rt->dest.s_addr, sizeof(rt->dest.s_addr));
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800580 if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
581 add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700582 &rt->iface->addr.s_addr, sizeof(rt->iface->addr.s_addr));
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800583 }
584 /* If destination == gateway then don't add the gateway */
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700585 if (rt->dest.s_addr != rt->gate.s_addr ||
586 rt->net.s_addr != INADDR_BROADCAST)
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800587 add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700588 &rt->gate.s_addr, sizeof(rt->gate.s_addr));
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800589
590 add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
Dmitry Shmidta3a22602012-07-23 16:45:46 -0700591 add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800592
593 if (send_netlink(&nlm->hdr) == -1)
594 retval = -1;
595 free(nlm);
596 return retval;
597}