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 #ifndef SOL_NETLINK
     29 #define SOL_NETLINK 270
     30 #endif
     31 
     32 #ifndef MIN
     33 #define MIN(a, b) ((a) < (b) ? (a) : (b))
     34 #endif
     35 
     36 int rcvbuf = 1024 * 1024;
     37 
     38 void rtnl_close(struct rtnl_handle *rth)
     39 {
     40 	if (rth->fd >= 0) {
     41 		close(rth->fd);
     42 		rth->fd = -1;
     43 	}
     44 }
     45 
     46 int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
     47 		      int protocol)
     48 {
     49 	socklen_t addr_len;
     50 	int sndbuf = 32768;
     51 
     52 	memset(rth, 0, sizeof(*rth));
     53 
     54 	rth->proto = protocol;
     55 	rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
     56 	if (rth->fd < 0) {
     57 		perror("Cannot open netlink socket");
     58 		return -1;
     59 	}
     60 
     61 	if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
     62 		perror("SO_SNDBUF");
     63 		return -1;
     64 	}
     65 
     66 	if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
     67 		perror("SO_RCVBUF");
     68 		return -1;
     69 	}
     70 
     71 	memset(&rth->local, 0, sizeof(rth->local));
     72 	rth->local.nl_family = AF_NETLINK;
     73 	rth->local.nl_groups = subscriptions;
     74 
     75 	if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
     76 		perror("Cannot bind netlink socket");
     77 		return -1;
     78 	}
     79 	addr_len = sizeof(rth->local);
     80 	if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
     81 		perror("Cannot getsockname");
     82 		return -1;
     83 	}
     84 	if (addr_len != sizeof(rth->local)) {
     85 		fprintf(stderr, "Wrong address length %d\n", addr_len);
     86 		return -1;
     87 	}
     88 	if (rth->local.nl_family != AF_NETLINK) {
     89 		fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
     90 		return -1;
     91 	}
     92 	rth->seq = time(NULL);
     93 	return 0;
     94 }
     95 
     96 int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
     97 {
     98 	return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
     99 }
    100 
    101 int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
    102 {
    103 	return rtnl_wilddump_req_filter(rth, family, type, RTEXT_FILTER_VF);
    104 }
    105 
    106 int rtnl_wilddump_req_filter(struct rtnl_handle *rth, int family, int type,
    107 			    __u32 filt_mask)
    108 {
    109 	struct {
    110 		struct nlmsghdr nlh;
    111 		struct ifinfomsg ifm;
    112 		/* attribute has to be NLMSG aligned */
    113 		struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO)));
    114 		__u32 ext_filter_mask;
    115 	} req;
    116 
    117 	memset(&req, 0, sizeof(req));
    118 	req.nlh.nlmsg_len = sizeof(req);
    119 	req.nlh.nlmsg_type = type;
    120 	req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
    121 	req.nlh.nlmsg_pid = 0;
    122 	req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
    123 	req.ifm.ifi_family = family;
    124 
    125 	req.ext_req.rta_type = IFLA_EXT_MASK;
    126 	req.ext_req.rta_len = RTA_LENGTH(sizeof(__u32));
    127 	req.ext_filter_mask = filt_mask;
    128 
    129 	return send(rth->fd, (void*)&req, sizeof(req), 0);
    130 }
    131 
    132 int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
    133 {
    134 	return send(rth->fd, buf, len, 0);
    135 }
    136 
    137 int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
    138 {
    139 	struct nlmsghdr *h;
    140 	int status;
    141 	char resp[1024];
    142 
    143 	status = send(rth->fd, buf, len, 0);
    144 	if (status < 0)
    145 		return status;
    146 
    147 	/* Check for immediate errors */
    148 	status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
    149 	if (status < 0) {
    150 		if (errno == EAGAIN)
    151 			return 0;
    152 		return -1;
    153 	}
    154 
    155 	for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
    156 	     h = NLMSG_NEXT(h, status)) {
    157 		if (h->nlmsg_type == NLMSG_ERROR) {
    158 			struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
    159 			if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
    160 				fprintf(stderr, "ERROR truncated\n");
    161 			else
    162 				errno = -err->error;
    163 			return -1;
    164 		}
    165 	}
    166 
    167 	return 0;
    168 }
    169 
    170 int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
    171 {
    172 	struct nlmsghdr nlh;
    173 	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
    174 	struct iovec iov[2] = {
    175 		{ .iov_base = &nlh, .iov_len = sizeof(nlh) },
    176 		{ .iov_base = req, .iov_len = len }
    177 	};
    178 	struct msghdr msg = {
    179 		.msg_name = &nladdr,
    180 		.msg_namelen = 	sizeof(nladdr),
    181 		.msg_iov = iov,
    182 		.msg_iovlen = 2,
    183 	};
    184 
    185 	nlh.nlmsg_len = NLMSG_LENGTH(len);
    186 	nlh.nlmsg_type = type;
    187 	nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
    188 	nlh.nlmsg_pid = 0;
    189 	nlh.nlmsg_seq = rth->dump = ++rth->seq;
    190 
    191 	return sendmsg(rth->fd, &msg, 0);
    192 }
    193 
    194 int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
    195 {
    196 	struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
    197 	struct iovec iov = {
    198 		.iov_base = (void*) n,
    199 		.iov_len = n->nlmsg_len
    200 	};
    201 	struct msghdr msg = {
    202 		.msg_name = &nladdr,
    203 		.msg_namelen = sizeof(nladdr),
    204 		.msg_iov = &iov,
    205 		.msg_iovlen = 1,
    206 	};
    207 
    208 	n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
    209 	n->nlmsg_pid = 0;
    210 	n->nlmsg_seq = rth->dump = ++rth->seq;
    211 
    212 	return sendmsg(rth->fd, &msg, 0);
    213 }
    214 
    215 int rtnl_dump_filter_l(struct rtnl_handle *rth,
    216 		       const struct rtnl_dump_filter_arg *arg)
    217 {
    218 	struct sockaddr_nl nladdr;
    219 	struct iovec iov;
    220 	struct msghdr msg = {
    221 		.msg_name = &nladdr,
    222 		.msg_namelen = sizeof(nladdr),
    223 		.msg_iov = &iov,
    224 		.msg_iovlen = 1,
    225 	};
    226 	char buf[16384];
    227 	int dump_intr = 0;
    228 
    229 	iov.iov_base = buf;
    230 	while (1) {
    231 		int status;
    232 		const struct rtnl_dump_filter_arg *a;
    233 		int found_done = 0;
    234 		int msglen = 0;
    235 
    236 		iov.iov_len = sizeof(buf);
    237 		status = recvmsg(rth->fd, &msg, 0);
    238 
    239 		if (status < 0) {
    240 			if (errno == EINTR || errno == EAGAIN)
    241 				continue;
    242 			fprintf(stderr, "netlink receive error %s (%d)\n",
    243 				strerror(errno), errno);
    244 			return -1;
    245 		}
    246 
    247 		if (status == 0) {
    248 			fprintf(stderr, "EOF on netlink\n");
    249 			return -1;
    250 		}
    251 
    252 		if (rth->dump_fp)
    253 			fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp);
    254 
    255 		for (a = arg; a->filter; a++) {
    256 			struct nlmsghdr *h = (struct nlmsghdr*)buf;
    257 			msglen = status;
    258 
    259 			while (NLMSG_OK(h, msglen)) {
    260 				int err = 0;
    261 
    262 				h->nlmsg_flags &= ~a->nc_flags;
    263 
    264 				if (nladdr.nl_pid != 0 ||
    265 				    h->nlmsg_pid != rth->local.nl_pid ||
    266 				    h->nlmsg_seq != rth->dump)
    267 					goto skip_it;
    268 
    269 				if (h->nlmsg_flags & NLM_F_DUMP_INTR)
    270 					dump_intr = 1;
    271 
    272 				if (h->nlmsg_type == NLMSG_DONE) {
    273 					found_done = 1;
    274 					break; /* process next filter */
    275 				}
    276 				if (h->nlmsg_type == NLMSG_ERROR) {
    277 					struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
    278 					if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
    279 						fprintf(stderr,
    280 							"ERROR truncated\n");
    281 					} else {
    282 						errno = -err->error;
    283 						if (rth->proto == NETLINK_SOCK_DIAG &&
    284 						    (errno == ENOENT ||
    285 						     errno == EOPNOTSUPP))
    286 							return -1;
    287 
    288 						perror("RTNETLINK answers");
    289 					}
    290 					return -1;
    291 				}
    292 
    293 				if (!rth->dump_fp) {
    294 					err = a->filter(&nladdr, h, a->arg1);
    295 					if (err < 0)
    296 						return err;
    297 				}
    298 
    299 skip_it:
    300 				h = NLMSG_NEXT(h, msglen);
    301 			}
    302 		}
    303 
    304 		if (found_done) {
    305 			if (dump_intr)
    306 				fprintf(stderr,
    307 					"Dump was interrupted and may be inconsistent.\n");
    308 			return 0;
    309 		}
    310 
    311 		if (msg.msg_flags & MSG_TRUNC) {
    312 			fprintf(stderr, "Message truncated\n");
    313 			continue;
    314 		}
    315 		if (msglen) {
    316 			fprintf(stderr, "!!!Remnant of size %d\n", msglen);
    317 			exit(1);
    318 		}
    319 	}
    320 }
    321 
    322 int rtnl_dump_filter_nc(struct rtnl_handle *rth,
    323 		     rtnl_filter_t filter,
    324 		     void *arg1, __u16 nc_flags)
    325 {
    326 	const struct rtnl_dump_filter_arg a[2] = {
    327 		{ .filter = filter, .arg1 = arg1, .nc_flags = nc_flags, },
    328 		{ .filter = NULL,   .arg1 = NULL, .nc_flags = 0, },
    329 	};
    330 
    331 	return rtnl_dump_filter_l(rth, a);
    332 }
    333 
    334 int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
    335 	      struct nlmsghdr *answer, size_t maxlen)
    336 {
    337 	int status;
    338 	unsigned seq;
    339 	struct nlmsghdr *h;
    340 	struct sockaddr_nl nladdr;
    341 	struct iovec iov = {
    342 		.iov_base = (void*) n,
    343 		.iov_len = n->nlmsg_len
    344 	};
    345 	struct msghdr msg = {
    346 		.msg_name = &nladdr,
    347 		.msg_namelen = sizeof(nladdr),
    348 		.msg_iov = &iov,
    349 		.msg_iovlen = 1,
    350 	};
    351 	char   buf[32768];
    352 
    353 	memset(&nladdr, 0, sizeof(nladdr));
    354 	nladdr.nl_family = AF_NETLINK;
    355 
    356 	n->nlmsg_seq = seq = ++rtnl->seq;
    357 
    358 	if (answer == NULL)
    359 		n->nlmsg_flags |= NLM_F_ACK;
    360 
    361 	status = sendmsg(rtnl->fd, &msg, 0);
    362 	if (status < 0) {
    363 		perror("Cannot talk to rtnetlink");
    364 		return -1;
    365 	}
    366 
    367 	memset(buf,0,sizeof(buf));
    368 
    369 	iov.iov_base = buf;
    370 	while (1) {
    371 		iov.iov_len = sizeof(buf);
    372 		status = recvmsg(rtnl->fd, &msg, 0);
    373 
    374 		if (status < 0) {
    375 			if (errno == EINTR || errno == EAGAIN)
    376 				continue;
    377 			fprintf(stderr, "netlink receive error %s (%d)\n",
    378 				strerror(errno), errno);
    379 			return -1;
    380 		}
    381 		if (status == 0) {
    382 			fprintf(stderr, "EOF on netlink\n");
    383 			return -1;
    384 		}
    385 		if (msg.msg_namelen != sizeof(nladdr)) {
    386 			fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
    387 			exit(1);
    388 		}
    389 		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
    390 			int len = h->nlmsg_len;
    391 			int l = len - sizeof(*h);
    392 
    393 			if (l < 0 || len>status) {
    394 				if (msg.msg_flags & MSG_TRUNC) {
    395 					fprintf(stderr, "Truncated message\n");
    396 					return -1;
    397 				}
    398 				fprintf(stderr, "!!!malformed message: len=%d\n", len);
    399 				exit(1);
    400 			}
    401 
    402 			if (nladdr.nl_pid != 0 ||
    403 			    h->nlmsg_pid != rtnl->local.nl_pid ||
    404 			    h->nlmsg_seq != seq) {
    405 				/* Don't forget to skip that message. */
    406 				status -= NLMSG_ALIGN(len);
    407 				h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
    408 				continue;
    409 			}
    410 
    411 			if (h->nlmsg_type == NLMSG_ERROR) {
    412 				struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
    413 				if (l < sizeof(struct nlmsgerr)) {
    414 					fprintf(stderr, "ERROR truncated\n");
    415 				} else if (!err->error) {
    416 					if (answer)
    417 						memcpy(answer, h,
    418 						       MIN(maxlen, h->nlmsg_len));
    419 					return 0;
    420 				}
    421 
    422 				if (rtnl->proto != NETLINK_SOCK_DIAG)
    423 					fprintf(stderr,
    424 						"RTNETLINK answers: %s\n",
    425 						strerror(-err->error));
    426 				errno = -err->error;
    427 				return -1;
    428 			}
    429 
    430 			if (answer) {
    431 				memcpy(answer, h,
    432 				       MIN(maxlen, h->nlmsg_len));
    433 				return 0;
    434 			}
    435 
    436 			fprintf(stderr, "Unexpected reply!!!\n");
    437 
    438 			status -= NLMSG_ALIGN(len);
    439 			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
    440 		}
    441 
    442 		if (msg.msg_flags & MSG_TRUNC) {
    443 			fprintf(stderr, "Message truncated\n");
    444 			continue;
    445 		}
    446 
    447 		if (status) {
    448 			fprintf(stderr, "!!!Remnant of size %d\n", status);
    449 			exit(1);
    450 		}
    451 	}
    452 }
    453 
    454 int rtnl_listen_all_nsid(struct rtnl_handle *rth)
    455 {
    456 	unsigned int on = 1;
    457 
    458 	if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
    459 		       sizeof(on)) < 0) {
    460 		perror("NETLINK_LISTEN_ALL_NSID");
    461 		return -1;
    462 	}
    463 	rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
    464 	return 0;
    465 }
    466 
    467 int rtnl_listen(struct rtnl_handle *rtnl,
    468 		rtnl_listen_filter_t handler,
    469 		void *jarg)
    470 {
    471 	int status;
    472 	struct nlmsghdr *h;
    473 	struct sockaddr_nl nladdr;
    474 	struct iovec iov;
    475 	struct msghdr msg = {
    476 		.msg_name = &nladdr,
    477 		.msg_namelen = sizeof(nladdr),
    478 		.msg_iov = &iov,
    479 		.msg_iovlen = 1,
    480 	};
    481 	char   buf[16384];
    482 	char   cmsgbuf[BUFSIZ];
    483 
    484 	if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
    485 		msg.msg_control = &cmsgbuf;
    486 		msg.msg_controllen = sizeof(cmsgbuf);
    487 	}
    488 
    489 	memset(&nladdr, 0, sizeof(nladdr));
    490 	nladdr.nl_family = AF_NETLINK;
    491 	nladdr.nl_pid = 0;
    492 	nladdr.nl_groups = 0;
    493 
    494 	iov.iov_base = buf;
    495 	while (1) {
    496 		struct rtnl_ctrl_data ctrl;
    497 		struct cmsghdr *cmsg;
    498 
    499 		iov.iov_len = sizeof(buf);
    500 		status = recvmsg(rtnl->fd, &msg, 0);
    501 
    502 		if (status < 0) {
    503 			if (errno == EINTR || errno == EAGAIN)
    504 				continue;
    505 			fprintf(stderr, "netlink receive error %s (%d)\n",
    506 				strerror(errno), errno);
    507 			if (errno == ENOBUFS)
    508 				continue;
    509 			return -1;
    510 		}
    511 		if (status == 0) {
    512 			fprintf(stderr, "EOF on netlink\n");
    513 			return -1;
    514 		}
    515 		if (msg.msg_namelen != sizeof(nladdr)) {
    516 			fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
    517 			exit(1);
    518 		}
    519 
    520 		if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
    521 			memset(&ctrl, 0, sizeof(ctrl));
    522 			ctrl.nsid = -1;
    523 			for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
    524 			     cmsg = CMSG_NXTHDR(&msg, cmsg))
    525 				if (cmsg->cmsg_level == SOL_NETLINK &&
    526 				    cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
    527 				    cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
    528 					int *data = (int *)CMSG_DATA(cmsg);
    529 
    530 					ctrl.nsid = *data;
    531 				}
    532 		}
    533 
    534 		for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
    535 			int err;
    536 			int len = h->nlmsg_len;
    537 			int l = len - sizeof(*h);
    538 
    539 			if (l<0 || len>status) {
    540 				if (msg.msg_flags & MSG_TRUNC) {
    541 					fprintf(stderr, "Truncated message\n");
    542 					return -1;
    543 				}
    544 				fprintf(stderr, "!!!malformed message: len=%d\n", len);
    545 				exit(1);
    546 			}
    547 
    548 			err = handler(&nladdr, &ctrl, h, jarg);
    549 			if (err < 0)
    550 				return err;
    551 
    552 			status -= NLMSG_ALIGN(len);
    553 			h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
    554 		}
    555 		if (msg.msg_flags & MSG_TRUNC) {
    556 			fprintf(stderr, "Message truncated\n");
    557 			continue;
    558 		}
    559 		if (status) {
    560 			fprintf(stderr, "!!!Remnant of size %d\n", status);
    561 			exit(1);
    562 		}
    563 	}
    564 }
    565 
    566 int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
    567 		   void *jarg)
    568 {
    569 	int status;
    570 	struct sockaddr_nl nladdr;
    571 	char   buf[16384];
    572 	struct nlmsghdr *h = (void*)buf;
    573 
    574 	memset(&nladdr, 0, sizeof(nladdr));
    575 	nladdr.nl_family = AF_NETLINK;
    576 	nladdr.nl_pid = 0;
    577 	nladdr.nl_groups = 0;
    578 
    579 	while (1) {
    580 		int err, len;
    581 		int l;
    582 
    583 		status = fread(&buf, 1, sizeof(*h), rtnl);
    584 
    585 		if (status < 0) {
    586 			if (errno == EINTR)
    587 				continue;
    588 			perror("rtnl_from_file: fread");
    589 			return -1;
    590 		}
    591 		if (status == 0)
    592 			return 0;
    593 
    594 		len = h->nlmsg_len;
    595 		l = len - sizeof(*h);
    596 
    597 		if (l<0 || len>sizeof(buf)) {
    598 			fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
    599 				len, ftell(rtnl));
    600 			return -1;
    601 		}
    602 
    603 		status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
    604 
    605 		if (status < 0) {
    606 			perror("rtnl_from_file: fread");
    607 			return -1;
    608 		}
    609 		if (status < l) {
    610 			fprintf(stderr, "rtnl-from_file: truncated message\n");
    611 			return -1;
    612 		}
    613 
    614 		err = handler(&nladdr, NULL, h, jarg);
    615 		if (err < 0)
    616 			return err;
    617 	}
    618 }
    619 
    620 int addattr(struct nlmsghdr *n, int maxlen, int type)
    621 {
    622 	return addattr_l(n, maxlen, type, NULL, 0);
    623 }
    624 
    625 int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
    626 {
    627 	return addattr_l(n, maxlen, type, &data, sizeof(__u8));
    628 }
    629 
    630 int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
    631 {
    632 	return addattr_l(n, maxlen, type, &data, sizeof(__u16));
    633 }
    634 
    635 int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
    636 {
    637 	return addattr_l(n, maxlen, type, &data, sizeof(__u32));
    638 }
    639 
    640 int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
    641 {
    642 	return addattr_l(n, maxlen, type, &data, sizeof(__u64));
    643 }
    644 
    645 int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
    646 {
    647 	return addattr_l(n, maxlen, type, str, strlen(str)+1);
    648 }
    649 
    650 int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
    651 	      int alen)
    652 {
    653 	int len = RTA_LENGTH(alen);
    654 	struct rtattr *rta;
    655 
    656 	if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
    657 		fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
    658 		return -1;
    659 	}
    660 	rta = NLMSG_TAIL(n);
    661 	rta->rta_type = type;
    662 	rta->rta_len = len;
    663 	memcpy(RTA_DATA(rta), data, alen);
    664 	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
    665 	return 0;
    666 }
    667 
    668 int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
    669 {
    670 	if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
    671 		fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
    672 		return -1;
    673 	}
    674 
    675 	memcpy(NLMSG_TAIL(n), data, len);
    676 	memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
    677 	n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
    678 	return 0;
    679 }
    680 
    681 struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
    682 {
    683 	struct rtattr *nest = NLMSG_TAIL(n);
    684 
    685 	addattr_l(n, maxlen, type, NULL, 0);
    686 	return nest;
    687 }
    688 
    689 int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
    690 {
    691 	nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
    692 	return n->nlmsg_len;
    693 }
    694 
    695 struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
    696 				   const void *data, int len)
    697 {
    698 	struct rtattr *start = NLMSG_TAIL(n);
    699 
    700 	addattr_l(n, maxlen, type, data, len);
    701 	addattr_nest(n, maxlen, type);
    702 	return start;
    703 }
    704 
    705 int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
    706 {
    707 	struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
    708 
    709 	start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
    710 	addattr_nest_end(n, nest);
    711 	return n->nlmsg_len;
    712 }
    713 
    714 int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
    715 {
    716 	int len = RTA_LENGTH(4);
    717 	struct rtattr *subrta;
    718 
    719 	if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
    720 		fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
    721 		return -1;
    722 	}
    723 	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
    724 	subrta->rta_type = type;
    725 	subrta->rta_len = len;
    726 	memcpy(RTA_DATA(subrta), &data, 4);
    727 	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
    728 	return 0;
    729 }
    730 
    731 int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
    732 		  const void *data, int alen)
    733 {
    734 	struct rtattr *subrta;
    735 	int len = RTA_LENGTH(alen);
    736 
    737 	if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
    738 		fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
    739 		return -1;
    740 	}
    741 	subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
    742 	subrta->rta_type = type;
    743 	subrta->rta_len = len;
    744 	memcpy(RTA_DATA(subrta), data, alen);
    745 	rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
    746 	return 0;
    747 }
    748 
    749 int rta_addattr8(struct rtattr *rta, int maxlen, int type, __u8 data)
    750 {
    751 	return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u8));
    752 }
    753 
    754 int rta_addattr16(struct rtattr *rta, int maxlen, int type, __u16 data)
    755 {
    756 	return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u16));
    757 }
    758 
    759 int rta_addattr64(struct rtattr *rta, int maxlen, int type, __u64 data)
    760 {
    761 	return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u64));
    762 }
    763 
    764 struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type)
    765 {
    766 	struct rtattr *nest = RTA_TAIL(rta);
    767 
    768 	rta_addattr_l(rta, maxlen, type, NULL, 0);
    769 
    770 	return nest;
    771 }
    772 
    773 int rta_nest_end(struct rtattr *rta, struct rtattr *nest)
    774 {
    775 	nest->rta_len = (void *)RTA_TAIL(rta) - (void *)nest;
    776 
    777 	return rta->rta_len;
    778 }
    779 
    780 int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
    781 {
    782 	return parse_rtattr_flags(tb, max, rta, len, 0);
    783 }
    784 
    785 int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
    786 		       int len, unsigned short flags)
    787 {
    788 	unsigned short type;
    789 
    790 	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
    791 	while (RTA_OK(rta, len)) {
    792 		type = rta->rta_type & ~flags;
    793 		if ((type <= max) && (!tb[type]))
    794 			tb[type] = rta;
    795 		rta = RTA_NEXT(rta,len);
    796 	}
    797 	if (len)
    798 		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
    799 	return 0;
    800 }
    801 
    802 int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
    803 {
    804 	int i = 0;
    805 
    806 	memset(tb, 0, sizeof(struct rtattr *) * max);
    807 	while (RTA_OK(rta, len)) {
    808 		if (rta->rta_type <= max && i < max)
    809 			tb[i++] = rta;
    810 		rta = RTA_NEXT(rta,len);
    811 	}
    812 	if (len)
    813 		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
    814 	return i;
    815 }
    816 
    817 struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
    818 {
    819 	while (RTA_OK(rta, len)) {
    820 		if (rta->rta_type == type)
    821 			return rta;
    822 		rta = RTA_NEXT(rta, len);
    823 	}
    824 	if (len)
    825 		fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
    826 	return NULL;
    827 }
    828 
    829 int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
    830 			         int len)
    831 {
    832 	if (RTA_PAYLOAD(rta) < len)
    833 		return -1;
    834 	if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
    835 		rta = RTA_DATA(rta) + RTA_ALIGN(len);
    836 		return parse_rtattr_nested(tb, max, rta);
    837 	}
    838 	memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
    839 	return 0;
    840 }
    841