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