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