blob: a4e91cf7c875e1a525d3ad7297b5f6132a838052 [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{
Stephen Hemminger3bfa73f2006-09-26 10:41:57 -070030 if (rth->fd >= 0) {
31 close(rth->fd);
32 rth->fd = -1;
33 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000034}
35
shemminger8ed63ab2005-09-21 19:33:17 +000036int rtnl_open_byproto(struct rtnl_handle *rth, unsigned subscriptions,
37 int protocol)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000038{
shemmingerf332d162005-07-05 22:37:15 +000039 socklen_t addr_len;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +000040 int sndbuf = 32768;
41 int rcvbuf = 32768;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000042
Stephen Hemmingerb16621c2007-05-10 19:33:21 -070043 memset(rth, 0, sizeof(*rth));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000044
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000045 rth->fd = socket(AF_NETLINK, SOCK_RAW, protocol);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000046 if (rth->fd < 0) {
47 perror("Cannot open netlink socket");
48 return -1;
49 }
50
osdl.net!shemminger007d3a32004-08-13 23:54:55 +000051 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
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000061 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
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +000086int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
87{
88 return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
89}
90
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000091int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
92{
93 struct {
94 struct nlmsghdr nlh;
95 struct rtgenmsg g;
96 } req;
97 struct sockaddr_nl nladdr;
98
99 memset(&nladdr, 0, sizeof(nladdr));
100 nladdr.nl_family = AF_NETLINK;
101
shemminger8ed63ab2005-09-21 19:33:17 +0000102 memset(&req, 0, sizeof(req));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000103 req.nlh.nlmsg_len = sizeof(req);
104 req.nlh.nlmsg_type = type;
105 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|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
shemminger8ed63ab2005-09-21 19:33:17 +0000110 return sendto(rth->fd, (void*)&req, sizeof(req), 0,
111 (struct sockaddr*)&nladdr, sizeof(nladdr));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000112}
113
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000114int rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000115{
116 struct sockaddr_nl nladdr;
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800117 struct nlmsghdr *h;
118 int status;
119 char resp[1024];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000120
121 memset(&nladdr, 0, sizeof(nladdr));
122 nladdr.nl_family = AF_NETLINK;
123
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800124 status = sendto(rth->fd, buf, len, 0,
125 (struct sockaddr*)&nladdr, sizeof(nladdr));
126 if (status < 0)
127 return status;
128
129 /* Check for errors */
130 status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT);
131 if (status < 0) {
132 if (errno == EAGAIN)
133 return 0;
134 return -1;
135 }
136
137 for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
138 h = NLMSG_NEXT(h, status)) {
139 if (h->nlmsg_type == NLMSG_ERROR) {
140 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
141 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
142 fprintf(stderr, "ERROR truncated\n");
143 else
144 errno = -err->error;
145 }
146 return -1;
147 }
148
149 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000150}
151
152int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
153{
154 struct nlmsghdr nlh;
155 struct sockaddr_nl nladdr;
shemminger8ed63ab2005-09-21 19:33:17 +0000156 struct iovec iov[2] = {
157 { .iov_base = &nlh, .iov_len = sizeof(nlh) },
158 { .iov_base = req, .iov_len = len }
159 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000160 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000161 .msg_name = &nladdr,
162 .msg_namelen = sizeof(nladdr),
163 .msg_iov = iov,
164 .msg_iovlen = 2,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000165 };
166
167 memset(&nladdr, 0, sizeof(nladdr));
168 nladdr.nl_family = AF_NETLINK;
169
170 nlh.nlmsg_len = NLMSG_LENGTH(len);
171 nlh.nlmsg_type = type;
172 nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|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
179int rtnl_dump_filter(struct rtnl_handle *rth,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000180 rtnl_filter_t filter,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000181 void *arg1,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000182 rtnl_filter_t junk,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000183 void *arg2)
184{
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000185 struct sockaddr_nl nladdr;
shemminger8ed63ab2005-09-21 19:33:17 +0000186 struct iovec iov;
187 struct msghdr msg = {
188 .msg_name = &nladdr,
189 .msg_namelen = sizeof(nladdr),
190 .msg_iov = &iov,
191 .msg_iovlen = 1,
192 };
193 char buf[16384];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000194
shemminger8ed63ab2005-09-21 19:33:17 +0000195 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000196 while (1) {
197 int status;
198 struct nlmsghdr *h;
199
shemminger8ed63ab2005-09-21 19:33:17 +0000200 iov.iov_len = sizeof(buf);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000201 status = recvmsg(rth->fd, &msg, 0);
202
203 if (status < 0) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800204 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000205 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800206 fprintf(stderr, "netlink receive error %s (%d)\n",
207 strerror(errno), errno);
208 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000209 }
shemminger8ed63ab2005-09-21 19:33:17 +0000210
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000211 if (status == 0) {
212 fprintf(stderr, "EOF on netlink\n");
213 return -1;
214 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000215
216 h = (struct nlmsghdr*)buf;
217 while (NLMSG_OK(h, status)) {
218 int err;
219
org[shemminger]!shemminger10f57ef2004-06-07 22:04:04 +0000220 if (nladdr.nl_pid != 0 ||
221 h->nlmsg_pid != rth->local.nl_pid ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000222 h->nlmsg_seq != rth->dump) {
223 if (junk) {
224 err = junk(&nladdr, h, arg2);
225 if (err < 0)
226 return err;
227 }
228 goto skip_it;
229 }
230
231 if (h->nlmsg_type == NLMSG_DONE)
232 return 0;
233 if (h->nlmsg_type == NLMSG_ERROR) {
234 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
235 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
236 fprintf(stderr, "ERROR truncated\n");
237 } else {
238 errno = -err->error;
239 perror("RTNETLINK answers");
240 }
241 return -1;
242 }
243 err = filter(&nladdr, h, arg1);
244 if (err < 0)
245 return err;
246
247skip_it:
248 h = NLMSG_NEXT(h, status);
249 }
250 if (msg.msg_flags & MSG_TRUNC) {
251 fprintf(stderr, "Message truncated\n");
252 continue;
253 }
254 if (status) {
255 fprintf(stderr, "!!!Remnant of size %d\n", status);
256 exit(1);
257 }
258 }
259}
260
261int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
262 unsigned groups, struct nlmsghdr *answer,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000263 rtnl_filter_t junk,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000264 void *jarg)
265{
266 int status;
267 unsigned seq;
268 struct nlmsghdr *h;
269 struct sockaddr_nl nladdr;
shemmingerfb229752005-10-04 23:15:32 +0000270 struct iovec iov = {
271 .iov_base = (void*) n,
272 .iov_len = n->nlmsg_len
273 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000274 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000275 .msg_name = &nladdr,
276 .msg_namelen = sizeof(nladdr),
277 .msg_iov = &iov,
278 .msg_iovlen = 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000279 };
shemminger8ed63ab2005-09-21 19:33:17 +0000280 char buf[16384];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000281
282 memset(&nladdr, 0, sizeof(nladdr));
283 nladdr.nl_family = AF_NETLINK;
284 nladdr.nl_pid = peer;
285 nladdr.nl_groups = groups;
286
287 n->nlmsg_seq = seq = ++rtnl->seq;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000288
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000289 if (answer == NULL)
290 n->nlmsg_flags |= NLM_F_ACK;
291
292 status = sendmsg(rtnl->fd, &msg, 0);
293
294 if (status < 0) {
295 perror("Cannot talk to rtnetlink");
296 return -1;
297 }
298
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000299 memset(buf,0,sizeof(buf));
300
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000301 iov.iov_base = buf;
302
303 while (1) {
304 iov.iov_len = sizeof(buf);
305 status = recvmsg(rtnl->fd, &msg, 0);
306
307 if (status < 0) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800308 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000309 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800310 fprintf(stderr, "netlink receive error %s (%d)\n",
311 strerror(errno), errno);
312 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000313 }
314 if (status == 0) {
315 fprintf(stderr, "EOF on netlink\n");
316 return -1;
317 }
318 if (msg.msg_namelen != sizeof(nladdr)) {
319 fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
320 exit(1);
321 }
322 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
323 int err;
324 int len = h->nlmsg_len;
325 int l = len - sizeof(*h);
326
327 if (l<0 || len>status) {
328 if (msg.msg_flags & MSG_TRUNC) {
329 fprintf(stderr, "Truncated message\n");
330 return -1;
331 }
332 fprintf(stderr, "!!!malformed message: len=%d\n", len);
333 exit(1);
334 }
335
org[shemminger]!shemminger10f57ef2004-06-07 22:04:04 +0000336 if (nladdr.nl_pid != peer ||
337 h->nlmsg_pid != rtnl->local.nl_pid ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000338 h->nlmsg_seq != seq) {
339 if (junk) {
340 err = junk(&nladdr, h, jarg);
341 if (err < 0)
342 return err;
343 }
shemminger4cca16f2006-03-10 23:31:46 +0000344 /* Don't forget to skip that message. */
345 status -= NLMSG_ALIGN(len);
346 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000347 continue;
348 }
349
350 if (h->nlmsg_type == NLMSG_ERROR) {
351 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
352 if (l < sizeof(struct nlmsgerr)) {
353 fprintf(stderr, "ERROR truncated\n");
354 } else {
355 errno = -err->error;
356 if (errno == 0) {
357 if (answer)
358 memcpy(answer, h, h->nlmsg_len);
359 return 0;
360 }
361 perror("RTNETLINK answers");
362 }
363 return -1;
364 }
365 if (answer) {
366 memcpy(answer, h, h->nlmsg_len);
367 return 0;
368 }
369
370 fprintf(stderr, "Unexpected reply!!!\n");
371
372 status -= NLMSG_ALIGN(len);
373 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
374 }
375 if (msg.msg_flags & MSG_TRUNC) {
376 fprintf(stderr, "Message truncated\n");
377 continue;
378 }
379 if (status) {
380 fprintf(stderr, "!!!Remnant of size %d\n", status);
381 exit(1);
382 }
383 }
384}
385
shemminger8ed63ab2005-09-21 19:33:17 +0000386int rtnl_listen(struct rtnl_handle *rtnl,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000387 rtnl_filter_t handler,
388 void *jarg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000389{
390 int status;
391 struct nlmsghdr *h;
392 struct sockaddr_nl nladdr;
393 struct iovec iov;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000394 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000395 .msg_name = &nladdr,
396 .msg_namelen = sizeof(nladdr),
397 .msg_iov = &iov,
398 .msg_iovlen = 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000399 };
shemminger8ed63ab2005-09-21 19:33:17 +0000400 char buf[8192];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000401
402 memset(&nladdr, 0, sizeof(nladdr));
403 nladdr.nl_family = AF_NETLINK;
404 nladdr.nl_pid = 0;
405 nladdr.nl_groups = 0;
406
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000407 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000408 while (1) {
409 iov.iov_len = sizeof(buf);
410 status = recvmsg(rtnl->fd, &msg, 0);
411
412 if (status < 0) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800413 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000414 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800415 fprintf(stderr, "netlink receive error %s (%d)\n",
416 strerror(errno), errno);
417 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000418 }
419 if (status == 0) {
420 fprintf(stderr, "EOF on netlink\n");
421 return -1;
422 }
423 if (msg.msg_namelen != sizeof(nladdr)) {
424 fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
425 exit(1);
426 }
427 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
428 int err;
429 int len = h->nlmsg_len;
430 int l = len - sizeof(*h);
431
432 if (l<0 || len>status) {
433 if (msg.msg_flags & MSG_TRUNC) {
434 fprintf(stderr, "Truncated message\n");
435 return -1;
436 }
437 fprintf(stderr, "!!!malformed message: len=%d\n", len);
438 exit(1);
439 }
440
441 err = handler(&nladdr, h, jarg);
442 if (err < 0)
443 return err;
444
445 status -= NLMSG_ALIGN(len);
446 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
447 }
448 if (msg.msg_flags & MSG_TRUNC) {
449 fprintf(stderr, "Message truncated\n");
450 continue;
451 }
452 if (status) {
453 fprintf(stderr, "!!!Remnant of size %d\n", status);
454 exit(1);
455 }
456 }
457}
458
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000459int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
460 void *jarg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000461{
462 int status;
463 struct sockaddr_nl nladdr;
464 char buf[8192];
465 struct nlmsghdr *h = (void*)buf;
466
467 memset(&nladdr, 0, sizeof(nladdr));
468 nladdr.nl_family = AF_NETLINK;
469 nladdr.nl_pid = 0;
470 nladdr.nl_groups = 0;
471
472 while (1) {
473 int err, len, type;
474 int l;
475
476 status = fread(&buf, 1, sizeof(*h), rtnl);
477
478 if (status < 0) {
479 if (errno == EINTR)
480 continue;
481 perror("rtnl_from_file: fread");
482 return -1;
483 }
484 if (status == 0)
485 return 0;
486
487 len = h->nlmsg_len;
488 type= h->nlmsg_type;
489 l = len - sizeof(*h);
490
491 if (l<0 || len>sizeof(buf)) {
492 fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
493 len, ftell(rtnl));
494 return -1;
495 }
496
497 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
498
499 if (status < 0) {
500 perror("rtnl_from_file: fread");
501 return -1;
502 }
503 if (status < l) {
504 fprintf(stderr, "rtnl-from_file: truncated message\n");
505 return -1;
506 }
507
508 err = handler(&nladdr, h, jarg);
509 if (err < 0)
510 return err;
511 }
512}
513
514int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
515{
516 int len = RTA_LENGTH(4);
517 struct rtattr *rta;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000518 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
519 fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000520 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000521 }
6!tgraf07f94362005-01-18 13:58:49 +0000522 rta = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000523 rta->rta_type = type;
524 rta->rta_len = len;
525 memcpy(RTA_DATA(rta), &data, 4);
526 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
527 return 0;
528}
529
shemminger8ed63ab2005-09-21 19:33:17 +0000530int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000531 int alen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000532{
533 int len = RTA_LENGTH(alen);
534 struct rtattr *rta;
535
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000536 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000537 fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000538 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000539 }
6!tgraf07f94362005-01-18 13:58:49 +0000540 rta = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000541 rta->rta_type = type;
542 rta->rta_len = len;
543 memcpy(RTA_DATA(rta), data, alen);
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000544 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000545 return 0;
546}
547
6!tgraf07f94362005-01-18 13:58:49 +0000548int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
549{
550 if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
551 fprintf(stderr, "addraw_l ERROR: message exceeded bound of %d\n",maxlen);
552 return -1;
553 }
554
555 memcpy(NLMSG_TAIL(n), data, len);
556 memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
557 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
558 return 0;
559}
560
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700561struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
562{
563 struct rtattr *nest = NLMSG_TAIL(n);
564
565 addattr_l(n, maxlen, type, NULL, 0);
566 return nest;
567}
568
569int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
570{
571 nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
572 return n->nlmsg_len;
573}
574
575struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
576 const void *data, int len)
577{
578 struct rtattr *start = NLMSG_TAIL(n);
579
580 addattr_l(n, maxlen, type, data, len);
581 addattr_nest(n, maxlen, type);
582 return start;
583}
584
585int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
586{
587 struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
588
589 start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
590 addattr_nest_end(n, nest);
591 return n->nlmsg_len;
592}
593
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000594int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
595{
596 int len = RTA_LENGTH(4);
597 struct rtattr *subrta;
598
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000599 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
600 fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000601 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000602 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000603 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
604 subrta->rta_type = type;
605 subrta->rta_len = len;
606 memcpy(RTA_DATA(subrta), &data, 4);
607 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
608 return 0;
609}
610
shemminger8ed63ab2005-09-21 19:33:17 +0000611int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000612 const void *data, int alen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000613{
614 struct rtattr *subrta;
615 int len = RTA_LENGTH(alen);
616
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000617 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000618 fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000619 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000620 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000621 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
622 subrta->rta_type = type;
623 subrta->rta_len = len;
624 memcpy(RTA_DATA(subrta), data, alen);
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000625 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000626 return 0;
627}
628
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000629int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
630{
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000631 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000632 while (RTA_OK(rta, len)) {
633 if (rta->rta_type <= max)
634 tb[rta->rta_type] = rta;
635 rta = RTA_NEXT(rta,len);
636 }
637 if (len)
638 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
639 return 0;
640}
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000641
642int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
643{
644 int i = 0;
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000645
646 memset(tb, 0, sizeof(struct rtattr *) * max);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000647 while (RTA_OK(rta, len)) {
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000648 if (rta->rta_type <= max && i < max)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000649 tb[i++] = rta;
650 rta = RTA_NEXT(rta,len);
651 }
652 if (len)
653 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
654 return i;
655}
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700656
657int __parse_rtattr_nested_compat(struct rtattr *tb[], int max, struct rtattr *rta,
658 int len)
659{
660 if (RTA_PAYLOAD(rta) < len)
661 return -1;
662 if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
663 rta = RTA_DATA(rta) + RTA_ALIGN(len);
664 return parse_rtattr_nested(tb, max, rta);
665 }
Stephen Hemminger037c6352007-12-10 11:34:40 -0800666 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700667 return 0;
668}