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