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@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 
rtnl_close(struct rtnl_handle * rth)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 
rtnl_open_byproto(struct rtnl_handle * rth,unsigned subscriptions,int protocol)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 
rtnl_open(struct rtnl_handle * rth,unsigned subscriptions)87 int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
88 {
89 	return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
90 }
91 
rtnl_wilddump_request(struct rtnl_handle * rth,int family,int type)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 
rtnl_send(struct rtnl_handle * rth,const void * buf,int len)117 int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
118 {
119 	return send(rth->fd, buf, len, 0);
120 }
121 
rtnl_send_check(struct rtnl_handle * rth,const void * buf,int len)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 
rtnl_dump_request(struct rtnl_handle * rth,int type,void * req,int len)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 
rtnl_dump_filter_l(struct rtnl_handle * rth,const struct rtnl_dump_filter_arg * arg)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 
rtnl_dump_filter(struct rtnl_handle * rth,rtnl_filter_t filter,void * arg1)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 
rtnl_talk(struct rtnl_handle * rtnl,struct nlmsghdr * n,pid_t peer,unsigned groups,struct nlmsghdr * answer)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 
rtnl_listen(struct rtnl_handle * rtnl,rtnl_filter_t handler,void * jarg)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 
rtnl_from_file(FILE * rtnl,rtnl_filter_t handler,void * jarg)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 
addattr(struct nlmsghdr * n,int maxlen,int type)523 int addattr(struct nlmsghdr *n, int maxlen, int type)
524 {
525 	return addattr_l(n, maxlen, type, NULL, 0);
526 }
527 
addattr8(struct nlmsghdr * n,int maxlen,int type,__u8 data)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 
addattr16(struct nlmsghdr * n,int maxlen,int type,__u16 data)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 
addattr32(struct nlmsghdr * n,int maxlen,int type,__u32 data)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 
addattr64(struct nlmsghdr * n,int maxlen,int type,__u64 data)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 
addattrstrz(struct nlmsghdr * n,int maxlen,int type,const char * str)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 
addattr_l(struct nlmsghdr * n,int maxlen,int type,const void * data,int alen)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 
addraw_l(struct nlmsghdr * n,int maxlen,const void * data,int len)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 
addattr_nest(struct nlmsghdr * n,int maxlen,int type)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 
addattr_nest_end(struct nlmsghdr * n,struct rtattr * nest)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 
addattr_nest_compat(struct nlmsghdr * n,int maxlen,int type,const void * data,int len)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 
addattr_nest_compat_end(struct nlmsghdr * n,struct rtattr * start)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 
rta_addattr32(struct rtattr * rta,int maxlen,int type,__u32 data)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 
rta_addattr_l(struct rtattr * rta,int maxlen,int type,const void * data,int alen)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 
parse_rtattr(struct rtattr * tb[],int max,struct rtattr * rta,int len)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 
parse_rtattr_byindex(struct rtattr * tb[],int max,struct rtattr * rta,int len)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 
__parse_rtattr_nested_compat(struct rtattr * tb[],int max,struct rtattr * rta,int len)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