Home | History | Annotate | Download | only in lib
      1 /*
      2  * libnetlink.c	RTnetlink service routines.
      3  *
      4  *		This program is free software; you can redistribute it and/or
      5  *		modify it under the terms of the GNU General Public License
      6  *		as published by the Free Software Foundation; either version
      7  *		2 of the License, or (at your option) any later version.
      8  *
      9  * Authors:	Alexey Kuznetsov, <kuznet (at) ms2.inr.ac.ru>
     10  *
     11  */
     12 
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <unistd.h>
     16 #include <syslog.h>
     17 #include <fcntl.h>
     18 #include <net/if_arp.h>
     19 #include <sys/socket.h>
     20 #include <netinet/in.h>
     21 #include <string.h>
     22 #include <errno.h>
     23 #include <time.h>
     24 #include <sys/uio.h>
     25 
     26 #include "libnetlink.h"
     27 
     28 int rcvbuf = 1024 * 1024;
     29 
     30 void rtnl_close(struct rtnl_handle *rth)
     31 {
     32 	if (rth->fd >= 0) {
     33 		close(rth->fd);
     34 		rth->fd = -1;
     35 	}
     36 }
     37 
     38 int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
     39 		      int protocol)
     40 {
     41 	socklen_t addr_len;
     42 	int sndbuf = 32768;
     43 
     44 	memset(rth, 0, sizeof(*rth));
     45 
     46 	rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
     47 	if (rth->fd < 0) {
     48 		perror("Cannot open netlink socket");
     49 		return -1;
     50 	}
     51 
     52 	if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
     53 		perror("SO_SNDBUF");
     54 		return -1;
     55 	}
     56 
     57 	if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
     58 		perror("SO_RCVBUF");
     59 		return -1;
     60 	}
     61 
     62 	memset(&rth->local, 0, sizeof(rth->local));
     63 	rth->local.nl_family = AF_NETLINK;
     64 	rth->local.nl_groups = subscriptions;
     65 
     66 	if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
     67 		perror("Cannot bind netlink socket");
     68 		return -1;
     69 	}
     70 	addr_len = sizeof(rth->local);
     71 	if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
     72 		perror("Cannot getsockname");
     73 		return -1;
     74 	}
     75 	if (addr_len != sizeof(rth->local)) {
     76 		fprintf(stderr, "Wrong address length %d\n", addr_len);
     77 		return -1;
     78 	}
     79 	if (rth->local.nl_family != AF_NETLINK) {
     80 		fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
     81 		return -1;
     82 	}
     83 	rth->seq = time(NULL);
     84 	return 0;
     85 }
     86 
     87 int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
     88 {
     89 	return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
     90 }
     91 
     92 int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
     93 {
     94 	struct {
     95 		struct nlmsghdr nlh;
     96 		struct rtgenmsg g;
     97 		__u16 align_rta;	/* attribute has to be 32bit aligned */
     98 		struct rtattr ext_req;
     99 		__u32 ext_filter_mask;
    100 	} req;
    101 
    102 	memset(&req, 0, sizeof(req));
    103 	req.nlh.nlmsg_len = sizeof(req);
    104 	req.nlh.nlmsg_type = type;
    105 	req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
    106 	req.nlh.nlmsg_pid = 0;
    107 	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
    108 	req.g.rtgen_family = family;
    109 
    110 	req.ext_req.rta_type = IFLA_EXT_MASK;
    111 	req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32));
    112 	req.ext_filter_mask = RTEXT_FILTER_VF;
    113 
    114 	return send(rth->fd, (void*)&req, sizeof(req), 0);
    115 }
    116 
    117 int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
    118 {
    119 	return send(rth->fd, buf, len, 0);
    120 }
    121 
    122 int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
    123 {
    124 	struct nlmsghdr *h;
    125 	int status;
    126 	char resp[1024];
    127 
    128 	status = send(rth->fd, buf, len, 0);
    129 	if (status < 0)
    130 		return status;
    131 
    132 	/* Check for immediate errors */
    133 	status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
    134 	if (status < 0) {
    135 		if (errno == EAGAIN)
    136 			return 0;
    137 		return -1;
    138 	}
    139 
    140 	for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
    141 	     h = NLMSG_NEXT(h, status)) {
    142 		if (h->nlmsg_type == NLMSG_ERROR) {
    143 			struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
    144 			if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
    145 				fprintf(stderr, "ERROR truncated\n");
    146 			else
    147 				errno = -err->error;
    148 			return -1;
    149 		}
    150 	}
    151 
    152 	return 0;
    153 }
    154 
    155 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
    156 {
    157 	struct nlmsghdr nlh;
    158 	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
    159 	struct iovec iov[2] = {
    160 		{ .iov_base = &nlh, .iov_len = sizeof(nlh) },
    161 		{ .iov_base = req, .iov_len = len }
    162 	};
    163 	struct msghdr msg = {
    164 		.msg_name = &nladdr,
    165 		.msg_namelen = 	sizeof(nladdr),
    166 		.msg_iov = iov,
    167 		.msg_iovlen = 2,
    168 	};
    169 
    170 	nlh.nlmsg_len = NLMSG_LENGTH(len);
    171 	nlh.nlmsg_type = type;
    172 	nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
    173 	nlh.nlmsg_pid = 0;
    174 	nlh.nlmsg_seq = rth->dump = ++rth->seq;
    175 
    176 	return sendmsg(rth->fd, &msg, 0);
    177 }
    178 
    179 int rtnl_dump_filter_l(struct rtnl_handle *rth,
    180 		       const struct rtnl_dump_filter_arg *arg)
    181 {
    182 	struct sockaddr_nl nladdr;
    183 	struct iovec iov;
    184 	struct msghdr msg = {
    185 		.msg_name = &nladdr,
    186 		.msg_namelen = sizeof(nladdr),
    187 		.msg_iov = &iov,
    188 		.msg_iovlen = 1,
    189 	};
    190 	char buf[16384];
    191 
    192 	iov.iov_base = buf;
    193 	while (1) {
    194 		int status;
    195 		const struct rtnl_dump_filter_arg *a;
    196 		int found_done = 0;
    197 		int msglen = 0;
    198 
    199 		iov.iov_len = sizeof(buf);
    200 		status = recvmsg(rth->fd, &msg, 0);
    201 
    202 		if (status < 0) {
    203 			if (errno == EINTR || errno == EAGAIN)
    204 				continue;
    205 			fprintf(stderr, "netlink receive error %s (%d)\n",
    206 				strerror(errno), errno);
    207 			return -1;
    208 		}
    209 
    210 		if (status == 0) {
    211 			fprintf(stderr, "EOF on netlink\n");
    212 			return -1;
    213 		}
    214 
    215 		for (a = arg; a->filter; a++) {
    216 			struct nlmsghdr *h = (struct nlmsghdr*)buf;
    217 			msglen = status;
    218 
    219 			while (NLMSG_OK(h, msglen)) {
    220 				int err;
    221 
    222 				if (nladdr.nl_pid != 0 ||
    223 				    h->nlmsg_pid != rth->local.nl_pid ||
    224 				    h->nlmsg_seq != rth->dump)
    225 					goto skip_it;
    226 
    227 				if (h->nlmsg_type == NLMSG_DONE) {
    228 					found_done = 1;
    229 					break; /* process next filter */
    230 				}
    231 				if (h->nlmsg_type == NLMSG_ERROR) {
    232 					struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
    233 					if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
    234 						fprintf(stderr,
    235 							"ERROR truncated\n");
    236 					} else {
    237 						errno = -err->error;
    238 						perror("RTNETLINK answers");
    239 					}
    240 					return -1;
    241 				}
    242 				err = a->filter(&nladdr, h, a->arg1);
    243 				if (err < 0)
    244 					return err;
    245 
    246 skip_it:
    247 				h = NLMSG_NEXT(h, msglen);
    248 			}
    249 		}
    250 
    251 		if (found_done)
    252 			return 0;
    253 
    254 		if (msg.msg_flags & MSG_TRUNC) {
    255 			fprintf(stderr, "Message truncated\n");
    256 			continue;
    257 		}
    258 		if (msglen) {
    259 			fprintf(stderr, "!!!Remnant of size %d\n", msglen);
    260 			exit(1);
    261 		}
    262 	}
    263 }
    264 
    265 int rtnl_dump_filter(struct rtnl_handle *rth,
    266 		     rtnl_filter_t filter,
    267 		     void *arg1)
    268 {
    269 	const struct rtnl_dump_filter_arg a[2] = {
    270 		{ .filter = filter, .arg1 = arg1, },
    271 		{ .filter = NULL,   .arg1 = NULL, },
    272 	};
    273 
    274 	return rtnl_dump_filter_l(rth, a);
    275 }
    276 
    277 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
    278 	      unsigned groups, struct nlmsghdr *answer)
    279 {
    280 	int status;
    281 	unsigned seq;
    282 	struct nlmsghdr *h;
    283 	struct sockaddr_nl nladdr;
    284 	struct iovec iov = {
    285 		.iov_base = (void*) n,
    286 		.iov_len = n->nlmsg_len
    287 	};
    288 	struct msghdr msg = {
    289 		.msg_name = &nladdr,
    290 		.msg_namelen = sizeof(nladdr),
    291 		.msg_iov = &iov,
    292 		.msg_iovlen = 1,
    293 	};
    294 	char   buf[16384];
    295 
    296 	memset(&nladdr, 0, sizeof(nladdr));
    297 	nladdr.nl_family = AF_NETLINK;
    298 	nladdr.nl_pid = peer;
    299 	nladdr.nl_groups = groups;
    300 
    301 	n->nlmsg_seq = seq = ++rtnl->seq;
    302 
    303 	if (answer == NULL)
    304 		n->nlmsg_flags |= NLM_F_ACK;
    305 
    306 	status = sendmsg(rtnl->fd, &msg, 0);
    307 
    308 	if (status < 0) {
    309 		perror("Cannot talk to rtnetlink");
    310 		return -1;
    311 	}
    312 
    313 	memset(buf,0,sizeof(buf));
    314 
    315 	iov.iov_base = buf;
    316 
    317 	while (1) {
    318 		iov.iov_len = sizeof(buf);
    319 		status = recvmsg(rtnl->fd, &msg, 0);
    320 
    321 		if (status < 0) {
    322 			if (errno == EINTR || errno == EAGAIN)
    323 				continue;
    324 			fprintf(stderr, "netlink receive error %s (%d)\n",
    325 				strerror(errno), errno);
    326 			return -1;
    327 		}
    328 		if (status == 0) {
    329 			fprintf(stderr, "EOF on netlink\n");
    330 			return -1;
    331 		}
    332 		if (msg.msg_namelen != sizeof(nladdr)) {
    333 			fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
    334 			exit(1);
    335 		}
    336 		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
    337 			int len = h->nlmsg_len;
    338 			int l = len - sizeof(*h);
    339 
    340 			if (l < 0 || len>status) {
    341 				if (msg.msg_flags & MSG_TRUNC) {
    342 					fprintf(stderr, "Truncated message\n");
    343 					return -1;
    344 				}
    345 				fprintf(stderr, "!!!malformed message: len=%d\n", len);
    346 				exit(1);
    347 			}
    348 
    349 			if (nladdr.nl_pid != peer ||
    350 			    h->nlmsg_pid != rtnl->local.nl_pid ||
    351 			    h->nlmsg_seq != seq) {
    352 				/* Don't forget to skip that message. */
    353 				status -= NLMSG_ALIGN(len);
    354 				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
    355 				continue;
    356 			}
    357 
    358 			if (h->nlmsg_type == NLMSG_ERROR) {
    359 				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
    360 				if (l < sizeof(struct nlmsgerr)) {
    361 					fprintf(stderr, "ERROR truncated\n");
    362 				} else {
    363 					errno = -err->error;
    364 					if (errno == 0) {
    365 						if (answer)
    366 							memcpy(answer, h, h->nlmsg_len);
    367 						return 0;
    368 					}
    369 					perror("RTNETLINK answers");
    370 				}
    371 				return -1;
    372 			}
    373 			if (answer) {
    374 				memcpy(answer, h, h->nlmsg_len);
    375 				return 0;
    376 			}
    377 
    378 			fprintf(stderr, "Unexpected reply!!!\n");
    379 
    380 			status -= NLMSG_ALIGN(len);
    381 			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
    382 		}
    383 		if (msg.msg_flags & MSG_TRUNC) {
    384 			fprintf(stderr, "Message truncated\n");
    385 			continue;
    386 		}
    387 		if (status) {
    388 			fprintf(stderr, "!!!Remnant of size %d\n", status);
    389 			exit(1);
    390 		}
    391 	}
    392 }
    393 
    394 int rtnl_listen(struct rtnl_handle *rtnl,
    395 		rtnl_filter_t handler,
    396 		void *jarg)
    397 {
    398 	int status;
    399 	struct nlmsghdr *h;
    400 	struct sockaddr_nl nladdr;
    401 	struct iovec iov;
    402 	struct msghdr msg = {
    403 		.msg_name = &nladdr,
    404 		.msg_namelen = sizeof(nladdr),
    405 		.msg_iov = &iov,
    406 		.msg_iovlen = 1,
    407 	};
    408 	char   buf[8192];
    409 
    410 	memset(&nladdr, 0, sizeof(nladdr));
    411 	nladdr.nl_family = AF_NETLINK;
    412 	nladdr.nl_pid = 0;
    413 	nladdr.nl_groups = 0;
    414 
    415 	iov.iov_base = buf;
    416 	while (1) {
    417 		iov.iov_len = sizeof(buf);
    418 		status = recvmsg(rtnl->fd, &msg, 0);
    419 
    420 		if (status < 0) {
    421 			if (errno == EINTR || errno == EAGAIN)
    422 				continue;
    423 			fprintf(stderr, "netlink receive error %s (%d)\n",
    424 				strerror(errno), errno);
    425 			if (errno == ENOBUFS)
    426 				continue;
    427 			return -1;
    428 		}
    429 		if (status == 0) {
    430 			fprintf(stderr, "EOF on netlink\n");
    431 			return -1;
    432 		}
    433 		if (msg.msg_namelen != sizeof(nladdr)) {
    434 			fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
    435 			exit(1);
    436 		}
    437 		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
    438 			int err;
    439 			int len = h->nlmsg_len;
    440 			int l = len - sizeof(*h);
    441 
    442 			if (l<0 || len>status) {
    443 				if (msg.msg_flags & MSG_TRUNC) {
    444 					fprintf(stderr, "Truncated message\n");
    445 					return -1;
    446 				}
    447 				fprintf(stderr, "!!!malformed message: len=%d\n", len);
    448 				exit(1);
    449 			}
    450 
    451 			err = handler(&nladdr, h, jarg);
    452 			if (err < 0)
    453 				return err;
    454 
    455 			status -= NLMSG_ALIGN(len);
    456 			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
    457 		}
    458 		if (msg.msg_flags & MSG_TRUNC) {
    459 			fprintf(stderr, "Message truncated\n");
    460 			continue;
    461 		}
    462 		if (status) {
    463 			fprintf(stderr, "!!!Remnant of size %d\n", status);
    464 			exit(1);
    465 		}
    466 	}
    467 }
    468 
    469 int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
    470 		   void *jarg)
    471 {
    472 	int status;
    473 	struct sockaddr_nl nladdr;
    474 	char   buf[8192];
    475 	struct nlmsghdr *h = (void*)buf;
    476 
    477 	memset(&nladdr, 0, sizeof(nladdr));
    478 	nladdr.nl_family = AF_NETLINK;
    479 	nladdr.nl_pid = 0;
    480 	nladdr.nl_groups = 0;
    481 
    482 	while (1) {
    483 		int err, len;
    484 		int l;
    485 
    486 		status = fread(&buf, 1, sizeof(*h), rtnl);
    487 
    488 		if (status < 0) {
    489 			if (errno == EINTR)
    490 				continue;
    491 			perror("rtnl_from_file: fread");
    492 			return -1;
    493 		}
    494 		if (status == 0)
    495 			return 0;
    496 
    497 		len = h->nlmsg_len;
    498 		l = len - sizeof(*h);
    499 
    500 		if (l<0 || len>sizeof(buf)) {
    501 			fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
    502 				len, ftell(rtnl));
    503 			return -1;
    504 		}
    505 
    506 		status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
    507 
    508 		if (status < 0) {
    509 			perror("rtnl_from_file: fread");
    510 			return -1;
    511 		}
    512 		if (status < l) {
    513 			fprintf(stderr, "rtnl-from_file: truncated message\n");
    514 			return -1;
    515 		}
    516 
    517 		err = handler(&nladdr, h, jarg);
    518 		if (err < 0)
    519 			return err;
    520 	}
    521 }
    522 
    523 int addattr(struct nlmsghdr *n, int maxlen, int type)
    524 {
    525 	return addattr_l(n, maxlen, type, NULL, 0);
    526 }
    527 
    528 int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
    529 {
    530 	return addattr_l(n, maxlen, type, &data, sizeof(__u8));
    531 }
    532 
    533 int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
    534 {
    535 	return addattr_l(n, maxlen, type, &data, sizeof(__u16));
    536 }
    537 
    538 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
    539 {
    540 	return addattr_l(n, maxlen, type, &data, sizeof(__u32));
    541 }
    542 
    543 int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
    544 {
    545 	return addattr_l(n, maxlen, type, &data, sizeof(__u64));
    546 }
    547 
    548 int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
    549 {
    550 	return addattr_l(n, maxlen, type, str, strlen(str)+1);
    551 }
    552 
    553 int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
    554 	      int alen)
    555 {
    556 	int len = RTA_LENGTH(alen);
    557 	struct rtattr *rta;
    558 
    559 	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
    560 		fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
    561 		return -1;
    562 	}
    563 	rta = NLMSG_TAIL(n);
    564 	rta->rta_type = type;
    565 	rta->rta_len = len;
    566 	memcpy(RTA_DATA(rta), data, alen);
    567 	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
    568 	return 0;
    569 }
    570 
    571 int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
    572 {
    573 	if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
    574 		fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
    575 		return -1;
    576 	}
    577 
    578 	memcpy(NLMSG_TAIL(n), data, len);
    579 	memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
    580 	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
    581 	return 0;
    582 }
    583 
    584 struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
    585 {
    586 	struct rtattr *nest = NLMSG_TAIL(n);
    587 
    588 	addattr_l(n, maxlen, type, NULL, 0);
    589 	return nest;
    590 }
    591 
    592 int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
    593 {
    594 	nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
    595 	return n->nlmsg_len;
    596 }
    597 
    598 struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
    599 				   const void *data, int len)
    600 {
    601 	struct rtattr *start = NLMSG_TAIL(n);
    602 
    603 	addattr_l(n, maxlen, type, data, len);
    604 	addattr_nest(n, maxlen, type);
    605 	return start;
    606 }
    607 
    608 int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
    609 {
    610 	struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
    611 
    612 	start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
    613 	addattr_nest_end(n, nest);
    614 	return n->nlmsg_len;
    615 }
    616 
    617 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
    618 {
    619 	int len = RTA_LENGTH(4);
    620 	struct rtattr *subrta;
    621 
    622 	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
    623 		fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
    624 		return -1;
    625 	}
    626 	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
    627 	subrta->rta_type = type;
    628 	subrta->rta_len = len;
    629 	memcpy(RTA_DATA(subrta), &data, 4);
    630 	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
    631 	return 0;
    632 }
    633 
    634 int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
    635 		  const void *data, int alen)
    636 {
    637 	struct rtattr *subrta;
    638 	int len = RTA_LENGTH(alen);
    639 
    640 	if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
    641 		fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
    642 		return -1;
    643 	}
    644 	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
    645 	subrta->rta_type = type;
    646 	subrta->rta_len = len;
    647 	memcpy(RTA_DATA(subrta), data, alen);
    648 	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
    649 	return 0;
    650 }
    651 
    652 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
    653 {
    654 	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
    655 	while (RTA_OK(rta, len)) {
    656 		if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
    657 			tb[rta->rta_type] = rta;
    658 		rta = RTA_NEXT(rta,len);
    659 	}
    660 	if (len)
    661 		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
    662 	return 0;
    663 }
    664 
    665 int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
    666 {
    667 	int i = 0;
    668 
    669 	memset(tb, 0, sizeof(struct rtattr *) * max);
    670 	while (RTA_OK(rta, len)) {
    671 		if (rta->rta_type <= max && i < max)
    672 			tb[i++] = rta;
    673 		rta = RTA_NEXT(rta,len);
    674 	}
    675 	if (len)
    676 		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
    677 	return i;
    678 }
    679 
    680 int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
    681 			         int len)
    682 {
    683 	if (RTA_PAYLOAD(rta) < len)
    684 		return -1;
    685 	if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
    686 		rta = RTA_DATA(rta) + RTA_ALIGN(len);
    687 		return parse_rtattr_nested(tb, max, rta);
    688 	}
    689 	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
    690 	return 0;
    691 }
    692