]> git.proxmox.com Git - mirror_iproute2.git/blame - lib/libnetlink.c
libnetlink: dump extack string in done message
[mirror_iproute2.git] / lib / libnetlink.c
CommitLineData
aba5acdf
SH
1/*
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>
463d9efa 15#include <stdbool.h>
aba5acdf 16#include <unistd.h>
aba5acdf
SH
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>
b05d9a3d 25#include <linux/fib_rules.h>
39360023 26#include <linux/if_addrlabel.h>
9dbe6df4 27#include <linux/if_bridge.h>
aba5acdf
SH
28
29#include "libnetlink.h"
30
449b824a
ND
31#ifndef SOL_NETLINK
32#define SOL_NETLINK 270
33#endif
34
c079e121
SH
35#ifndef MIN
36#define MIN(a, b) ((a) < (b) ? (a) : (b))
37#endif
38
7f03191f
PM
39int rcvbuf = 1024 * 1024;
40
b6432e68
SH
41#ifdef HAVE_LIBMNL
42#include <libmnl/libmnl.h>
43
44static const enum mnl_attr_data_type extack_policy[NLMSGERR_ATTR_MAX + 1] = {
45 [NLMSGERR_ATTR_MSG] = MNL_TYPE_NUL_STRING,
46 [NLMSGERR_ATTR_OFFS] = MNL_TYPE_U32,
47};
48
49static int err_attr_cb(const struct nlattr *attr, void *data)
50{
51 const struct nlattr **tb = data;
52 uint16_t type;
53
e5fa0e6f
DA
54 if (mnl_attr_type_valid(attr, NLMSGERR_ATTR_MAX) < 0) {
55 fprintf(stderr, "Invalid extack attribute\n");
b6432e68 56 return MNL_CB_ERROR;
e5fa0e6f 57 }
b6432e68
SH
58
59 type = mnl_attr_get_type(attr);
e5fa0e6f
DA
60 if (mnl_attr_validate(attr, extack_policy[type]) < 0) {
61 fprintf(stderr, "extack attribute %d failed validation\n",
62 type);
b6432e68 63 return MNL_CB_ERROR;
e5fa0e6f 64 }
b6432e68
SH
65
66 tb[type] = attr;
67 return MNL_CB_OK;
68}
69
2750252d
DA
70static void print_ext_ack_msg(bool is_err, const char *msg)
71{
72 fprintf(stderr, "%s: %s", is_err ? "Error" : "Warning", msg);
73 if (msg[strlen(msg) - 1] != '.')
74 fprintf(stderr, ".");
75 fprintf(stderr, "\n");
76}
77
b6432e68 78/* dump netlink extended ack error message */
049c5853 79int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
b6432e68 80{
e5fa0e6f 81 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
b6432e68
SH
82 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
83 const struct nlmsghdr *err_nlh = NULL;
84 unsigned int hlen = sizeof(*err);
844c37b4 85 const char *msg = NULL;
b6432e68
SH
86 uint32_t off = 0;
87
b6432e68
SH
88 /* no TLVs, nothing to do here */
89 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
90 return 0;
91
92 /* if NLM_F_CAPPED is set then the inner err msg was capped */
93 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
94 hlen += mnl_nlmsg_get_payload_len(&err->msg);
95
e5fa0e6f
DA
96 if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
97 return 0;
b6432e68
SH
98
99 if (tb[NLMSGERR_ATTR_MSG])
844c37b4 100 msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
b6432e68
SH
101
102 if (tb[NLMSGERR_ATTR_OFFS]) {
103 off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
104
105 if (off > nlh->nlmsg_len) {
106 fprintf(stderr,
107 "Invalid offset for NLMSGERR_ATTR_OFFS\n");
108 off = 0;
109 } else if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
110 err_nlh = &err->msg;
111 }
112
fb6cb307 113 if (errfn)
844c37b4 114 return errfn(msg, off, err_nlh);
fb6cb307 115
844c37b4
DA
116 if (msg && *msg != '\0') {
117 bool is_err = !!err->error;
118
2750252d
DA
119 print_ext_ack_msg(is_err, msg);
120 return is_err ? 1 : 0;
121 }
fb6cb307 122
2750252d
DA
123 return 0;
124}
125
126static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
127{
128 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
129 unsigned int hlen = sizeof(int);
130 const char *msg = NULL;
131
132 if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
133 return 0;
134
135 if (tb[NLMSGERR_ATTR_MSG])
136 msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
137
138 if (msg && *msg != '\0') {
139 bool is_err = !!error;
140
141 print_ext_ack_msg(is_err, msg);
844c37b4 142 return is_err ? 1 : 0;
fb6cb307
DA
143 }
144
145 return 0;
b6432e68
SH
146}
147#else
7d23fa55
SH
148#warning "libmnl required for error support"
149
b6432e68 150/* No extended error ack without libmnl */
049c5853 151int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
b6432e68
SH
152{
153 return 0;
154}
2750252d
DA
155
156static int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, int error)
157{
158 return 0;
159}
b6432e68
SH
160#endif
161
aba5acdf
SH
162void rtnl_close(struct rtnl_handle *rth)
163{
3bfa73ff
SH
164 if (rth->fd >= 0) {
165 close(rth->fd);
166 rth->fd = -1;
167 }
aba5acdf
SH
168}
169
2c500a4d 170int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
8ed63ab1 171 int protocol)
aba5acdf 172{
f332d169 173 socklen_t addr_len;
007d3a3e 174 int sndbuf = 32768;
b6432e68 175 int one = 1;
aba5acdf 176
b16621ca 177 memset(rth, 0, sizeof(*rth));
aba5acdf 178
8a4025f6 179 rth->proto = protocol;
bcb9d403 180 rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
aba5acdf
SH
181 if (rth->fd < 0) {
182 perror("Cannot open netlink socket");
183 return -1;
184 }
185
2c500a4d
SH
186 if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF,
187 &sndbuf, sizeof(sndbuf)) < 0) {
007d3a3e
SH
188 perror("SO_SNDBUF");
189 return -1;
190 }
191
2c500a4d
SH
192 if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF,
193 &rcvbuf, sizeof(rcvbuf)) < 0) {
007d3a3e
SH
194 perror("SO_RCVBUF");
195 return -1;
196 }
197
b6432e68
SH
198 /* Older kernels may no support extended ACK reporting */
199 setsockopt(rth->fd, SOL_NETLINK, NETLINK_EXT_ACK,
200 &one, sizeof(one));
201
aba5acdf
SH
202 memset(&rth->local, 0, sizeof(rth->local));
203 rth->local.nl_family = AF_NETLINK;
204 rth->local.nl_groups = subscriptions;
205
2c500a4d
SH
206 if (bind(rth->fd, (struct sockaddr *)&rth->local,
207 sizeof(rth->local)) < 0) {
aba5acdf
SH
208 perror("Cannot bind netlink socket");
209 return -1;
210 }
211 addr_len = sizeof(rth->local);
2c500a4d
SH
212 if (getsockname(rth->fd, (struct sockaddr *)&rth->local,
213 &addr_len) < 0) {
aba5acdf
SH
214 perror("Cannot getsockname");
215 return -1;
216 }
217 if (addr_len != sizeof(rth->local)) {
218 fprintf(stderr, "Wrong address length %d\n", addr_len);
219 return -1;
220 }
221 if (rth->local.nl_family != AF_NETLINK) {
2c500a4d
SH
222 fprintf(stderr, "Wrong address family %d\n",
223 rth->local.nl_family);
aba5acdf
SH
224 return -1;
225 }
226 rth->seq = time(NULL);
227 return 0;
228}
229
2c500a4d 230int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
c7699875 231{
232 return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
233}
234
46917d08
DA
235int rtnl_addrdump_req(struct rtnl_handle *rth, int family)
236{
237 struct {
238 struct nlmsghdr nlh;
239 struct ifaddrmsg ifm;
240 } req = {
241 .nlh.nlmsg_len = sizeof(req),
242 .nlh.nlmsg_type = RTM_GETADDR,
243 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
244 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
245 .ifm.ifa_family = family,
246 };
247
248 return send(rth->fd, &req, sizeof(req), 0);
249}
250
39360023
DA
251int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
252{
253 struct {
254 struct nlmsghdr nlh;
255 struct ifaddrlblmsg ifal;
256 } req = {
257 .nlh.nlmsg_len = sizeof(req),
258 .nlh.nlmsg_type = RTM_GETADDRLABEL,
259 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
260 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
261 .ifal.ifal_family = family,
262 };
263
264 return send(rth->fd, &req, sizeof(req), 0);
265}
266
bfb27dfa
DA
267int rtnl_routedump_req(struct rtnl_handle *rth, int family)
268{
269 struct {
270 struct nlmsghdr nlh;
271 struct rtmsg rtm;
272 } req = {
273 .nlh.nlmsg_len = sizeof(req),
274 .nlh.nlmsg_type = RTM_GETROUTE,
275 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
276 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
277 .rtm.rtm_family = family,
278 };
279
280 return send(rth->fd, &req, sizeof(req), 0);
281}
282
b05d9a3d
DA
283int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
284{
285 struct {
286 struct nlmsghdr nlh;
287 struct fib_rule_hdr frh;
288 } req = {
289 .nlh.nlmsg_len = sizeof(req),
290 .nlh.nlmsg_type = RTM_GETRULE,
291 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
292 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
293 .frh.family = family
294 };
295
296 return send(rth->fd, &req, sizeof(req), 0);
297}
298
9e0ab19c
DA
299int rtnl_neighdump_req(struct rtnl_handle *rth, int family)
300{
301 struct {
302 struct nlmsghdr nlh;
303 struct ndmsg ndm;
304 } req = {
305 .nlh.nlmsg_len = sizeof(req),
306 .nlh.nlmsg_type = RTM_GETNEIGH,
307 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
308 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
309 .ndm.ndm_family = family,
310 };
311
312 return send(rth->fd, &req, sizeof(req), 0);
313}
314
ff41db8a
DA
315int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
316{
317 struct {
318 struct nlmsghdr nlh;
319 struct ndtmsg ndtmsg;
320 } req = {
321 .nlh.nlmsg_len = sizeof(req),
322 .nlh.nlmsg_type = RTM_GETNEIGHTBL,
323 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
324 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
325 .ndtmsg.ndtm_family = family,
326 };
327
328 return send(rth->fd, &req, sizeof(req), 0);
329}
330
9dbe6df4
DA
331int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
332{
333 struct {
334 struct nlmsghdr nlh;
335 struct br_port_msg bpm;
336 } req = {
337 .nlh.nlmsg_len = sizeof(req),
338 .nlh.nlmsg_type = RTM_GETMDB,
339 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
340 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
341 .bpm.family = family,
342 };
343
344 return send(rth->fd, &req, sizeof(req), 0);
345}
346
ddee16bc
DA
347int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
348{
349 struct {
350 struct nlmsghdr nlh;
351 struct netconfmsg ncm;
352 } req = {
353 .nlh.nlmsg_len = sizeof(req),
354 .nlh.nlmsg_type = RTM_GETNETCONF,
355 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
356 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
357 .ncm.ncm_family = family,
358 };
359
360 return send(rth->fd, &req, sizeof(req), 0);
361}
362
efb0b383
DA
363int rtnl_nsiddump_req(struct rtnl_handle *rth, int family)
364{
365 struct {
366 struct nlmsghdr nlh;
367 struct rtgenmsg rtm;
368 } req = {
369 .nlh.nlmsg_len = sizeof(req),
370 .nlh.nlmsg_type = RTM_GETNSID,
371 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
372 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
373 .rtm.rtgen_family = family,
374 };
375
376 return send(rth->fd, &req, sizeof(req), 0);
377}
378
31ae2912 379int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
9eff0e5c 380{
31ae2912 381 return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
9eff0e5c
VY
382}
383
31ae2912 384int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
9eff0e5c 385 __u32 filt_mask)
aba5acdf
SH
386{
387 struct {
388 struct nlmsghdr nlh;
63338dca 389 struct ifinfomsg ifm;
257422f7
LJ
390 /* attribute has to be NLMSG aligned */
391 struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO)));
bd886ebb 392 __u32 ext_filter_mask;
d17b136f
PS
393 } req = {
394 .nlh.nlmsg_len = sizeof(req),
31ae2912 395 .nlh.nlmsg_type = RTM_GETLINK,
d17b136f
PS
396 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
397 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
398 .ifm.ifi_family = family,
399 .ext_req.rta_type = IFLA_EXT_MASK,
400 .ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
401 .ext_filter_mask = filt_mask,
402 };
bd886ebb 403
2c500a4d 404 return send(rth->fd, &req, sizeof(req), 0);
aba5acdf
SH
405}
406
31ae2912 407int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
b0a4ce62
DA
408 req_filter_fn_t filter_fn)
409{
410 struct {
411 struct nlmsghdr nlh;
412 struct ifinfomsg ifm;
413 char buf[1024];
d17b136f
PS
414 } req = {
415 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
31ae2912 416 .nlh.nlmsg_type = RTM_GETLINK,
d17b136f
PS
417 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
418 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
419 .ifm.ifi_family = family,
420 };
b0a4ce62
DA
421 int err;
422
423 if (!filter_fn)
424 return -EINVAL;
425
b0a4ce62
DA
426 err = filter_fn(&req.nlh, sizeof(req));
427 if (err)
428 return err;
429
1b109a30 430 return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
b0a4ce62
DA
431}
432
56eeeda9 433int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam, __u32 filt_mask)
7abf5de6
NA
434{
435 struct {
436 struct nlmsghdr nlh;
437 struct if_stats_msg ifsm;
438 } req;
439
440 memset(&req, 0, sizeof(req));
441 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg));
56eeeda9 442 req.nlh.nlmsg_type = RTM_GETSTATS;
7abf5de6
NA
443 req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
444 req.nlh.nlmsg_pid = 0;
445 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
446 req.ifsm.family = fam;
447 req.ifsm.filter_mask = filt_mask;
448
2c500a4d 449 return send(rth->fd, &req, sizeof(req), 0);
7abf5de6
NA
450}
451
6cf8398f 452int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
aba5acdf 453{
f31a37f7
SH
454 return send(rth->fd, buf, len, 0);
455}
456
6cf8398f 457int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
f31a37f7 458{
54bb35c6
SH
459 struct nlmsghdr *h;
460 int status;
461 char resp[1024];
aba5acdf 462
f31a37f7 463 status = send(rth->fd, buf, len, 0);
54bb35c6
SH
464 if (status < 0)
465 return status;
466
2d8240f8
SH
467 /* Check for immediate errors */
468 status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
54bb35c6
SH
469 if (status < 0) {
470 if (errno == EAGAIN)
471 return 0;
472 return -1;
473 }
474
475 for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
476 h = NLMSG_NEXT(h, status)) {
477 if (h->nlmsg_type == NLMSG_ERROR) {
2c500a4d
SH
478 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
479
54bb35c6
SH
480 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
481 fprintf(stderr, "ERROR truncated\n");
e9e9365b 482 else
54bb35c6 483 errno = -err->error;
24f38182 484 return -1;
54bb35c6 485 }
54bb35c6
SH
486 }
487
488 return 0;
aba5acdf
SH
489}
490
491int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
492{
d17b136f
PS
493 struct nlmsghdr nlh = {
494 .nlmsg_len = NLMSG_LENGTH(len),
495 .nlmsg_type = type,
496 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
497 .nlmsg_seq = rth->dump = ++rth->seq,
498 };
6cf8398f 499 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
8ed63ab1
SH
500 struct iovec iov[2] = {
501 { .iov_base = &nlh, .iov_len = sizeof(nlh) },
502 { .iov_base = req, .iov_len = len }
503 };
aba5acdf 504 struct msghdr msg = {
8ed63ab1 505 .msg_name = &nladdr,
d17b136f 506 .msg_namelen = sizeof(nladdr),
8ed63ab1
SH
507 .msg_iov = iov,
508 .msg_iovlen = 2,
aba5acdf
SH
509 };
510
aba5acdf
SH
511 return sendmsg(rth->fd, &msg, 0);
512}
513
0d238ca2
DA
514int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
515{
516 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
517 struct iovec iov = {
2c500a4d 518 .iov_base = n,
0d238ca2
DA
519 .iov_len = n->nlmsg_len
520 };
521 struct msghdr msg = {
522 .msg_name = &nladdr,
523 .msg_namelen = sizeof(nladdr),
524 .msg_iov = &iov,
525 .msg_iovlen = 1,
526 };
527
528 n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
529 n->nlmsg_pid = 0;
530 n->nlmsg_seq = rth->dump = ++rth->seq;
531
532 return sendmsg(rth->fd, &msg, 0);
533}
534
0efa6257 535static int rtnl_dump_done(struct nlmsghdr *h)
892a25e2
SH
536{
537 int len = *(int *)NLMSG_DATA(h);
538
05a14fc1
DA
539 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
540 fprintf(stderr, "DONE truncated\n");
541 return -1;
542 }
892a25e2 543
05a14fc1 544 if (len < 0) {
2750252d
DA
545 /* check for any messages returned from kernel */
546 if (nl_dump_ext_ack_done(h, len))
547 return len;
548
05a14fc1
DA
549 errno = -len;
550 switch (errno) {
551 case ENOENT:
552 case EOPNOTSUPP:
553 return -1;
554 case EMSGSIZE:
555 fprintf(stderr,
556 "Error: Buffer too small for object.\n");
557 break;
558 default:
892a25e2 559 perror("RTNETLINK answers");
892a25e2 560 }
05a14fc1 561 return len;
892a25e2 562 }
05a14fc1 563
844c37b4
DA
564 /* check for any messages returned from kernel */
565 nl_dump_ext_ack(h, NULL);
566
892a25e2
SH
567 return 0;
568}
569
570static void rtnl_dump_error(const struct rtnl_handle *rth,
571 struct nlmsghdr *h)
572{
573
574 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
575 fprintf(stderr, "ERROR truncated\n");
576 } else {
577 const struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
578
579 errno = -err->error;
580 if (rth->proto == NETLINK_SOCK_DIAG &&
581 (errno == ENOENT ||
582 errno == EOPNOTSUPP))
583 return;
584
3ad6d176
DA
585 if (!(rth->flags & RTNL_HANDLE_F_SUPPRESS_NLERR))
586 perror("RTNETLINK answers");
892a25e2
SH
587 }
588}
589
2d34851c
HL
590static int __rtnl_recvmsg(int fd, struct msghdr *msg, int flags)
591{
592 int len;
593
594 do {
595 len = recvmsg(fd, msg, flags);
596 } while (len < 0 && (errno == EINTR || errno == EAGAIN));
597
598 if (len < 0) {
599 fprintf(stderr, "netlink receive error %s (%d)\n",
600 strerror(errno), errno);
601 return -errno;
602 }
603
604 if (len == 0) {
605 fprintf(stderr, "EOF on netlink\n");
606 return -ENODATA;
607 }
608
609 return len;
610}
611
612static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
613{
614 struct iovec *iov = msg->msg_iov;
615 char *buf;
616 int len;
617
618 iov->iov_base = NULL;
619 iov->iov_len = 0;
620
621 len = __rtnl_recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC);
622 if (len < 0)
623 return len;
624
625 buf = malloc(len);
626 if (!buf) {
627 fprintf(stderr, "malloc error: not enough buffer\n");
628 return -ENOMEM;
629 }
630
631 iov->iov_base = buf;
632 iov->iov_len = len;
633
634 len = __rtnl_recvmsg(fd, msg, 0);
635 if (len < 0) {
636 free(buf);
637 return len;
638 }
639
640 if (answer)
641 *answer = buf;
642 else
643 free(buf);
644
645 return len;
646}
647
1d2fac41
SH
648static int rtnl_dump_filter_l(struct rtnl_handle *rth,
649 const struct rtnl_dump_filter_arg *arg)
aba5acdf 650{
aba5acdf 651 struct sockaddr_nl nladdr;
8ed63ab1
SH
652 struct iovec iov;
653 struct msghdr msg = {
654 .msg_name = &nladdr,
655 .msg_namelen = sizeof(nladdr),
656 .msg_iov = &iov,
657 .msg_iovlen = 1,
658 };
2d34851c 659 char *buf;
16f02e14 660 int dump_intr = 0;
aba5acdf
SH
661
662 while (1) {
663 int status;
b49240ec 664 const struct rtnl_dump_filter_arg *a;
3bc1c4f2
BG
665 int found_done = 0;
666 int msglen = 0;
aba5acdf 667
2d34851c
HL
668 status = rtnl_recvmsg(rth->fd, &msg, &buf);
669 if (status < 0)
670 return status;
aba5acdf 671
486ccd99
VK
672 if (rth->dump_fp)
673 fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp);
674
b49240ec 675 for (a = arg; a->filter; a++) {
2c500a4d
SH
676 struct nlmsghdr *h = (struct nlmsghdr *)buf;
677
3bc1c4f2 678 msglen = status;
b49240ec 679
3bc1c4f2 680 while (NLMSG_OK(h, msglen)) {
486ccd99 681 int err = 0;
b49240ec 682
8e72880f
PS
683 h->nlmsg_flags &= ~a->nc_flags;
684
b49240ec
SH
685 if (nladdr.nl_pid != 0 ||
686 h->nlmsg_pid != rth->local.nl_pid ||
cd70f3f5 687 h->nlmsg_seq != rth->dump)
b49240ec 688 goto skip_it;
aba5acdf 689
16f02e14
ND
690 if (h->nlmsg_flags & NLM_F_DUMP_INTR)
691 dump_intr = 1;
692
3bc1c4f2 693 if (h->nlmsg_type == NLMSG_DONE) {
0efa6257 694 err = rtnl_dump_done(h);
2d34851c
HL
695 if (err < 0) {
696 free(buf);
892a25e2 697 return -1;
2d34851c 698 }
892a25e2 699
3bc1c4f2
BG
700 found_done = 1;
701 break; /* process next filter */
702 }
892a25e2 703
b49240ec 704 if (h->nlmsg_type == NLMSG_ERROR) {
892a25e2 705 rtnl_dump_error(rth, h);
2d34851c 706 free(buf);
b49240ec 707 return -1;
aba5acdf 708 }
486ccd99
VK
709
710 if (!rth->dump_fp) {
cd554f2c 711 err = a->filter(h, a->arg1);
2d34851c
HL
712 if (err < 0) {
713 free(buf);
486ccd99 714 return err;
2d34851c 715 }
486ccd99 716 }
aba5acdf
SH
717
718skip_it:
3bc1c4f2 719 h = NLMSG_NEXT(h, msglen);
b49240ec 720 }
3bc1c4f2 721 }
2d34851c 722 free(buf);
3bc1c4f2 723
16f02e14
ND
724 if (found_done) {
725 if (dump_intr)
726 fprintf(stderr,
727 "Dump was interrupted and may be inconsistent.\n");
3bc1c4f2 728 return 0;
16f02e14 729 }
3bc1c4f2 730
aba5acdf
SH
731 if (msg.msg_flags & MSG_TRUNC) {
732 fprintf(stderr, "Message truncated\n");
733 continue;
734 }
3bc1c4f2
BG
735 if (msglen) {
736 fprintf(stderr, "!!!Remnant of size %d\n", msglen);
aba5acdf
SH
737 exit(1);
738 }
739 }
740}
741
8e72880f 742int rtnl_dump_filter_nc(struct rtnl_handle *rth,
b49240ec 743 rtnl_filter_t filter,
8e72880f 744 void *arg1, __u16 nc_flags)
b49240ec
SH
745{
746 const struct rtnl_dump_filter_arg a[2] = {
8e72880f
PS
747 { .filter = filter, .arg1 = arg1, .nc_flags = nc_flags, },
748 { .filter = NULL, .arg1 = NULL, .nc_flags = 0, },
b49240ec
SH
749 };
750
751 return rtnl_dump_filter_l(rth, a);
752}
753
b6432e68
SH
754static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
755 nl_ext_ack_fn_t errfn)
756{
844c37b4 757 if (nl_dump_ext_ack(h, errfn))
b6432e68
SH
758 return;
759
760 fprintf(stderr, "RTNETLINK answers: %s\n",
761 strerror(-err->error));
762}
763
72a2ff39
CM
764
765static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iov,
766 size_t iovlen, struct nlmsghdr **answer,
767 bool show_rtnl_err, nl_ext_ack_fn_t errfn)
aba5acdf 768{
d17b136f 769 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
72a2ff39 770 struct iovec riov;
aba5acdf 771 struct msghdr msg = {
8ed63ab1
SH
772 .msg_name = &nladdr,
773 .msg_namelen = sizeof(nladdr),
72a2ff39
CM
774 .msg_iov = iov,
775 .msg_iovlen = iovlen,
aba5acdf 776 };
72a2ff39
CM
777 unsigned int seq = 0;
778 struct nlmsghdr *h;
779 int i, status;
2d34851c 780 char *buf;
aba5acdf 781
72a2ff39
CM
782 for (i = 0; i < iovlen; i++) {
783 h = iov[i].iov_base;
784 h->nlmsg_seq = seq = ++rtnl->seq;
785 if (answer == NULL)
786 h->nlmsg_flags |= NLM_F_ACK;
787 }
aba5acdf
SH
788
789 status = sendmsg(rtnl->fd, &msg, 0);
aba5acdf
SH
790 if (status < 0) {
791 perror("Cannot talk to rtnetlink");
792 return -1;
793 }
794
72a2ff39
CM
795 /* change msg to use the response iov */
796 msg.msg_iov = &riov;
797 msg.msg_iovlen = 1;
798 i = 0;
aba5acdf 799 while (1) {
0951cbcd 800next:
2d34851c 801 status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
72a2ff39 802 ++i;
2d34851c
HL
803
804 if (status < 0)
805 return status;
aba5acdf 806
aba5acdf 807 if (msg.msg_namelen != sizeof(nladdr)) {
2c500a4d
SH
808 fprintf(stderr,
809 "sender address length == %d\n",
810 msg.msg_namelen);
aba5acdf
SH
811 exit(1);
812 }
2c500a4d 813 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
aba5acdf
SH
814 int len = h->nlmsg_len;
815 int l = len - sizeof(*h);
816
2c500a4d 817 if (l < 0 || len > status) {
aba5acdf
SH
818 if (msg.msg_flags & MSG_TRUNC) {
819 fprintf(stderr, "Truncated message\n");
2d34851c 820 free(buf);
aba5acdf
SH
821 return -1;
822 }
2c500a4d
SH
823 fprintf(stderr,
824 "!!!malformed message: len=%d\n",
825 len);
aba5acdf
SH
826 exit(1);
827 }
828
c079e121 829 if (nladdr.nl_pid != 0 ||
10f57ef1 830 h->nlmsg_pid != rtnl->local.nl_pid ||
72a2ff39 831 h->nlmsg_seq > seq || h->nlmsg_seq < seq - iovlen) {
4cca16f2
SH
832 /* Don't forget to skip that message. */
833 status -= NLMSG_ALIGN(len);
2c500a4d 834 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
aba5acdf
SH
835 continue;
836 }
837
838 if (h->nlmsg_type == NLMSG_ERROR) {
2c500a4d 839 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
8c50b728 840 int error = err->error;
2c500a4d 841
aba5acdf
SH
842 if (l < sizeof(struct nlmsgerr)) {
843 fprintf(stderr, "ERROR truncated\n");
c60389e4
SH
844 free(buf);
845 return -1;
846 }
847
bfb3bf18 848 if (!error) {
844c37b4
DA
849 /* check messages from kernel */
850 nl_dump_ext_ack(h, errfn);
bfb3bf18
SH
851 } else {
852 errno = -error;
844c37b4 853
b45e3000
SH
854 if (rtnl->proto != NETLINK_SOCK_DIAG &&
855 show_rtnl_err)
856 rtnl_talk_error(h, err, errfn);
857 }
b6432e68 858
c60389e4
SH
859 if (answer)
860 *answer = (struct nlmsghdr *)buf;
861 else
862 free(buf);
b45e3000 863
0951cbcd
PM
864 if (i < iovlen)
865 goto next;
8c50b728 866 return error ? -i : 0;
aba5acdf 867 }
c079e121 868
aba5acdf 869 if (answer) {
86bf43c7 870 *answer = (struct nlmsghdr *)buf;
aba5acdf
SH
871 return 0;
872 }
873
874 fprintf(stderr, "Unexpected reply!!!\n");
875
876 status -= NLMSG_ALIGN(len);
2c500a4d 877 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
aba5acdf 878 }
2d34851c 879 free(buf);
c079e121 880
aba5acdf
SH
881 if (msg.msg_flags & MSG_TRUNC) {
882 fprintf(stderr, "Message truncated\n");
883 continue;
884 }
c079e121 885
aba5acdf
SH
886 if (status) {
887 fprintf(stderr, "!!!Remnant of size %d\n", status);
888 exit(1);
889 }
890 }
891}
892
72a2ff39
CM
893static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
894 struct nlmsghdr **answer,
895 bool show_rtnl_err, nl_ext_ack_fn_t errfn)
896{
897 struct iovec iov = {
898 .iov_base = n,
899 .iov_len = n->nlmsg_len
900 };
901
902 return __rtnl_talk_iov(rtnl, &iov, 1, answer, show_rtnl_err, errfn);
903}
904
463d9efa 905int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
86bf43c7 906 struct nlmsghdr **answer)
463d9efa 907{
86bf43c7 908 return __rtnl_talk(rtnl, n, answer, true, NULL);
b6432e68
SH
909}
910
72a2ff39
CM
911int rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iovec, size_t iovlen,
912 struct nlmsghdr **answer)
913{
914 return __rtnl_talk_iov(rtnl, iovec, iovlen, answer, true, NULL);
915}
916
463d9efa 917int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle *rtnl, struct nlmsghdr *n,
86bf43c7 918 struct nlmsghdr **answer)
463d9efa 919{
86bf43c7 920 return __rtnl_talk(rtnl, n, answer, false, NULL);
463d9efa
DA
921}
922
449b824a
ND
923int rtnl_listen_all_nsid(struct rtnl_handle *rth)
924{
925 unsigned int on = 1;
926
927 if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
928 sizeof(on)) < 0) {
929 perror("NETLINK_LISTEN_ALL_NSID");
930 return -1;
931 }
932 rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
933 return 0;
934}
935
8ed63ab1 936int rtnl_listen(struct rtnl_handle *rtnl,
0628cddd 937 rtnl_listen_filter_t handler,
6dc9f016 938 void *jarg)
aba5acdf
SH
939{
940 int status;
941 struct nlmsghdr *h;
d17b136f 942 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
aba5acdf 943 struct iovec iov;
aba5acdf 944 struct msghdr msg = {
8ed63ab1
SH
945 .msg_name = &nladdr,
946 .msg_namelen = sizeof(nladdr),
947 .msg_iov = &iov,
948 .msg_iovlen = 1,
aba5acdf 949 };
e557212e 950 char buf[16384];
449b824a
ND
951 char cmsgbuf[BUFSIZ];
952
953 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
954 msg.msg_control = &cmsgbuf;
955 msg.msg_controllen = sizeof(cmsgbuf);
956 }
aba5acdf 957
aba5acdf 958 iov.iov_base = buf;
aba5acdf 959 while (1) {
449b824a
ND
960 struct rtnl_ctrl_data ctrl;
961 struct cmsghdr *cmsg;
962
aba5acdf
SH
963 iov.iov_len = sizeof(buf);
964 status = recvmsg(rtnl->fd, &msg, 0);
965
966 if (status < 0) {
aa8032e6 967 if (errno == EINTR || errno == EAGAIN)
aba5acdf 968 continue;
aa8032e6
SH
969 fprintf(stderr, "netlink receive error %s (%d)\n",
970 strerror(errno), errno);
7f03191f
PM
971 if (errno == ENOBUFS)
972 continue;
aa8032e6 973 return -1;
aba5acdf
SH
974 }
975 if (status == 0) {
976 fprintf(stderr, "EOF on netlink\n");
977 return -1;
978 }
979 if (msg.msg_namelen != sizeof(nladdr)) {
2c500a4d
SH
980 fprintf(stderr,
981 "Sender address length == %d\n",
982 msg.msg_namelen);
aba5acdf
SH
983 exit(1);
984 }
449b824a
ND
985
986 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
987 memset(&ctrl, 0, sizeof(ctrl));
988 ctrl.nsid = -1;
989 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
990 cmsg = CMSG_NXTHDR(&msg, cmsg))
991 if (cmsg->cmsg_level == SOL_NETLINK &&
992 cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
993 cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
994 int *data = (int *)CMSG_DATA(cmsg);
995
996 ctrl.nsid = *data;
997 }
998 }
999
2c500a4d 1000 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
aba5acdf
SH
1001 int err;
1002 int len = h->nlmsg_len;
1003 int l = len - sizeof(*h);
1004
2c500a4d 1005 if (l < 0 || len > status) {
aba5acdf
SH
1006 if (msg.msg_flags & MSG_TRUNC) {
1007 fprintf(stderr, "Truncated message\n");
1008 return -1;
1009 }
2c500a4d
SH
1010 fprintf(stderr,
1011 "!!!malformed message: len=%d\n",
1012 len);
aba5acdf
SH
1013 exit(1);
1014 }
1015
cd554f2c 1016 err = handler(&ctrl, h, jarg);
aba5acdf
SH
1017 if (err < 0)
1018 return err;
1019
1020 status -= NLMSG_ALIGN(len);
2c500a4d 1021 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
aba5acdf
SH
1022 }
1023 if (msg.msg_flags & MSG_TRUNC) {
1024 fprintf(stderr, "Message truncated\n");
1025 continue;
1026 }
1027 if (status) {
1028 fprintf(stderr, "!!!Remnant of size %d\n", status);
1029 exit(1);
1030 }
1031 }
1032}
1033
0628cddd 1034int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
6dc9f016 1035 void *jarg)
aba5acdf
SH
1036{
1037 int status;
2c500a4d
SH
1038 char buf[16384];
1039 struct nlmsghdr *h = (struct nlmsghdr *)buf;
aba5acdf 1040
aba5acdf 1041 while (1) {
2dd9f8e0 1042 int err, len;
aba5acdf
SH
1043 int l;
1044
1045 status = fread(&buf, 1, sizeof(*h), rtnl);
1046
1047 if (status < 0) {
1048 if (errno == EINTR)
1049 continue;
1050 perror("rtnl_from_file: fread");
1051 return -1;
1052 }
1053 if (status == 0)
1054 return 0;
1055
1056 len = h->nlmsg_len;
aba5acdf
SH
1057 l = len - sizeof(*h);
1058
2c500a4d 1059 if (l < 0 || len > sizeof(buf)) {
aba5acdf
SH
1060 fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
1061 len, ftell(rtnl));
1062 return -1;
1063 }
1064
1065 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
1066
1067 if (status < 0) {
1068 perror("rtnl_from_file: fread");
1069 return -1;
1070 }
1071 if (status < l) {
1072 fprintf(stderr, "rtnl-from_file: truncated message\n");
1073 return -1;
1074 }
1075
cd554f2c 1076 err = handler(NULL, h, jarg);
aba5acdf
SH
1077 if (err < 0)
1078 return err;
1079 }
1080}
1081
2aa3dd29
SH
1082int addattr(struct nlmsghdr *n, int maxlen, int type)
1083{
1084 return addattr_l(n, maxlen, type, NULL, 0);
1085}
1086
1087int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
1088{
1089 return addattr_l(n, maxlen, type, &data, sizeof(__u8));
1090}
1091
1092int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
1093{
1094 return addattr_l(n, maxlen, type, &data, sizeof(__u16));
1095}
1096
aba5acdf
SH
1097int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
1098{
2aa3dd29
SH
1099 return addattr_l(n, maxlen, type, &data, sizeof(__u32));
1100}
1101
1102int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
1103{
1104 return addattr_l(n, maxlen, type, &data, sizeof(__u64));
1105}
1106
1107int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
1108{
1109 return addattr_l(n, maxlen, type, str, strlen(str)+1);
aba5acdf
SH
1110}
1111
8ed63ab1 1112int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
6dc9f016 1113 int alen)
aba5acdf
SH
1114{
1115 int len = RTA_LENGTH(alen);
1116 struct rtattr *rta;
1117
3dabdbb3 1118 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
2c500a4d
SH
1119 fprintf(stderr,
1120 "addattr_l ERROR: message exceeded bound of %d\n",
1121 maxlen);
aba5acdf 1122 return -1;
007d3a3e 1123 }
07f94362 1124 rta = NLMSG_TAIL(n);
aba5acdf
SH
1125 rta->rta_type = type;
1126 rta->rta_len = len;
893deac4
PS
1127 if (alen)
1128 memcpy(RTA_DATA(rta), data, alen);
3dabdbb3 1129 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
aba5acdf
SH
1130 return 0;
1131}
1132
07f94362 1133int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
1134{
1135 if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
2c500a4d
SH
1136 fprintf(stderr,
1137 "addraw_l ERROR: message exceeded bound of %d\n",
1138 maxlen);
07f94362 1139 return -1;
1140 }
1141
1142 memcpy(NLMSG_TAIL(n), data, len);
1143 memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
1144 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
1145 return 0;
1146}
1147
2f90c9c0
PM
1148struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
1149{
1150 struct rtattr *nest = NLMSG_TAIL(n);
1151
1152 addattr_l(n, maxlen, type, NULL, 0);
1153 return nest;
1154}
1155
1156int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
1157{
1158 nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
1159 return n->nlmsg_len;
1160}
1161
1162struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
1163 const void *data, int len)
1164{
1165 struct rtattr *start = NLMSG_TAIL(n);
1166
1167 addattr_l(n, maxlen, type, data, len);
1168 addattr_nest(n, maxlen, type);
1169 return start;
1170}
1171
1172int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
1173{
1174 struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
1175
1176 start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
1177 addattr_nest_end(n, nest);
1178 return n->nlmsg_len;
1179}
1180
aba5acdf
SH
1181int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
1182{
1183 int len = RTA_LENGTH(4);
1184 struct rtattr *subrta;
1185
007d3a3e 1186 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
2c500a4d
SH
1187 fprintf(stderr,
1188 "rta_addattr32: Error! max allowed bound %d exceeded\n",
1189 maxlen);
aba5acdf 1190 return -1;
007d3a3e 1191 }
2c500a4d 1192 subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
aba5acdf
SH
1193 subrta->rta_type = type;
1194 subrta->rta_len = len;
1195 memcpy(RTA_DATA(subrta), &data, 4);
1196 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
1197 return 0;
1198}
1199
8ed63ab1 1200int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
6dc9f016 1201 const void *data, int alen)
aba5acdf
SH
1202{
1203 struct rtattr *subrta;
1204 int len = RTA_LENGTH(alen);
1205
3dabdbb3 1206 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
2c500a4d
SH
1207 fprintf(stderr,
1208 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
1209 maxlen);
aba5acdf 1210 return -1;
007d3a3e 1211 }
2c500a4d 1212 subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
aba5acdf
SH
1213 subrta->rta_type = type;
1214 subrta->rta_len = len;
893deac4
PS
1215 if (alen)
1216 memcpy(RTA_DATA(subrta), data, alen);
3dabdbb3 1217 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
aba5acdf
SH
1218 return 0;
1219}
1220
303cc9cb
RP
1221int rta_addattr8(struct rtattr *rta, int maxlen, int type, __u8 data)
1222{
1223 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u8));
1224}
1225
1226int rta_addattr16(struct rtattr *rta, int maxlen, int type, __u16 data)
1227{
1228 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u16));
1229}
1230
1231int rta_addattr64(struct rtattr *rta, int maxlen, int type, __u64 data)
1232{
1233 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u64));
1234}
1235
1236struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type)
1237{
1238 struct rtattr *nest = RTA_TAIL(rta);
1239
1240 rta_addattr_l(rta, maxlen, type, NULL, 0);
1241
1242 return nest;
1243}
1244
1245int rta_nest_end(struct rtattr *rta, struct rtattr *nest)
1246{
1247 nest->rta_len = (void *)RTA_TAIL(rta) - (void *)nest;
1248
1249 return rta->rta_len;
1250}
1251
aba5acdf
SH
1252int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
1253{
b1b7ce0f
VY
1254 return parse_rtattr_flags(tb, max, rta, len, 0);
1255}
1256
1257int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
1258 int len, unsigned short flags)
1259{
1260 unsigned short type;
1261
175e2440 1262 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
aba5acdf 1263 while (RTA_OK(rta, len)) {
b1b7ce0f
VY
1264 type = rta->rta_type & ~flags;
1265 if ((type <= max) && (!tb[type]))
1266 tb[type] = rta;
2c500a4d 1267 rta = RTA_NEXT(rta, len);
aba5acdf
SH
1268 }
1269 if (len)
2c500a4d
SH
1270 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
1271 len, rta->rta_len);
aba5acdf
SH
1272 return 0;
1273}
c7699875 1274
decbb437
JP
1275struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
1276{
1277 while (RTA_OK(rta, len)) {
1278 if (rta->rta_type == type)
1279 return rta;
1280 rta = RTA_NEXT(rta, len);
1281 }
2c500a4d 1282
decbb437 1283 if (len)
2c500a4d
SH
1284 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
1285 len, rta->rta_len);
decbb437
JP
1286 return NULL;
1287}
1288
2c500a4d
SH
1289int __parse_rtattr_nested_compat(struct rtattr *tb[], int max,
1290 struct rtattr *rta,
1291 int len)
2f90c9c0
PM
1292{
1293 if (RTA_PAYLOAD(rta) < len)
1294 return -1;
1295 if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
1296 rta = RTA_DATA(rta) + RTA_ALIGN(len);
1297 return parse_rtattr_nested(tb, max, rta);
1298 }
037c635e 1299 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
2f90c9c0
PM
1300 return 0;
1301}