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