Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2011 Roy Marples <roy (at) marples.name>
      4  * 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>
     32 #include <sys/ioctl.h>
     33 #include <sys/param.h>
     34 
     35 #include <linux/netlink.h>
     36 #include <linux/rtnetlink.h>
     37 
     38 /* Support older kernels */
     39 #ifndef IFLA_WIRELESS
     40 # define IFLA_WIRELESS (IFLA_MASTER + 1)
     41 #endif
     42 
     43 #include <errno.h>
     44 #include <ctype.h>
     45 #include <stddef.h>
     46 #include <stdio.h>
     47 #include <stdlib.h>
     48 #include <string.h>
     49 #include <unistd.h>
     50 
     51 #include "config.h"
     52 #include "common.h"
     53 #include "configure.h"
     54 #include "dhcp.h"
     55 #include "net.h"
     56 
     57 /* 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 
     66 static int sock_fd;
     67 static struct sockaddr_nl sock_nl;
     68 
     69 int
     70 if_init(struct interface *iface)
     71 {
     72 	char path[PATH_MAX];
     73 	FILE *fp;
     74 	int n;
     75 
     76 	/* 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 
     95 int
     96 if_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);
    112 	return 0;
    113 }
    114 
    115 static int
    116 _open_link_socket(struct sockaddr_nl *nl)
    117 {
    118 	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 
    129 int
    130 init_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 
    140 int
    141 open_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 
    150 static int
    151 get_netlink(int fd, int flags,
    152     int (*callback)(struct nlmsghdr *))
    153 {
    154 	char *buf = NULL, *nbuf;
    155 	ssize_t buflen = 0, bytes;
    156 	struct nlmsghdr *nlm;
    157 	int r = -1;
    158 
    159 	for (;;) {
    160 		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);
    186 		if (bytes == -1) {
    187 			if (errno == EAGAIN) {
    188 				r = 0;
    189 				goto eexit;
    190 			}
    191 			if (errno == EINTR)
    192 				continue;
    193 			goto eexit;
    194 		}
    195 		for (nlm = (struct nlmsghdr *)buf;
    196 		     NLMSG_OK(nlm, (size_t)bytes);
    197 		     nlm = NLMSG_NEXT(nlm, bytes))
    198 		{
    199 			r = callback(nlm);
    200 			if (r != 0)
    201 				goto eexit;
    202 		}
    203 	}
    204 
    205 eexit:
    206 	free(buf);
    207 	return r;
    208 }
    209 
    210 static int
    211 err_netlink(struct nlmsghdr *nlm)
    212 {
    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 
    230 static int
    231 link_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 
    291 static int
    292 link_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 
    341 static int
    342 link_netlink(struct nlmsghdr *nlm)
    343 {
    344 	int len;
    345 	struct rtattr *rta;
    346 	struct ifinfomsg *ifi;
    347 	char ifn[IF_NAMESIZE + 1];
    348 
    349 	len = link_route(nlm);
    350 	if (len != 0)
    351 		return len;
    352 	len = link_addr(nlm);
    353 	if (len != 0)
    354 		return len;
    355 
    356 	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)
    365 		return 1;
    366 	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 &&
    374 			    ifi->ifi_change == 0)
    375 				return 1;
    376 			break;
    377 		case IFLA_IFNAME:
    378 			strlcpy(ifn, RTA_DATA(rta), sizeof(ifn));
    379 			break;
    380 		}
    381 		rta = RTA_NEXT(rta, len);
    382 	}
    383 
    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);
    400 	return 1;
    401 }
    402 
    403 int
    404 manage_link(int fd)
    405 {
    406 	return get_netlink(fd, MSG_DONTWAIT, &link_netlink);
    407 }
    408 
    409 static int
    410 send_netlink(struct nlmsghdr *hdr)
    411 {
    412 	int r;
    413 	struct iovec iov;
    414 	struct msghdr msg;
    415 	static unsigned int seq;
    416 
    417 	memset(&iov, 0, sizeof(iov));
    418 	iov.iov_base = hdr;
    419 	iov.iov_len = hdr->nlmsg_len;
    420 	memset(&msg, 0, sizeof(msg));
    421 	msg.msg_name = &sock_nl;
    422 	msg.msg_namelen = sizeof(sock_nl);
    423 	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 
    429 	if (sendmsg(sock_fd, &msg, 0) != -1)
    430 		r = get_netlink(sock_fd, 0, &err_netlink);
    431 	else
    432 		r = -1;
    433 	return r;
    434 }
    435 
    436 #define NLMSG_TAIL(nmsg)						\
    437 	((struct rtattr *)(((ptrdiff_t)(nmsg))+NLMSG_ALIGN((nmsg)->nlmsg_len)))
    438 
    439 static int
    440 add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type,
    441     const void *data, int alen)
    442 {
    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 
    460 static int
    461 add_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 
    480 struct nlma
    481 {
    482 	struct nlmsghdr hdr;
    483 	struct ifaddrmsg ifa;
    484 	char buffer[64];
    485 };
    486 
    487 struct nlmr
    488 {
    489 	struct nlmsghdr hdr;
    490 	struct rtmsg rt;
    491 	char buffer[256];
    492 };
    493 
    494 int
    495 if_address(const struct interface *iface,
    496     const struct in_addr *address, const struct in_addr *netmask,
    497     const struct in_addr *broadcast, int action)
    498 {
    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;
    510 	if (!(nlm->ifa.ifa_index = if_nametoindex(iface->name))) {
    511 		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,
    519 	    iface->name, strlen(iface->name) + 1);
    520 	add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_LOCAL,
    521 	    &address->s_addr, sizeof(address->s_addr));
    522 	if (action >= 0 && broadcast)
    523 		add_attr_l(&nlm->hdr, sizeof(*nlm), IFA_BROADCAST,
    524 		    &broadcast->s_addr, sizeof(broadcast->s_addr));
    525 
    526 	if (send_netlink(&nlm->hdr) == -1)
    527 		retval = -1;
    528 	free(nlm);
    529 	return retval;
    530 }
    531 
    532 int
    533 if_route(const struct rt *rt, int action)
    534 {
    535 	struct nlmr *nlm;
    536 	unsigned int ifindex;
    537 	int retval = 0;
    538 
    539 	if (!(ifindex = if_nametoindex(rt->iface->name))) {
    540 		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)
    548 		nlm->hdr.nlmsg_flags = NLM_F_REPLACE;
    549 	else if (action == 1)
    550 		nlm->hdr.nlmsg_flags = NLM_F_CREATE /*| NLM_F_EXCL*/;
    551 	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 
    557 	if (action == -1 || action == -2)
    558 		nlm->rt.rtm_scope = RT_SCOPE_NOWHERE;
    559 	else {
    560 		nlm->hdr.nlmsg_flags |= NLM_F_CREATE /*| NLM_F_EXCL*/;
    561 		/* We only change route metrics for kernel routes */
    562 		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)
    565 			nlm->rt.rtm_protocol = RTPROT_KERNEL;
    566 		else
    567 			nlm->rt.rtm_protocol = RTPROT_BOOT;
    568 		if (rt->gate.s_addr == INADDR_ANY ||
    569 		    (rt->gate.s_addr == rt->dest.s_addr &&
    570 			rt->net.s_addr == INADDR_BROADCAST))
    571 			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 
    577 	nlm->rt.rtm_dst_len = inet_ntocidr(rt->net);
    578 	add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_DST,
    579 	    &rt->dest.s_addr, sizeof(rt->dest.s_addr));
    580 	if (nlm->rt.rtm_protocol == RTPROT_KERNEL) {
    581 		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_PREFSRC,
    582 		    &rt->iface->addr.s_addr, sizeof(rt->iface->addr.s_addr));
    583 	}
    584 	/* If destination == gateway then don't add the gateway */
    585 	if (rt->dest.s_addr != rt->gate.s_addr ||
    586 	    rt->net.s_addr != INADDR_BROADCAST)
    587 		add_attr_l(&nlm->hdr, sizeof(*nlm), RTA_GATEWAY,
    588 		    &rt->gate.s_addr, sizeof(rt->gate.s_addr));
    589 
    590 	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_OIF, ifindex);
    591 	add_attr_32(&nlm->hdr, sizeof(*nlm), RTA_PRIORITY, rt->metric);
    592 
    593 	if (send_netlink(&nlm->hdr) == -1)
    594 		retval = -1;
    595 	free(nlm);
    596 	return retval;
    597 }
    598