blob: 9390e56fb6addf1733dd6a3994116c966ac69667 [file] [log] [blame]
Glenn L McGrath9a2d2722002-11-10 01:33:55 +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
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000013#include <sys/socket.h>
Glenn L McGrath275be872002-12-16 07:37:21 +000014
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000015#include <errno.h>
Glenn L McGrath275be872002-12-16 07:37:21 +000016#include <stdio.h>
17#include <string.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000018#include <time.h>
Glenn L McGrath275be872002-12-16 07:37:21 +000019#include <unistd.h>
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000020
Eric Andersen0f08e532003-06-20 09:05:00 +000021#include <sys/uio.h>
22
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000023#include "libnetlink.h"
Glenn L McGrathd4de9752002-11-28 12:35:46 +000024#include "libbb.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000025
26void rtnl_close(struct rtnl_handle *rth)
27{
28 close(rth->fd);
29}
30
31int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
32{
33 int addr_len;
34
35 memset(rth, 0, sizeof(rth));
36
37 rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
38 if (rth->fd < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000039 bb_perror_msg("Cannot open netlink socket");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000040 return -1;
41 }
42
43 memset(&rth->local, 0, sizeof(rth->local));
44 rth->local.nl_family = AF_NETLINK;
45 rth->local.nl_groups = subscriptions;
46
47 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000048 bb_perror_msg("Cannot bind netlink socket");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000049 return -1;
50 }
51 addr_len = sizeof(rth->local);
52 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000053 bb_perror_msg("Cannot getsockname");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000054 return -1;
55 }
56 if (addr_len != sizeof(rth->local)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000057 bb_error_msg("Wrong address length %d", addr_len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000058 return -1;
59 }
60 if (rth->local.nl_family != AF_NETLINK) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000061 bb_error_msg("Wrong address family %d", rth->local.nl_family);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000062 return -1;
63 }
64 rth->seq = time(NULL);
65 return 0;
66}
67
68int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
69{
70 struct {
71 struct nlmsghdr nlh;
72 struct rtgenmsg g;
73 } req;
74 struct sockaddr_nl nladdr;
75
76 memset(&nladdr, 0, sizeof(nladdr));
77 nladdr.nl_family = AF_NETLINK;
78
79 req.nlh.nlmsg_len = sizeof(req);
80 req.nlh.nlmsg_type = type;
81 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
82 req.nlh.nlmsg_pid = 0;
83 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
84 req.g.rtgen_family = family;
85
86 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
87}
88
89int rtnl_send(struct rtnl_handle *rth, char *buf, int len)
90{
91 struct sockaddr_nl nladdr;
92
93 memset(&nladdr, 0, sizeof(nladdr));
94 nladdr.nl_family = AF_NETLINK;
95
96 return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
97}
98
99int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
100{
101 struct nlmsghdr nlh;
102 struct sockaddr_nl nladdr;
103 struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
104 struct msghdr msg = {
105 (void*)&nladdr, sizeof(nladdr),
106 iov, 2,
107 NULL, 0,
108 0
109 };
110
111 memset(&nladdr, 0, sizeof(nladdr));
112 nladdr.nl_family = AF_NETLINK;
113
114 nlh.nlmsg_len = NLMSG_LENGTH(len);
115 nlh.nlmsg_type = type;
116 nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
117 nlh.nlmsg_pid = 0;
118 nlh.nlmsg_seq = rth->dump = ++rth->seq;
119
120 return sendmsg(rth->fd, &msg, 0);
121}
122
123int rtnl_dump_filter(struct rtnl_handle *rth,
124 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
125 void *arg1,
126 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
127 void *arg2)
128{
129 char buf[8192];
130 struct sockaddr_nl nladdr;
131 struct iovec iov = { buf, sizeof(buf) };
132
133 while (1) {
134 int status;
135 struct nlmsghdr *h;
136
137 struct msghdr msg = {
138 (void*)&nladdr, sizeof(nladdr),
139 &iov, 1,
140 NULL, 0,
141 0
142 };
143
144 status = recvmsg(rth->fd, &msg, 0);
145
146 if (status < 0) {
147 if (errno == EINTR)
148 continue;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000149 bb_perror_msg("OVERRUN");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000150 continue;
151 }
152 if (status == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000153 bb_error_msg("EOF on netlink");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000154 return -1;
155 }
156 if (msg.msg_namelen != sizeof(nladdr)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000157 bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000158 }
159
160 h = (struct nlmsghdr*)buf;
161 while (NLMSG_OK(h, status)) {
162 int err;
163
164 if (h->nlmsg_pid != rth->local.nl_pid ||
165 h->nlmsg_seq != rth->dump) {
166 if (junk) {
167 err = junk(&nladdr, h, arg2);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000168 if (err < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000169 return err;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000170 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000171 }
172 goto skip_it;
173 }
174
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000175 if (h->nlmsg_type == NLMSG_DONE) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000176 return 0;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000177 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000178 if (h->nlmsg_type == NLMSG_ERROR) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000179 struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000180 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000181 bb_error_msg("ERROR truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000182 } else {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000183 errno = -l_err->error;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000184 bb_perror_msg("RTNETLINK answers");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000185 }
186 return -1;
187 }
188 err = filter(&nladdr, h, arg1);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000189 if (err < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000190 return err;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000191 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000192
193skip_it:
194 h = NLMSG_NEXT(h, status);
195 }
196 if (msg.msg_flags & MSG_TRUNC) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000197 bb_error_msg("Message truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000198 continue;
199 }
200 if (status) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000201 bb_error_msg_and_die("!!!Remnant of size %d", status);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000202 }
203 }
204}
205
206int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
207 unsigned groups, struct nlmsghdr *answer,
208 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
209 void *jarg)
210{
211 int status;
212 unsigned seq;
213 struct nlmsghdr *h;
214 struct sockaddr_nl nladdr;
215 struct iovec iov = { (void*)n, n->nlmsg_len };
216 char buf[8192];
217 struct msghdr msg = {
218 (void*)&nladdr, sizeof(nladdr),
219 &iov, 1,
220 NULL, 0,
221 0
222 };
223
224 memset(&nladdr, 0, sizeof(nladdr));
225 nladdr.nl_family = AF_NETLINK;
226 nladdr.nl_pid = peer;
227 nladdr.nl_groups = groups;
228
229 n->nlmsg_seq = seq = ++rtnl->seq;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000230 if (answer == NULL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000231 n->nlmsg_flags |= NLM_F_ACK;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000232 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000233 status = sendmsg(rtnl->fd, &msg, 0);
234
235 if (status < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000236 bb_perror_msg("Cannot talk to rtnetlink");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000237 return -1;
238 }
239
240 iov.iov_base = buf;
241
242 while (1) {
243 iov.iov_len = sizeof(buf);
244 status = recvmsg(rtnl->fd, &msg, 0);
245
246 if (status < 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000247 if (errno == EINTR) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000248 continue;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000249 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000250 bb_perror_msg("OVERRUN");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000251 continue;
252 }
253 if (status == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000254 bb_error_msg("EOF on netlink");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000255 return -1;
256 }
257 if (msg.msg_namelen != sizeof(nladdr)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000258 bb_error_msg_and_die("sender address length == %d", msg.msg_namelen);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000259 }
260 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000261 int l_err;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000262 int len = h->nlmsg_len;
263 int l = len - sizeof(*h);
264
265 if (l<0 || len>status) {
266 if (msg.msg_flags & MSG_TRUNC) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000267 bb_error_msg("Truncated message");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000268 return -1;
269 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000270 bb_error_msg_and_die("!!!malformed message: len=%d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000271 }
272
273 if (h->nlmsg_pid != rtnl->local.nl_pid ||
274 h->nlmsg_seq != seq) {
275 if (junk) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000276 l_err = junk(&nladdr, h, jarg);
277 if (l_err < 0) {
278 return l_err;
279 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000280 }
281 continue;
282 }
283
284 if (h->nlmsg_type == NLMSG_ERROR) {
285 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
286 if (l < sizeof(struct nlmsgerr)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000287 bb_error_msg("ERROR truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000288 } else {
289 errno = -err->error;
290 if (errno == 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000291 if (answer) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000292 memcpy(answer, h, h->nlmsg_len);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000293 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000294 return 0;
295 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000296 bb_perror_msg("RTNETLINK answers");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000297 }
298 return -1;
299 }
300 if (answer) {
301 memcpy(answer, h, h->nlmsg_len);
302 return 0;
303 }
304
Manuel Novoa III cad53642003-03-19 09:13:01 +0000305 bb_error_msg("Unexpected reply!!!");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000306
307 status -= NLMSG_ALIGN(len);
308 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
309 }
310 if (msg.msg_flags & MSG_TRUNC) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000311 bb_error_msg("Message truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000312 continue;
313 }
314 if (status) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000315 bb_error_msg_and_die("!!!Remnant of size %d", status);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000316 }
317 }
318}
319
320int rtnl_listen(struct rtnl_handle *rtnl,
321 int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
322 void *jarg)
323{
324 int status;
325 struct nlmsghdr *h;
326 struct sockaddr_nl nladdr;
327 struct iovec iov;
328 char buf[8192];
329 struct msghdr msg = {
330 (void*)&nladdr, sizeof(nladdr),
331 &iov, 1,
332 NULL, 0,
333 0
334 };
335
336 memset(&nladdr, 0, sizeof(nladdr));
337 nladdr.nl_family = AF_NETLINK;
338 nladdr.nl_pid = 0;
339 nladdr.nl_groups = 0;
340
341
342 iov.iov_base = buf;
343
344 while (1) {
345 iov.iov_len = sizeof(buf);
346 status = recvmsg(rtnl->fd, &msg, 0);
347
348 if (status < 0) {
349 if (errno == EINTR)
350 continue;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000351 bb_perror_msg("OVERRUN");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000352 continue;
353 }
354 if (status == 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000355 bb_error_msg("EOF on netlink");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000356 return -1;
357 }
358 if (msg.msg_namelen != sizeof(nladdr)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000359 bb_error_msg_and_die("Sender address length == %d", msg.msg_namelen);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000360 }
361 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
362 int err;
363 int len = h->nlmsg_len;
364 int l = len - sizeof(*h);
365
366 if (l<0 || len>status) {
367 if (msg.msg_flags & MSG_TRUNC) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000368 bb_error_msg("Truncated message");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000369 return -1;
370 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000371 bb_error_msg_and_die("!!!malformed message: len=%d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000372 }
373
374 err = handler(&nladdr, h, jarg);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000375 if (err < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000376 return err;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000377 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000378
379 status -= NLMSG_ALIGN(len);
380 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
381 }
382 if (msg.msg_flags & MSG_TRUNC) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000383 bb_error_msg("Message truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000384 continue;
385 }
386 if (status) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000387 bb_error_msg_and_die("!!!Remnant of size %d", status);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000388 }
389 }
390}
391
392int rtnl_from_file(FILE *rtnl,
393 int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
394 void *jarg)
395{
396 int status;
397 struct sockaddr_nl nladdr;
398 char buf[8192];
399 struct nlmsghdr *h = (void*)buf;
400
401 memset(&nladdr, 0, sizeof(nladdr));
402 nladdr.nl_family = AF_NETLINK;
403 nladdr.nl_pid = 0;
404 nladdr.nl_groups = 0;
405
406 while (1) {
407 int err, len, type;
408 int l;
409
410 status = fread(&buf, 1, sizeof(*h), rtnl);
411
412 if (status < 0) {
413 if (errno == EINTR)
414 continue;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000415 bb_perror_msg("rtnl_from_file: fread");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000416 return -1;
417 }
418 if (status == 0)
419 return 0;
420
421 len = h->nlmsg_len;
422 type= h->nlmsg_type;
423 l = len - sizeof(*h);
424
425 if (l<0 || len>sizeof(buf)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000426 bb_error_msg("!!!malformed message: len=%d @%lu",
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000427 len, ftell(rtnl));
428 return -1;
429 }
430
431 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
432
433 if (status < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000434 bb_perror_msg("rtnl_from_file: fread");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000435 return -1;
436 }
437 if (status < l) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000438 bb_error_msg("rtnl-from_file: truncated message");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000439 return -1;
440 }
441
442 err = handler(&nladdr, h, jarg);
443 if (err < 0)
444 return err;
445 }
446}
447
448int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
449{
450 int len = RTA_LENGTH(4);
451 struct rtattr *rta;
452 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
453 return -1;
454 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
455 rta->rta_type = type;
456 rta->rta_len = len;
457 memcpy(RTA_DATA(rta), &data, 4);
458 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
459 return 0;
460}
461
462int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
463{
464 int len = RTA_LENGTH(alen);
465 struct rtattr *rta;
466
467 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
468 return -1;
469 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
470 rta->rta_type = type;
471 rta->rta_len = len;
472 memcpy(RTA_DATA(rta), data, alen);
473 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
474 return 0;
475}
476
477int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
478{
479 int len = RTA_LENGTH(4);
480 struct rtattr *subrta;
481
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000482 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000483 return -1;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000484 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000485 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
486 subrta->rta_type = type;
487 subrta->rta_len = len;
488 memcpy(RTA_DATA(subrta), &data, 4);
489 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
490 return 0;
491}
492
493int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
494{
495 struct rtattr *subrta;
496 int len = RTA_LENGTH(alen);
497
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000498 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000499 return -1;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000500 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000501 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
502 subrta->rta_type = type;
503 subrta->rta_len = len;
504 memcpy(RTA_DATA(subrta), data, alen);
505 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
506 return 0;
507}
508
509
510int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
511{
512 while (RTA_OK(rta, len)) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000513 if (rta->rta_type <= max) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000514 tb[rta->rta_type] = rta;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000515 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000516 rta = RTA_NEXT(rta,len);
517 }
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000518 if (len) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000519 bb_error_msg("!!!Deficit %d, rta_len=%d", len, rta->rta_len);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000520 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000521 return 0;
522}