blob: 100dd4078a77d1cafaee8d437b8820cc7214667e [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;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000097
shemminger8ed63ab2005-09-21 19:33:17 +000098 memset(&req, 0, sizeof(req));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000099 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
Stephen Hemmingerf31a37f2008-01-31 21:38:58 -0800106 return send(rth->fd, (void*)&req, sizeof(req), 0);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000107}
108
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000109int rtnl_send(struct rtnl_handle *rth, const char *buf, int len)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000110{
Stephen Hemmingerf31a37f2008-01-31 21:38:58 -0800111 return send(rth->fd, buf, len, 0);
112}
113
114int rtnl_send_check(struct rtnl_handle *rth, const char *buf, int len)
115{
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800116 struct nlmsghdr *h;
117 int status;
118 char resp[1024];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000119
Stephen Hemmingerf31a37f2008-01-31 21:38:58 -0800120 status = send(rth->fd, buf, len, 0);
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800121 if (status < 0)
122 return status;
123
Stephen Hemminger2d8240f2009-07-13 10:15:23 -0700124 /* Check for immediate errors */
125 status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800126 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;
Sven Anders24f38182009-11-10 09:07:26 -0800140 return -1;
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800141 }
Stephen Hemminger54bb35c2008-01-26 11:09:42 -0800142 }
143
144 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000145}
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;
shemminger8ed63ab2005-09-21 19:33:17 +0000151 struct iovec iov[2] = {
152 { .iov_base = &nlh, .iov_len = sizeof(nlh) },
153 { .iov_base = req, .iov_len = len }
154 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000155 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000156 .msg_name = &nladdr,
157 .msg_namelen = sizeof(nladdr),
158 .msg_iov = iov,
159 .msg_iovlen = 2,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000160 };
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,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000175 rtnl_filter_t filter,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000176 void *arg1,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000177 rtnl_filter_t junk,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000178 void *arg2)
179{
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000180 struct sockaddr_nl nladdr;
shemminger8ed63ab2005-09-21 19:33:17 +0000181 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];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000189
shemminger8ed63ab2005-09-21 19:33:17 +0000190 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000191 while (1) {
192 int status;
193 struct nlmsghdr *h;
194
shemminger8ed63ab2005-09-21 19:33:17 +0000195 iov.iov_len = sizeof(buf);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000196 status = recvmsg(rth->fd, &msg, 0);
197
198 if (status < 0) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800199 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000200 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800201 fprintf(stderr, "netlink receive error %s (%d)\n",
202 strerror(errno), errno);
203 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000204 }
shemminger8ed63ab2005-09-21 19:33:17 +0000205
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000206 if (status == 0) {
207 fprintf(stderr, "EOF on netlink\n");
208 return -1;
209 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000210
211 h = (struct nlmsghdr*)buf;
212 while (NLMSG_OK(h, status)) {
213 int err;
214
org[shemminger]!shemminger10f57ef2004-06-07 22:04:04 +0000215 if (nladdr.nl_pid != 0 ||
216 h->nlmsg_pid != rth->local.nl_pid ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000217 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,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000258 rtnl_filter_t junk,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000259 void *jarg)
260{
261 int status;
262 unsigned seq;
263 struct nlmsghdr *h;
264 struct sockaddr_nl nladdr;
shemmingerfb229752005-10-04 23:15:32 +0000265 struct iovec iov = {
266 .iov_base = (void*) n,
267 .iov_len = n->nlmsg_len
268 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000269 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000270 .msg_name = &nladdr,
271 .msg_namelen = sizeof(nladdr),
272 .msg_iov = &iov,
273 .msg_iovlen = 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000274 };
shemminger8ed63ab2005-09-21 19:33:17 +0000275 char buf[16384];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000276
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;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000283
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000284 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
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000294 memset(buf,0,sizeof(buf));
295
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000296 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) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800303 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000304 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800305 fprintf(stderr, "netlink receive error %s (%d)\n",
306 strerror(errno), errno);
307 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000308 }
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
org[shemminger]!shemminger10f57ef2004-06-07 22:04:04 +0000331 if (nladdr.nl_pid != peer ||
332 h->nlmsg_pid != rtnl->local.nl_pid ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000333 h->nlmsg_seq != seq) {
334 if (junk) {
335 err = junk(&nladdr, h, jarg);
336 if (err < 0)
337 return err;
338 }
shemminger4cca16f2006-03-10 23:31:46 +0000339 /* Don't forget to skip that message. */
340 status -= NLMSG_ALIGN(len);
341 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000342 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
shemminger8ed63ab2005-09-21 19:33:17 +0000381int rtnl_listen(struct rtnl_handle *rtnl,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000382 rtnl_filter_t handler,
383 void *jarg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000384{
385 int status;
386 struct nlmsghdr *h;
387 struct sockaddr_nl nladdr;
388 struct iovec iov;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000389 struct msghdr msg = {
shemminger8ed63ab2005-09-21 19:33:17 +0000390 .msg_name = &nladdr,
391 .msg_namelen = sizeof(nladdr),
392 .msg_iov = &iov,
393 .msg_iovlen = 1,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000394 };
shemminger8ed63ab2005-09-21 19:33:17 +0000395 char buf[8192];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000396
397 memset(&nladdr, 0, sizeof(nladdr));
398 nladdr.nl_family = AF_NETLINK;
399 nladdr.nl_pid = 0;
400 nladdr.nl_groups = 0;
401
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000402 iov.iov_base = buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000403 while (1) {
404 iov.iov_len = sizeof(buf);
405 status = recvmsg(rtnl->fd, &msg, 0);
406
407 if (status < 0) {
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800408 if (errno == EINTR || errno == EAGAIN)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000409 continue;
Stephen Hemmingeraa8032e2008-01-25 15:39:09 -0800410 fprintf(stderr, "netlink receive error %s (%d)\n",
411 strerror(errno), errno);
412 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000413 }
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
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000454int rtnl_from_file(FILE *rtnl, rtnl_filter_t handler,
455 void *jarg)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000456{
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;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000513 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) {
514 fprintf(stderr,"addattr32: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000515 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000516 }
6!tgraf07f94362005-01-18 13:58:49 +0000517 rta = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000518 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
shemminger8ed63ab2005-09-21 19:33:17 +0000525int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000526 int alen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000527{
528 int len = RTA_LENGTH(alen);
529 struct rtattr *rta;
530
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000531 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000532 fprintf(stderr, "addattr_l ERROR: message exceeded bound of %d\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000533 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000534 }
6!tgraf07f94362005-01-18 13:58:49 +0000535 rta = NLMSG_TAIL(n);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000536 rta->rta_type = type;
537 rta->rta_len = len;
538 memcpy(RTA_DATA(rta), data, alen);
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000539 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000540 return 0;
541}
542
6!tgraf07f94362005-01-18 13:58:49 +0000543int 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
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700556struct 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
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000589int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
590{
591 int len = RTA_LENGTH(4);
592 struct rtattr *subrta;
593
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000594 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
595 fprintf(stderr,"rta_addattr32: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000596 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000597 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000598 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
shemminger8ed63ab2005-09-21 19:33:17 +0000606int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
osdl.net!shemminger6dc9f012004-08-31 17:45:21 +0000607 const void *data, int alen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000608{
609 struct rtattr *subrta;
610 int len = RTA_LENGTH(alen);
611
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000612 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000613 fprintf(stderr,"rta_addattr_l: Error! max allowed bound %d exceeded\n",maxlen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000614 return -1;
osdl.net!shemminger007d3a32004-08-13 23:54:55 +0000615 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000616 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);
net[shemminger]!shemminger3dabdbb2005-03-30 18:18:12 +0000620 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000621 return 0;
622}
623
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000624int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
625{
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000626 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000627 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}
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000636
637int parse_rtattr_byindex(struct rtattr *tb[], int max, struct rtattr *rta, int len)
638{
639 int i = 0;
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000640
641 memset(tb, 0, sizeof(struct rtattr *) * max);
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000642 while (RTA_OK(rta, len)) {
osdl.net!shemminger175e2442005-02-07 18:17:38 +0000643 if (rta->rta_type <= max && i < max)
net[shemminger]!shemmingerc7699872004-07-07 17:05:56 +0000644 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}
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700651
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 }
Stephen Hemminger037c6352007-12-10 11:34:40 -0800661 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
Patrick McHardy2f90c9c2007-08-14 11:21:19 -0700662 return 0;
663}