blob: fbc555dfee59524d8551495144ef8801ca7fdb56 [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
21#include "libnetlink.h"
Glenn L McGrathd4de9752002-11-28 12:35:46 +000022#include "libbb.h"
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000023
24void rtnl_close(struct rtnl_handle *rth)
25{
26 close(rth->fd);
27}
28
29int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
30{
31 int addr_len;
32
33 memset(rth, 0, sizeof(rth));
34
35 rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
36 if (rth->fd < 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +000037 perror_msg("Cannot open netlink socket");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000038 return -1;
39 }
40
41 memset(&rth->local, 0, sizeof(rth->local));
42 rth->local.nl_family = AF_NETLINK;
43 rth->local.nl_groups = subscriptions;
44
45 if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +000046 perror_msg("Cannot bind netlink socket");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000047 return -1;
48 }
49 addr_len = sizeof(rth->local);
50 if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +000051 perror_msg("Cannot getsockname");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000052 return -1;
53 }
54 if (addr_len != sizeof(rth->local)) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +000055 error_msg("Wrong address length %d", addr_len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000056 return -1;
57 }
58 if (rth->local.nl_family != AF_NETLINK) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +000059 error_msg("Wrong address family %d", rth->local.nl_family);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +000060 return -1;
61 }
62 rth->seq = time(NULL);
63 return 0;
64}
65
66int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
67{
68 struct {
69 struct nlmsghdr nlh;
70 struct rtgenmsg g;
71 } req;
72 struct sockaddr_nl nladdr;
73
74 memset(&nladdr, 0, sizeof(nladdr));
75 nladdr.nl_family = AF_NETLINK;
76
77 req.nlh.nlmsg_len = sizeof(req);
78 req.nlh.nlmsg_type = type;
79 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
80 req.nlh.nlmsg_pid = 0;
81 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
82 req.g.rtgen_family = family;
83
84 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
85}
86
87int rtnl_send(struct rtnl_handle *rth, char *buf, int len)
88{
89 struct sockaddr_nl nladdr;
90
91 memset(&nladdr, 0, sizeof(nladdr));
92 nladdr.nl_family = AF_NETLINK;
93
94 return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
95}
96
97int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
98{
99 struct nlmsghdr nlh;
100 struct sockaddr_nl nladdr;
101 struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
102 struct msghdr msg = {
103 (void*)&nladdr, sizeof(nladdr),
104 iov, 2,
105 NULL, 0,
106 0
107 };
108
109 memset(&nladdr, 0, sizeof(nladdr));
110 nladdr.nl_family = AF_NETLINK;
111
112 nlh.nlmsg_len = NLMSG_LENGTH(len);
113 nlh.nlmsg_type = type;
114 nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
115 nlh.nlmsg_pid = 0;
116 nlh.nlmsg_seq = rth->dump = ++rth->seq;
117
118 return sendmsg(rth->fd, &msg, 0);
119}
120
121int rtnl_dump_filter(struct rtnl_handle *rth,
122 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
123 void *arg1,
124 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
125 void *arg2)
126{
127 char buf[8192];
128 struct sockaddr_nl nladdr;
129 struct iovec iov = { buf, sizeof(buf) };
130
131 while (1) {
132 int status;
133 struct nlmsghdr *h;
134
135 struct msghdr msg = {
136 (void*)&nladdr, sizeof(nladdr),
137 &iov, 1,
138 NULL, 0,
139 0
140 };
141
142 status = recvmsg(rth->fd, &msg, 0);
143
144 if (status < 0) {
145 if (errno == EINTR)
146 continue;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000147 perror_msg("OVERRUN");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000148 continue;
149 }
150 if (status == 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000151 error_msg("EOF on netlink");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000152 return -1;
153 }
154 if (msg.msg_namelen != sizeof(nladdr)) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000155 error_msg_and_die("sender address length == %d", msg.msg_namelen);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000156 }
157
158 h = (struct nlmsghdr*)buf;
159 while (NLMSG_OK(h, status)) {
160 int err;
161
162 if (h->nlmsg_pid != rth->local.nl_pid ||
163 h->nlmsg_seq != rth->dump) {
164 if (junk) {
165 err = junk(&nladdr, h, arg2);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000166 if (err < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000167 return err;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000168 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000169 }
170 goto skip_it;
171 }
172
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000173 if (h->nlmsg_type == NLMSG_DONE) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000174 return 0;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000175 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000176 if (h->nlmsg_type == NLMSG_ERROR) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000177 struct nlmsgerr *l_err = (struct nlmsgerr*)NLMSG_DATA(h);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000178 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000179 error_msg("ERROR truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000180 } else {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000181 errno = -l_err->error;
182 perror_msg("RTNETLINK answers");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000183 }
184 return -1;
185 }
186 err = filter(&nladdr, h, arg1);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000187 if (err < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000188 return err;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000189 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000190
191skip_it:
192 h = NLMSG_NEXT(h, status);
193 }
194 if (msg.msg_flags & MSG_TRUNC) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000195 error_msg("Message truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000196 continue;
197 }
198 if (status) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000199 error_msg_and_die("!!!Remnant of size %d", status);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000200 }
201 }
202}
203
204int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
205 unsigned groups, struct nlmsghdr *answer,
206 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
207 void *jarg)
208{
209 int status;
210 unsigned seq;
211 struct nlmsghdr *h;
212 struct sockaddr_nl nladdr;
213 struct iovec iov = { (void*)n, n->nlmsg_len };
214 char buf[8192];
215 struct msghdr msg = {
216 (void*)&nladdr, sizeof(nladdr),
217 &iov, 1,
218 NULL, 0,
219 0
220 };
221
222 memset(&nladdr, 0, sizeof(nladdr));
223 nladdr.nl_family = AF_NETLINK;
224 nladdr.nl_pid = peer;
225 nladdr.nl_groups = groups;
226
227 n->nlmsg_seq = seq = ++rtnl->seq;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000228 if (answer == NULL) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000229 n->nlmsg_flags |= NLM_F_ACK;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000230 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000231 status = sendmsg(rtnl->fd, &msg, 0);
232
233 if (status < 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000234 perror_msg("Cannot talk to rtnetlink");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000235 return -1;
236 }
237
238 iov.iov_base = buf;
239
240 while (1) {
241 iov.iov_len = sizeof(buf);
242 status = recvmsg(rtnl->fd, &msg, 0);
243
244 if (status < 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000245 if (errno == EINTR) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000246 continue;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000247 }
248 perror_msg("OVERRUN");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000249 continue;
250 }
251 if (status == 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000252 error_msg("EOF on netlink");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000253 return -1;
254 }
255 if (msg.msg_namelen != sizeof(nladdr)) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000256 error_msg_and_die("sender address length == %d", msg.msg_namelen);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000257 }
258 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000259 int l_err;
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000260 int len = h->nlmsg_len;
261 int l = len - sizeof(*h);
262
263 if (l<0 || len>status) {
264 if (msg.msg_flags & MSG_TRUNC) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000265 error_msg("Truncated message");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000266 return -1;
267 }
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000268 error_msg_and_die("!!!malformed message: len=%d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000269 }
270
271 if (h->nlmsg_pid != rtnl->local.nl_pid ||
272 h->nlmsg_seq != seq) {
273 if (junk) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000274 l_err = junk(&nladdr, h, jarg);
275 if (l_err < 0) {
276 return l_err;
277 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000278 }
279 continue;
280 }
281
282 if (h->nlmsg_type == NLMSG_ERROR) {
283 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
284 if (l < sizeof(struct nlmsgerr)) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000285 error_msg("ERROR truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000286 } else {
287 errno = -err->error;
288 if (errno == 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000289 if (answer) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000290 memcpy(answer, h, h->nlmsg_len);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000291 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000292 return 0;
293 }
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000294 perror_msg("RTNETLINK answers");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000295 }
296 return -1;
297 }
298 if (answer) {
299 memcpy(answer, h, h->nlmsg_len);
300 return 0;
301 }
302
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000303 error_msg("Unexpected reply!!!");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000304
305 status -= NLMSG_ALIGN(len);
306 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
307 }
308 if (msg.msg_flags & MSG_TRUNC) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000309 error_msg("Message truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000310 continue;
311 }
312 if (status) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000313 error_msg_and_die("!!!Remnant of size %d", status);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000314 }
315 }
316}
317
318int rtnl_listen(struct rtnl_handle *rtnl,
319 int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
320 void *jarg)
321{
322 int status;
323 struct nlmsghdr *h;
324 struct sockaddr_nl nladdr;
325 struct iovec iov;
326 char buf[8192];
327 struct msghdr msg = {
328 (void*)&nladdr, sizeof(nladdr),
329 &iov, 1,
330 NULL, 0,
331 0
332 };
333
334 memset(&nladdr, 0, sizeof(nladdr));
335 nladdr.nl_family = AF_NETLINK;
336 nladdr.nl_pid = 0;
337 nladdr.nl_groups = 0;
338
339
340 iov.iov_base = buf;
341
342 while (1) {
343 iov.iov_len = sizeof(buf);
344 status = recvmsg(rtnl->fd, &msg, 0);
345
346 if (status < 0) {
347 if (errno == EINTR)
348 continue;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000349 perror_msg("OVERRUN");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000350 continue;
351 }
352 if (status == 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000353 error_msg("EOF on netlink");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000354 return -1;
355 }
356 if (msg.msg_namelen != sizeof(nladdr)) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000357 error_msg_and_die("Sender address length == %d", msg.msg_namelen);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000358 }
359 for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
360 int err;
361 int len = h->nlmsg_len;
362 int l = len - sizeof(*h);
363
364 if (l<0 || len>status) {
365 if (msg.msg_flags & MSG_TRUNC) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000366 error_msg("Truncated message");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000367 return -1;
368 }
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000369 error_msg_and_die("!!!malformed message: len=%d", len);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000370 }
371
372 err = handler(&nladdr, h, jarg);
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000373 if (err < 0) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000374 return err;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000375 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000376
377 status -= NLMSG_ALIGN(len);
378 h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
379 }
380 if (msg.msg_flags & MSG_TRUNC) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000381 error_msg("Message truncated");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000382 continue;
383 }
384 if (status) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000385 error_msg_and_die("!!!Remnant of size %d", status);
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000386 }
387 }
388}
389
390int rtnl_from_file(FILE *rtnl,
391 int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
392 void *jarg)
393{
394 int status;
395 struct sockaddr_nl nladdr;
396 char buf[8192];
397 struct nlmsghdr *h = (void*)buf;
398
399 memset(&nladdr, 0, sizeof(nladdr));
400 nladdr.nl_family = AF_NETLINK;
401 nladdr.nl_pid = 0;
402 nladdr.nl_groups = 0;
403
404 while (1) {
405 int err, len, type;
406 int l;
407
408 status = fread(&buf, 1, sizeof(*h), rtnl);
409
410 if (status < 0) {
411 if (errno == EINTR)
412 continue;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000413 perror_msg("rtnl_from_file: fread");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000414 return -1;
415 }
416 if (status == 0)
417 return 0;
418
419 len = h->nlmsg_len;
420 type= h->nlmsg_type;
421 l = len - sizeof(*h);
422
423 if (l<0 || len>sizeof(buf)) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000424 error_msg("!!!malformed message: len=%d @%lu",
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000425 len, ftell(rtnl));
426 return -1;
427 }
428
429 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
430
431 if (status < 0) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000432 perror_msg("rtnl_from_file: fread");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000433 return -1;
434 }
435 if (status < l) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000436 error_msg("rtnl-from_file: truncated message");
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000437 return -1;
438 }
439
440 err = handler(&nladdr, h, jarg);
441 if (err < 0)
442 return err;
443 }
444}
445
446int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
447{
448 int len = RTA_LENGTH(4);
449 struct rtattr *rta;
450 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
451 return -1;
452 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
453 rta->rta_type = type;
454 rta->rta_len = len;
455 memcpy(RTA_DATA(rta), &data, 4);
456 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
457 return 0;
458}
459
460int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
461{
462 int len = RTA_LENGTH(alen);
463 struct rtattr *rta;
464
465 if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
466 return -1;
467 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
468 rta->rta_type = type;
469 rta->rta_len = len;
470 memcpy(RTA_DATA(rta), data, alen);
471 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
472 return 0;
473}
474
475int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
476{
477 int len = RTA_LENGTH(4);
478 struct rtattr *subrta;
479
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000480 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000481 return -1;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000482 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000483 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
484 subrta->rta_type = type;
485 subrta->rta_len = len;
486 memcpy(RTA_DATA(subrta), &data, 4);
487 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
488 return 0;
489}
490
491int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
492{
493 struct rtattr *subrta;
494 int len = RTA_LENGTH(alen);
495
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000496 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000497 return -1;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000498 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000499 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
500 subrta->rta_type = type;
501 subrta->rta_len = len;
502 memcpy(RTA_DATA(subrta), data, alen);
503 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
504 return 0;
505}
506
507
508int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
509{
510 while (RTA_OK(rta, len)) {
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000511 if (rta->rta_type <= max) {
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000512 tb[rta->rta_type] = rta;
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000513 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000514 rta = RTA_NEXT(rta,len);
515 }
Glenn L McGrathd4de9752002-11-28 12:35:46 +0000516 if (len) {
517 error_msg("!!!Deficit %d, rta_len=%d", len, rta->rta_len);
518 }
Glenn L McGrath9a2d2722002-11-10 01:33:55 +0000519 return 0;
520}