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