]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - lib/libnetlink.c
iproute2: Add netlink attribute to filter dump requests
[lisovros/iproute2_canprio.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->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 }