blob: 82f811bbbbb7f970f2d0120ccc2543b118ad8266 [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
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{
30 close(rth->fd);
31}
32
shemminger8ed63ab2005-09-21 19:33:17 +000033int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
34 int protocol)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000035{
shemmingerf332d162005-07-05 22:37:15 +000036 socklen_t addr_len;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +000037 int sndbuf = 32768;
38 int rcvbuf = 32768;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000039
40 memset(rth, 0, sizeof(rth));
41
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000042 rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000043 if (rth->fd < 0) {
44 perror("Cannot open netlink socket");
45 return -1;
46 }
47
osdl.net!shemminger007d3a32004-08-13 23:54:55 +000048 if (setsockopt(rth->fd,SOL_SOCKET,SO_SNDBUF,&sndbuf,sizeof(sndbuf)) < 0) {
49 perror("SO_SNDBUF");
50 return -1;
51 }
52
53 if (setsockopt(rth->fd,SOL_SOCKET,SO_RCVBUF,&rcvbuf,sizeof(rcvbuf)) < 0) {
54 perror("SO_RCVBUF");
55 return -1;
56 }
57
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000058 memset(&rth->local, 0, sizeof(rth->local));
59 rth->local.nl_family = AF_NETLINK;
60 rth->local.nl_groups = subscriptions;
61
62 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
63 perror("Cannot bind netlink socket");
64 return -1;
65 }
66 addr_len = sizeof(rth->local);
67 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
68 perror("Cannot getsockname");
69 return -1;
70 }
71 if (addr_len != sizeof(rth->local)) {
72 fprintf(stderr, "Wrong address length %d\n", addr_len);
73 return -1;
74 }
75 if (rth->local.nl_family != AF_NETLINK) {
76 fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
77 return -1;
78 }
79 rth->seq = time(NULL);
80 return 0;
81}
82
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000083int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
84{
85 return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
86}
87
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000088int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
89{
90 struct {
91 struct nlmsghdr nlh;
92 struct rtgenmsg g;
93 } req;
94 struct sockaddr_nl nladdr;
95
96 memset(&nladdr, 0, sizeof(nladdr));
97 nladdr.nl_family = AF_NETLINK;
98
shemminger8ed63ab2005-09-21 19:33:17 +000099 memset(&req, 0, sizeof(req));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000100 req.nlh.nlmsg_len = sizeof(req);
101 req.nlh.nlmsg_type = type;
102 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
103 req.nlh.nlmsg_pid = 0;
104 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
105 req.g.rtgen_family = family;
106
shemminger8ed63ab2005-09-21 19:33:17 +0000107 return sendto(rth->fd, (void*)&req, sizeof(req), 0,
108 (struct sockaddr*)&nladdr, sizeof(nladdr));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000109}
110
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000111int rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000112{
113 struct sockaddr_nl nladdr;
114
115 memset(&nladdr, 0, sizeof(nladdr));
116 nladdr.nl_family = AF_NETLINK;
117
118 return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
119}
120
121int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
122{
123 struct nlmsghdr nlh;
124 struct sockaddr_nl nladdr;
shemminger8ed63ab2005-09-21 19:33:17 +0000125 struct iovec iov[2] = {
126 { .iov_base = &nlh, .iov_len = sizeof(nlh) },
127 { .iov_base = req, .iov_len = len }
128 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000129 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000130 .msg_name = &nladdr,
131 .msg_namelen = sizeof(nladdr),
132 .msg_iov = iov,
133 .msg_iovlen = 2,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000134 };
135
136 memset(&nladdr, 0, sizeof(nladdr));
137 nladdr.nl_family = AF_NETLINK;
138
139 nlh.nlmsg_len = NLMSG_LENGTH(len);
140 nlh.nlmsg_type = type;
141 nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
142 nlh.nlmsg_pid = 0;
143 nlh.nlmsg_seq = rth->dump = ++rth->seq;
144
145 return sendmsg(rth->fd, &msg, 0);
146}
147
148int rtnl_dump_filter(struct rtnl_handle *rth,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000149 rtnl_filter_t filter,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000150 void *arg1,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000151 rtnl_filter_t junk,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000152 void *arg2)
153{
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000154 struct sockaddr_nl nladdr;
shemminger8ed63ab2005-09-21 19:33:17 +0000155 struct iovec iov;
156 struct msghdr msg = {
157 .msg_name = &nladdr,
158 .msg_namelen = sizeof(nladdr),
159 .msg_iov = &iov,
160 .msg_iovlen = 1,
161 };
162 char buf[16384];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000163
shemminger8ed63ab2005-09-21 19:33:17 +0000164 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000165 while (1) {
166 int status;
167 struct nlmsghdr *h;
168
shemminger8ed63ab2005-09-21 19:33:17 +0000169 iov.iov_len = sizeof(buf);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000170 status = recvmsg(rth->fd, &msg, 0);
171
172 if (status < 0) {
173 if (errno == EINTR)
174 continue;
175 perror("OVERRUN");
176 continue;
177 }
shemminger8ed63ab2005-09-21 19:33:17 +0000178
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000179 if (status == 0) {
180 fprintf(stderr, "EOF on netlink\n");
181 return -1;
182 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000183
184 h = (struct nlmsghdr*)buf;
185 while (NLMSG_OK(h, status)) {
186 int err;
187
org[shemminger]!shemminger10f57ef2004-06-07 22:04:04 +0000188 if (nladdr.nl_pid != 0 ||
189 h->nlmsg_pid != rth->local.nl_pid ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000190 h->nlmsg_seq != rth->dump) {
191 if (junk) {
192 err = junk(&nladdr, h, arg2);
193 if (err < 0)
194 return err;
195 }
196 goto skip_it;
197 }
198
199 if (h->nlmsg_type == NLMSG_DONE)
200 return 0;
201 if (h->nlmsg_type == NLMSG_ERROR) {
202 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
203 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
204 fprintf(stderr, "ERROR truncated\n");
205 } else {
206 errno = -err->error;
207 perror("RTNETLINK answers");
208 }
209 return -1;
210 }
211 err = filter(&nladdr, h, arg1);
212 if (err < 0)
213 return err;
214
215skip_it:
216 h = NLMSG_NEXT(h, status);
217 }
218 if (msg.msg_flags & MSG_TRUNC) {
219 fprintf(stderr, "Message truncated\n");
220 continue;
221 }
222 if (status) {
223 fprintf(stderr, "!!!Remnant of size %d\n", status);
224 exit(1);
225 }
226 }
227}
228
229int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
230 unsigned groups, struct nlmsghdr *answer,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000231 rtnl_filter_t junk,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000232 void *jarg)
233{
234 int status;
235 unsigned seq;
236 struct nlmsghdr *h;
237 struct sockaddr_nl nladdr;
shemminger8ed63ab2005-09-21 19:33:17 +0000238 struct iovec iov;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000239 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000240 .msg_name = &nladdr,
241 .msg_namelen = sizeof(nladdr),
242 .msg_iov = &iov,
243 .msg_iovlen = 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000244 };
shemminger8ed63ab2005-09-21 19:33:17 +0000245 char buf[16384];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000246
247 memset(&nladdr, 0, sizeof(nladdr));
248 nladdr.nl_family = AF_NETLINK;
249 nladdr.nl_pid = peer;
250 nladdr.nl_groups = groups;
251
252 n->nlmsg_seq = seq = ++rtnl->seq;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000253
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000254 if (answer == NULL)
255 n->nlmsg_flags |= NLM_F_ACK;
256
257 status = sendmsg(rtnl->fd, &msg, 0);
258
259 if (status < 0) {
260 perror("Cannot talk to rtnetlink");
261 return -1;
262 }
263
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000264 memset(buf,0,sizeof(buf));
265
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000266 iov.iov_base = buf;
267
268 while (1) {
269 iov.iov_len = sizeof(buf);
270 status = recvmsg(rtnl->fd, &msg, 0);
271
272 if (status < 0) {
273 if (errno == EINTR)
274 continue;
275 perror("OVERRUN");
276 continue;
277 }
278 if (status == 0) {
279 fprintf(stderr, "EOF on netlink\n");
280 return -1;
281 }
282 if (msg.msg_namelen != sizeof(nladdr)) {
283 fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
284 exit(1);
285 }
286 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
287 int err;
288 int len = h->nlmsg_len;
289 int l = len - sizeof(*h);
290
291 if (l<0 || len>status) {
292 if (msg.msg_flags & MSG_TRUNC) {
293 fprintf(stderr, "Truncated message\n");
294 return -1;
295 }
296 fprintf(stderr, "!!!malformed message: len=%d\n", len);
297 exit(1);
298 }
299
org[shemminger]!shemminger10f57ef2004-06-07 22:04:04 +0000300 if (nladdr.nl_pid != peer ||
301 h->nlmsg_pid != rtnl->local.nl_pid ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000302 h->nlmsg_seq != seq) {
303 if (junk) {
304 err = junk(&nladdr, h, jarg);
305 if (err < 0)
306 return err;
307 }
308 continue;
309 }
310
311 if (h->nlmsg_type == NLMSG_ERROR) {
312 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
313 if (l < sizeof(struct nlmsgerr)) {
314 fprintf(stderr, "ERROR truncated\n");
315 } else {
316 errno = -err->error;
317 if (errno == 0) {
318 if (answer)
319 memcpy(answer, h, h->nlmsg_len);
320 return 0;
321 }
322 perror("RTNETLINK answers");
323 }
324 return -1;
325 }
326 if (answer) {
327 memcpy(answer, h, h->nlmsg_len);
328 return 0;
329 }
330
331 fprintf(stderr, "Unexpected reply!!!\n");
332
333 status -= NLMSG_ALIGN(len);
334 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
335 }
336 if (msg.msg_flags & MSG_TRUNC) {
337 fprintf(stderr, "Message truncated\n");
338 continue;
339 }
340 if (status) {
341 fprintf(stderr, "!!!Remnant of size %d\n", status);
342 exit(1);
343 }
344 }
345}
346
shemminger8ed63ab2005-09-21 19:33:17 +0000347int rtnl_listen(struct rtnl_handle *rtnl,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000348 rtnl_filter_t handler,
349 void *jarg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000350{
351 int status;
352 struct nlmsghdr *h;
353 struct sockaddr_nl nladdr;
354 struct iovec iov;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000355 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000356 .msg_name = &nladdr,
357 .msg_namelen = sizeof(nladdr),
358 .msg_iov = &iov,
359 .msg_iovlen = 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000360 };
shemminger8ed63ab2005-09-21 19:33:17 +0000361 char buf[8192];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000362
363 memset(&nladdr, 0, sizeof(nladdr));
364 nladdr.nl_family = AF_NETLINK;
365 nladdr.nl_pid = 0;
366 nladdr.nl_groups = 0;
367
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000368 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000369 while (1) {
370 iov.iov_len = sizeof(buf);
371 status = recvmsg(rtnl->fd, &msg, 0);
372
373 if (status < 0) {
374 if (errno == EINTR)
375 continue;
376 perror("OVERRUN");
377 continue;
378 }
379 if (status == 0) {
380 fprintf(stderr, "EOF on netlink\n");
381 return -1;
382 }
383 if (msg.msg_namelen != sizeof(nladdr)) {
384 fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
385 exit(1);
386 }
387 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
388 int err;
389 int len = h->nlmsg_len;
390 int l = len - sizeof(*h);
391
392 if (l<0 || len>status) {
393 if (msg.msg_flags & MSG_TRUNC) {
394 fprintf(stderr, "Truncated message\n");
395 return -1;
396 }
397 fprintf(stderr, "!!!malformed message: len=%d\n", len);
398 exit(1);
399 }
400
401 err = handler(&nladdr, h, jarg);
402 if (err < 0)
403 return err;
404
405 status -= NLMSG_ALIGN(len);
406 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
407 }
408 if (msg.msg_flags & MSG_TRUNC) {
409 fprintf(stderr, "Message truncated\n");
410 continue;
411 }
412 if (status) {
413 fprintf(stderr, "!!!Remnant of size %d\n", status);
414 exit(1);
415 }
416 }
417}
418
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000419int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
420 void *jarg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000421{
422 int status;
423 struct sockaddr_nl nladdr;
424 char buf[8192];
425 struct nlmsghdr *h = (void*)buf;
426
427 memset(&nladdr, 0, sizeof(nladdr));
428 nladdr.nl_family = AF_NETLINK;
429 nladdr.nl_pid = 0;
430 nladdr.nl_groups = 0;
431
432 while (1) {
433 int err, len, type;
434 int l;
435
436 status = fread(&buf, 1, sizeof(*h), rtnl);
437
438 if (status < 0) {
439 if (errno == EINTR)
440 continue;
441 perror("rtnl_from_file: fread");
442 return -1;
443 }
444 if (status == 0)
445 return 0;
446
447 len = h->nlmsg_len;
448 type= h->nlmsg_type;
449 l = len - sizeof(*h);
450
451 if (l<0 || len>sizeof(buf)) {
452 fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
453 len, ftell(rtnl));
454 return -1;
455 }
456
457 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
458
459 if (status < 0) {
460 perror("rtnl_from_file: fread");
461 return -1;
462 }
463 if (status < l) {
464 fprintf(stderr, "rtnl-from_file: truncated message\n");
465 return -1;
466 }
467
468 err = handler(&nladdr, h, jarg);
469 if (err < 0)
470 return err;
471 }
472}
473
474int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
475{
476 int len = RTA_LENGTH(4);
477 struct rtattr *rta;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000478 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
479 fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000480 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000481 }
6!tgraf07f94362005-01-18 13:58:49 +0000482 rta = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000483 rta->rta_type = type;
484 rta->rta_len = len;
485 memcpy(RTA_DATA(rta), &data, 4);
486 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
487 return 0;
488}
489
shemminger8ed63ab2005-09-21 19:33:17 +0000490int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000491 int alen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000492{
493 int len = RTA_LENGTH(alen);
494 struct rtattr *rta;
495
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000496 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000497 fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000498 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000499 }
6!tgraf07f94362005-01-18 13:58:49 +0000500 rta = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000501 rta->rta_type = type;
502 rta->rta_len = len;
503 memcpy(RTA_DATA(rta), data, alen);
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000504 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000505 return 0;
506}
507
6!tgraf07f94362005-01-18 13:58:49 +0000508int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
509{
510 if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
511 fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
512 return -1;
513 }
514
515 memcpy(NLMSG_TAIL(n), data, len);
516 memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
517 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
518 return 0;
519}
520
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000521int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
522{
523 int len = RTA_LENGTH(4);
524 struct rtattr *subrta;
525
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000526 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
527 fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000528 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000529 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000530 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
531 subrta->rta_type = type;
532 subrta->rta_len = len;
533 memcpy(RTA_DATA(subrta), &data, 4);
534 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
535 return 0;
536}
537
shemminger8ed63ab2005-09-21 19:33:17 +0000538int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000539 const void *data, int alen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000540{
541 struct rtattr *subrta;
542 int len = RTA_LENGTH(alen);
543
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000544 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000545 fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000546 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000547 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000548 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
549 subrta->rta_type = type;
550 subrta->rta_len = len;
551 memcpy(RTA_DATA(subrta), data, alen);
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000552 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000553 return 0;
554}
555
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000556int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
557{
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000558 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000559 while (RTA_OK(rta, len)) {
560 if (rta->rta_type <= max)
561 tb[rta->rta_type] = rta;
562 rta = RTA_NEXT(rta,len);
563 }
564 if (len)
565 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
566 return 0;
567}
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000568
569int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
570{
571 int i = 0;
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000572
573 memset(tb, 0, sizeof(struct rtattr *) * max);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000574 while (RTA_OK(rta, len)) {
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000575 if (rta->rta_type <= max && i < max)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000576 tb[i++] = rta;
577 rta = RTA_NEXT(rta,len);
578 }
579 if (len)
580 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
581 return i;
582}