1
2
3
4
5
6
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <stdbool.h>
11#include <unistd.h>
12#include <fcntl.h>
13#include <net/if_arp.h>
14#include <sys/socket.h>
15#include <netinet/in.h>
16#include <string.h>
17#include <errno.h>
18#include <time.h>
19#include <sys/uio.h>
20#include <linux/fib_rules.h>
21#include <linux/if_addrlabel.h>
22#include <linux/if_bridge.h>
23#include <linux/nexthop.h>
24
25#include "libnetlink.h"
26#include "utils.h"
27
28#ifndef __aligned
29#define __aligned(x) __attribute__((aligned(x)))
30#endif
31
32#ifndef SOL_NETLINK
33#define SOL_NETLINK 270
34#endif
35
36#ifndef MIN
37#define MIN(a, b) ((a) < (b) ? (a) : (b))
38#endif
39
40int rcvbuf = 1024 * 1024;
41
42#ifdef HAVE_LIBMNL
43#include <libmnl/libmnl.h>
44
45static const enum mnl_attr_data_type extack_policy[NLMSGERR_ATTR_MAX + 1] = {
46 [NLMSGERR_ATTR_MSG] = MNL_TYPE_NUL_STRING,
47 [NLMSGERR_ATTR_OFFS] = MNL_TYPE_U32,
48};
49
50static int err_attr_cb(const struct nlattr *attr, void *data)
51{
52 const struct nlattr **tb = data;
53 uint16_t type;
54
55 if (mnl_attr_type_valid(attr, NLMSGERR_ATTR_MAX) < 0) {
56 fprintf(stderr, "Invalid extack attribute\n");
57 return MNL_CB_ERROR;
58 }
59
60 type = mnl_attr_get_type(attr);
61 if (mnl_attr_validate(attr, extack_policy[type]) < 0) {
62 fprintf(stderr, "extack attribute %d failed validation\n",
63 type);
64 return MNL_CB_ERROR;
65 }
66
67 tb[type] = attr;
68 return MNL_CB_OK;
69}
70
71static void print_ext_ack_msg(bool is_err, const char *msg)
72{
73 fprintf(stderr, "%s: %s", is_err ? "Error" : "Warning", msg);
74 if (msg[strlen(msg) - 1] != '.')
75 fprintf(stderr, ".");
76 fprintf(stderr, "\n");
77}
78
79
80int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
81{
82 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
83 const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
84 const struct nlmsghdr *err_nlh = NULL;
85 unsigned int hlen = sizeof(*err);
86 const char *msg = NULL;
87 uint32_t off = 0;
88
89
90 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
91 return 0;
92
93
94 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
95 hlen += mnl_nlmsg_get_payload_len(&err->msg);
96
97 if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
98 return 0;
99
100 if (tb[NLMSGERR_ATTR_MSG])
101 msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
102
103 if (tb[NLMSGERR_ATTR_OFFS]) {
104 off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
105
106 if (off > nlh->nlmsg_len) {
107 fprintf(stderr,
108 "Invalid offset for NLMSGERR_ATTR_OFFS\n");
109 off = 0;
110 } else if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
111 err_nlh = &err->msg;
112 }
113
114 if (tb[NLMSGERR_ATTR_MISS_TYPE])
115 fprintf(stderr, "Missing required attribute type %u\n",
116 mnl_attr_get_u32(tb[NLMSGERR_ATTR_MISS_TYPE]));
117
118 if (errfn)
119 return errfn(msg, off, err_nlh);
120
121 if (msg && *msg != '\0') {
122 bool is_err = !!err->error;
123
124 print_ext_ack_msg(is_err, msg);
125 return is_err ? 1 : 0;
126 }
127
128 return 0;
129}
130
131int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, unsigned int offset, int error)
132{
133 struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
134 const char *msg = NULL;
135
136 if (mnl_attr_parse(nlh, offset, err_attr_cb, tb) != MNL_CB_OK)
137 return 0;
138
139 if (tb[NLMSGERR_ATTR_MSG])
140 msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]);
141
142 if (msg && *msg != '\0') {
143 bool is_err = !!error;
144
145 print_ext_ack_msg(is_err, msg);
146 return is_err ? 1 : 0;
147 }
148
149 return 0;
150}
151#else
152#warning "libmnl required for error support"
153
154
155int nl_dump_ext_ack(const struct nlmsghdr *nlh, nl_ext_ack_fn_t errfn)
156{
157 return 0;
158}
159
160int nl_dump_ext_ack_done(const struct nlmsghdr *nlh, unsigned int offset, int error)
161{
162 return 0;
163}
164#endif
165
166
167void rtnl_set_strict_dump(struct rtnl_handle *rth)
168{
169 int one = 1;
170
171 if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_GET_STRICT_CHK,
172 &one, sizeof(one)) < 0)
173 return;
174
175 rth->flags |= RTNL_HANDLE_F_STRICT_CHK;
176}
177
178int rtnl_add_nl_group(struct rtnl_handle *rth, unsigned int group)
179{
180 return setsockopt(rth->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
181 &group, sizeof(group));
182}
183
184void rtnl_close(struct rtnl_handle *rth)
185{
186 if (rth->fd >= 0) {
187 close(rth->fd);
188 rth->fd = -1;
189 }
190}
191
192int rtnl_open_byproto(struct rtnl_handle *rth, unsigned int subscriptions,
193 int protocol)
194{
195 socklen_t addr_len;
196 int sndbuf = 32768;
197 int one = 1;
198
199 memset(rth, 0, sizeof(*rth));
200
201 rth->proto = protocol;
202 rth->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
203 if (rth->fd < 0) {
204 perror("Cannot open netlink socket");
205 return -1;
206 }
207
208 if (setsockopt(rth->fd, SOL_SOCKET, SO_SNDBUF,
209 &sndbuf, sizeof(sndbuf)) < 0) {
210 perror("SO_SNDBUF");
211 goto err;
212 }
213
214 if (setsockopt(rth->fd, SOL_SOCKET, SO_RCVBUF,
215 &rcvbuf, sizeof(rcvbuf)) < 0) {
216 perror("SO_RCVBUF");
217 goto err;
218 }
219
220
221 setsockopt(rth->fd, SOL_NETLINK, NETLINK_EXT_ACK,
222 &one, sizeof(one));
223
224 memset(&rth->local, 0, sizeof(rth->local));
225 rth->local.nl_family = AF_NETLINK;
226 rth->local.nl_groups = subscriptions;
227
228 if (bind(rth->fd, (struct sockaddr *)&rth->local,
229 sizeof(rth->local)) < 0) {
230 perror("Cannot bind netlink socket");
231 goto err;
232 }
233 addr_len = sizeof(rth->local);
234 if (getsockname(rth->fd, (struct sockaddr *)&rth->local,
235 &addr_len) < 0) {
236 perror("Cannot getsockname");
237 goto err;
238 }
239 if (addr_len != sizeof(rth->local)) {
240 fprintf(stderr, "Wrong address length %d\n", addr_len);
241 goto err;
242 }
243 if (rth->local.nl_family != AF_NETLINK) {
244 fprintf(stderr, "Wrong address family %d\n",
245 rth->local.nl_family);
246 goto err;
247 }
248 rth->seq = time(NULL);
249 return 0;
250err:
251 rtnl_close(rth);
252 return -1;
253}
254
255int rtnl_open(struct rtnl_handle *rth, unsigned int subscriptions)
256{
257 return rtnl_open_byproto(rth, subscriptions, NETLINK_ROUTE);
258}
259
260int rtnl_nexthopdump_req(struct rtnl_handle *rth, int family,
261 req_filter_fn_t filter_fn)
262{
263 struct {
264 struct nlmsghdr nlh;
265 struct nhmsg nhm;
266 char buf[128];
267 } req = {
268 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
269 .nlh.nlmsg_type = RTM_GETNEXTHOP,
270 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
271 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
272 .nhm.nh_family = family,
273 };
274
275 if (filter_fn) {
276 int err;
277
278 err = filter_fn(&req.nlh, sizeof(req));
279 if (err)
280 return err;
281 }
282
283 return send(rth->fd, &req, sizeof(req), 0);
284}
285
286int rtnl_nexthop_bucket_dump_req(struct rtnl_handle *rth, int family,
287 req_filter_fn_t filter_fn)
288{
289 struct {
290 struct nlmsghdr nlh;
291 struct nhmsg nhm;
292 char buf[128];
293 } req = {
294 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)),
295 .nlh.nlmsg_type = RTM_GETNEXTHOPBUCKET,
296 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
297 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
298 .nhm.nh_family = family,
299 };
300
301 if (filter_fn) {
302 int err;
303
304 err = filter_fn(&req.nlh, sizeof(req));
305 if (err)
306 return err;
307 }
308
309 return send(rth->fd, &req, sizeof(req), 0);
310}
311
312int rtnl_addrdump_req(struct rtnl_handle *rth, int family,
313 req_filter_fn_t filter_fn)
314{
315 struct {
316 struct nlmsghdr nlh;
317 struct ifaddrmsg ifm;
318 char buf[128];
319 } req = {
320 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
321 .nlh.nlmsg_type = RTM_GETADDR,
322 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
323 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
324 .ifm.ifa_family = family,
325 };
326
327 if (filter_fn) {
328 int err;
329
330 err = filter_fn(&req.nlh, sizeof(req));
331 if (err)
332 return err;
333 }
334
335 return send(rth->fd, &req, sizeof(req), 0);
336}
337
338int rtnl_addrlbldump_req(struct rtnl_handle *rth, int family)
339{
340 struct {
341 struct nlmsghdr nlh;
342 struct ifaddrlblmsg ifal;
343 } req = {
344 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)),
345 .nlh.nlmsg_type = RTM_GETADDRLABEL,
346 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
347 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
348 .ifal.ifal_family = family,
349 };
350
351 return send(rth->fd, &req, sizeof(req), 0);
352}
353
354int rtnl_routedump_req(struct rtnl_handle *rth, int family,
355 req_filter_fn_t filter_fn)
356{
357 struct {
358 struct nlmsghdr nlh;
359 struct rtmsg rtm;
360 char buf[128];
361 } req = {
362 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
363 .nlh.nlmsg_type = RTM_GETROUTE,
364 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
365 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
366 .rtm.rtm_family = family,
367 };
368
369 if (filter_fn) {
370 int err;
371
372 err = filter_fn(&req.nlh, sizeof(req));
373 if (err)
374 return err;
375 }
376
377 return send(rth->fd, &req, sizeof(req), 0);
378}
379
380int rtnl_ruledump_req(struct rtnl_handle *rth, int family)
381{
382 struct {
383 struct nlmsghdr nlh;
384 struct fib_rule_hdr frh;
385 } req = {
386 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
387 .nlh.nlmsg_type = RTM_GETRULE,
388 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
389 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
390 .frh.family = family
391 };
392
393 return send(rth->fd, &req, sizeof(req), 0);
394}
395
396int rtnl_neighdump_req(struct rtnl_handle *rth, int family,
397 req_filter_fn_t filter_fn)
398{
399 struct {
400 struct nlmsghdr nlh;
401 struct ndmsg ndm;
402 char buf[256];
403 } req = {
404 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
405 .nlh.nlmsg_type = RTM_GETNEIGH,
406 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
407 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
408 .ndm.ndm_family = family,
409 };
410
411 if (filter_fn) {
412 int err;
413
414 err = filter_fn(&req.nlh, sizeof(req));
415 if (err)
416 return err;
417 }
418
419 return send(rth->fd, &req, sizeof(req), 0);
420}
421
422int rtnl_neightbldump_req(struct rtnl_handle *rth, int family)
423{
424 struct {
425 struct nlmsghdr nlh;
426 struct ndtmsg ndtmsg;
427 } req = {
428 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg)),
429 .nlh.nlmsg_type = RTM_GETNEIGHTBL,
430 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
431 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
432 .ndtmsg.ndtm_family = family,
433 };
434
435 return send(rth->fd, &req, sizeof(req), 0);
436}
437
438int rtnl_mdbdump_req(struct rtnl_handle *rth, int family)
439{
440 struct {
441 struct nlmsghdr nlh;
442 struct br_port_msg bpm;
443 } req = {
444 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)),
445 .nlh.nlmsg_type = RTM_GETMDB,
446 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
447 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
448 .bpm.family = family,
449 };
450
451 return send(rth->fd, &req, sizeof(req), 0);
452}
453
454int rtnl_brvlandump_req(struct rtnl_handle *rth, int family, __u32 dump_flags)
455{
456 struct {
457 struct nlmsghdr nlh;
458 struct br_vlan_msg bvm;
459 char buf[256];
460 } req = {
461 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
462 .nlh.nlmsg_type = RTM_GETVLAN,
463 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
464 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
465 .bvm.family = family,
466 };
467
468 addattr32(&req.nlh, sizeof(req), BRIDGE_VLANDB_DUMP_FLAGS, dump_flags);
469
470 return send(rth->fd, &req, sizeof(req), 0);
471}
472
473int rtnl_netconfdump_req(struct rtnl_handle *rth, int family)
474{
475 struct {
476 struct nlmsghdr nlh;
477 struct netconfmsg ncm;
478 char buf[0] __aligned(NLMSG_ALIGNTO);
479 } req = {
480 .nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct netconfmsg))),
481 .nlh.nlmsg_type = RTM_GETNETCONF,
482 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
483 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
484 .ncm.ncm_family = family,
485 };
486
487 return send(rth->fd, &req, sizeof(req), 0);
488}
489
490int rtnl_nsiddump_req_filter_fn(struct rtnl_handle *rth, int family,
491 req_filter_fn_t filter_fn)
492{
493 struct {
494 struct nlmsghdr nlh;
495 struct rtgenmsg rtm;
496 char buf[1024];
497 } req = {
498 .nlh.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
499 .nlh.nlmsg_type = RTM_GETNSID,
500 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
501 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
502 .rtm.rtgen_family = family,
503 };
504 int err;
505
506 if (!filter_fn)
507 return -EINVAL;
508
509 err = filter_fn(&req.nlh, sizeof(req));
510 if (err)
511 return err;
512
513 return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
514}
515
516static int __rtnl_linkdump_req(struct rtnl_handle *rth, int family)
517{
518 struct {
519 struct nlmsghdr nlh;
520 struct ifinfomsg ifm;
521 } req = {
522 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
523 .nlh.nlmsg_type = RTM_GETLINK,
524 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
525 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
526 .ifm.ifi_family = family,
527 };
528
529 return send(rth->fd, &req, sizeof(req), 0);
530}
531
532int rtnl_linkdump_req(struct rtnl_handle *rth, int family)
533{
534 if (family == AF_UNSPEC)
535 return rtnl_linkdump_req_filter(rth, family, RTEXT_FILTER_VF);
536
537 return __rtnl_linkdump_req(rth, family);
538}
539
540int rtnl_linkdump_req_filter(struct rtnl_handle *rth, int family,
541 __u32 filt_mask)
542{
543 if (family == AF_UNSPEC || family == AF_BRIDGE) {
544 struct {
545 struct nlmsghdr nlh;
546 struct ifinfomsg ifm;
547
548 struct rtattr ext_req __aligned(NLMSG_ALIGNTO);
549 __u32 ext_filter_mask;
550 } req = {
551 .nlh.nlmsg_len = sizeof(req),
552 .nlh.nlmsg_type = RTM_GETLINK,
553 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
554 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
555 .ifm.ifi_family = family,
556 .ext_req.rta_type = IFLA_EXT_MASK,
557 .ext_req.rta_len = RTA_LENGTH(sizeof(__u32)),
558 .ext_filter_mask = filt_mask,
559 };
560
561 return send(rth->fd, &req, sizeof(req), 0);
562 }
563
564 return __rtnl_linkdump_req(rth, family);
565}
566
567int rtnl_linkdump_req_filter_fn(struct rtnl_handle *rth, int family,
568 req_filter_fn_t filter_fn)
569{
570 if (family == AF_UNSPEC || family == AF_PACKET) {
571 struct {
572 struct nlmsghdr nlh;
573 struct ifinfomsg ifm;
574 char buf[1024];
575 } req = {
576 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
577 .nlh.nlmsg_type = RTM_GETLINK,
578 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
579 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
580 .ifm.ifi_family = family,
581 };
582 int err;
583
584 if (!filter_fn)
585 return -EINVAL;
586
587 err = filter_fn(&req.nlh, sizeof(req));
588 if (err)
589 return err;
590
591 return send(rth->fd, &req, req.nlh.nlmsg_len, 0);
592 }
593
594 return __rtnl_linkdump_req(rth, family);
595}
596
597int rtnl_fdb_linkdump_req_filter_fn(struct rtnl_handle *rth,
598 req_filter_fn_t filter_fn)
599{
600 struct {
601 struct nlmsghdr nlh;
602 struct ifinfomsg ifm;
603 char buf[128];
604 } req = {
605 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
606 .nlh.nlmsg_type = RTM_GETNEIGH,
607 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
608 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
609 .ifm.ifi_family = PF_BRIDGE,
610 };
611 int err;
612
613 err = filter_fn(&req.nlh, sizeof(req));
614 if (err)
615 return err;
616
617 return send(rth->fd, &req, sizeof(req), 0);
618}
619
620int rtnl_statsdump_req_filter(struct rtnl_handle *rth, int fam,
621 __u32 filt_mask,
622 int (*filter_fn)(struct ipstats_req *req,
623 void *data),
624 void *filter_data)
625{
626 struct ipstats_req req;
627
628 memset(&req, 0, sizeof(req));
629 req.nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct if_stats_msg));
630 req.nlh.nlmsg_type = RTM_GETSTATS;
631 req.nlh.nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
632 req.nlh.nlmsg_pid = 0;
633 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
634 req.ifsm.family = fam;
635 req.ifsm.filter_mask = filt_mask;
636
637 if (filter_fn) {
638 int err;
639
640 err = filter_fn(&req, filter_data);
641 if (err)
642 return err;
643 }
644
645 return send(rth->fd, &req, sizeof(req), 0);
646}
647
648int rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
649{
650 return send(rth->fd, buf, len, 0);
651}
652
653int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
654{
655 struct nlmsghdr *h;
656 int status;
657 char resp[1024];
658
659 status = send(rth->fd, buf, len, 0);
660 if (status < 0)
661 return status;
662
663
664 status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
665 if (status < 0) {
666 if (errno == EAGAIN)
667 return 0;
668 return -1;
669 }
670
671 for (h = (struct nlmsghdr *)resp; NLMSG_OK(h, status);
672 h = NLMSG_NEXT(h, status)) {
673 if (h->nlmsg_type == NLMSG_ERROR) {
674 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
675
676 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
677 fprintf(stderr, "ERROR truncated\n");
678 else
679 errno = -err->error;
680 return -1;
681 }
682 }
683
684 return 0;
685}
686
687int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
688{
689 struct nlmsghdr nlh = {
690 .nlmsg_len = NLMSG_LENGTH(len),
691 .nlmsg_type = type,
692 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
693 .nlmsg_seq = rth->dump = ++rth->seq,
694 };
695 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
696 struct iovec iov[2] = {
697 { .iov_base = &nlh, .iov_len = sizeof(nlh) },
698 { .iov_base = req, .iov_len = len }
699 };
700 struct msghdr msg = {
701 .msg_name = &nladdr,
702 .msg_namelen = sizeof(nladdr),
703 .msg_iov = iov,
704 .msg_iovlen = 2,
705 };
706
707 return sendmsg(rth->fd, &msg, 0);
708}
709
710int rtnl_dump_request_n(struct rtnl_handle *rth, struct nlmsghdr *n)
711{
712 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
713 struct iovec iov = {
714 .iov_base = n,
715 .iov_len = n->nlmsg_len
716 };
717 struct msghdr msg = {
718 .msg_name = &nladdr,
719 .msg_namelen = sizeof(nladdr),
720 .msg_iov = &iov,
721 .msg_iovlen = 1,
722 };
723
724 n->nlmsg_flags = NLM_F_DUMP|NLM_F_REQUEST;
725 n->nlmsg_pid = 0;
726 n->nlmsg_seq = rth->dump = ++rth->seq;
727
728 return sendmsg(rth->fd, &msg, 0);
729}
730
731static int rtnl_dump_done(struct nlmsghdr *h,
732 const struct rtnl_dump_filter_arg *a)
733{
734 int len;
735
736 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(int))) {
737 fprintf(stderr, "DONE truncated\n");
738 return -1;
739 }
740
741 len = *(int *)NLMSG_DATA(h);
742
743 if (len < 0) {
744 errno = -len;
745
746 if (a->errhndlr && (a->errhndlr(h, a->arg2) & RTNL_SUPPRESS_NLMSG_DONE_NLERR))
747 return 0;
748
749
750 if (nl_dump_ext_ack_done(h, sizeof(int), len))
751 return len;
752
753 switch (errno) {
754 case ENOENT:
755 case EOPNOTSUPP:
756 return -1;
757 case EMSGSIZE:
758 fprintf(stderr,
759 "Error: Buffer too small for object.\n");
760 break;
761 default:
762 perror("RTNETLINK answers");
763 }
764 return len;
765 }
766
767
768 nl_dump_ext_ack(h, NULL);
769
770 return 0;
771}
772
773static int rtnl_dump_error(const struct rtnl_handle *rth,
774 struct nlmsghdr *h,
775 const struct rtnl_dump_filter_arg *a)
776{
777
778 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
779 fprintf(stderr, "ERROR truncated\n");
780 } else {
781 const struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
782
783 errno = -err->error;
784 if (rth->proto == NETLINK_SOCK_DIAG &&
785 (errno == ENOENT ||
786 errno == EOPNOTSUPP))
787 return -1;
788
789 if (a->errhndlr && (a->errhndlr(h, a->arg2) & RTNL_SUPPRESS_NLMSG_ERROR_NLERR))
790 return 0;
791
792 if (!(rth->flags & RTNL_HANDLE_F_SUPPRESS_NLERR))
793 perror("RTNETLINK answers");
794 }
795
796 return -1;
797}
798
799static int __rtnl_recvmsg(int fd, struct msghdr *msg, int flags)
800{
801 int len;
802
803 do {
804 len = recvmsg(fd, msg, flags);
805 } while (len < 0 && (errno == EINTR || errno == EAGAIN));
806
807 if (len < 0) {
808 fprintf(stderr, "netlink receive error %s (%d)\n",
809 strerror(errno), errno);
810 return -errno;
811 }
812
813 if (len == 0) {
814 fprintf(stderr, "EOF on netlink\n");
815 return -ENODATA;
816 }
817
818 return len;
819}
820
821static int rtnl_recvmsg(int fd, struct msghdr *msg, char **answer)
822{
823 struct iovec *iov = msg->msg_iov;
824 char *buf;
825 int len;
826
827 iov->iov_base = NULL;
828 iov->iov_len = 0;
829
830 len = __rtnl_recvmsg(fd, msg, MSG_PEEK | MSG_TRUNC);
831 if (len < 0)
832 return len;
833
834 if (len < 32768)
835 len = 32768;
836 buf = malloc(len);
837 if (!buf) {
838 fprintf(stderr, "malloc error: not enough buffer\n");
839 return -ENOMEM;
840 }
841
842 iov->iov_base = buf;
843 iov->iov_len = len;
844
845 len = __rtnl_recvmsg(fd, msg, 0);
846 if (len < 0) {
847 free(buf);
848 return len;
849 }
850
851 if (answer)
852 *answer = buf;
853 else
854 free(buf);
855
856 return len;
857}
858
859static int rtnl_dump_filter_l(struct rtnl_handle *rth,
860 const struct rtnl_dump_filter_arg *arg)
861{
862 struct sockaddr_nl nladdr;
863 struct iovec iov;
864 struct msghdr msg = {
865 .msg_name = &nladdr,
866 .msg_namelen = sizeof(nladdr),
867 .msg_iov = &iov,
868 .msg_iovlen = 1,
869 };
870 char *buf;
871 int dump_intr = 0;
872
873 while (1) {
874 int status;
875 const struct rtnl_dump_filter_arg *a;
876 int found_done = 0;
877 int msglen = 0;
878
879 status = rtnl_recvmsg(rth->fd, &msg, &buf);
880 if (status < 0)
881 return status;
882
883 if (rth->dump_fp)
884 fwrite(buf, 1, NLMSG_ALIGN(status), rth->dump_fp);
885
886 for (a = arg; a->filter; a++) {
887 struct nlmsghdr *h = (struct nlmsghdr *)buf;
888
889 msglen = status;
890
891 while (NLMSG_OK(h, msglen)) {
892 int err = 0;
893
894 h->nlmsg_flags &= ~a->nc_flags;
895
896 if (nladdr.nl_pid != 0 ||
897 h->nlmsg_pid != rth->local.nl_pid ||
898 h->nlmsg_seq != rth->dump)
899 goto skip_it;
900
901 if (h->nlmsg_flags & NLM_F_DUMP_INTR)
902 dump_intr = 1;
903
904 if (h->nlmsg_type == NLMSG_DONE) {
905 err = rtnl_dump_done(h, a);
906 if (err < 0) {
907 free(buf);
908 return -1;
909 }
910
911 found_done = 1;
912 break;
913 }
914
915 if (h->nlmsg_type == NLMSG_ERROR) {
916 err = rtnl_dump_error(rth, h, a);
917 if (err < 0) {
918 free(buf);
919 return -1;
920 }
921
922 goto skip_it;
923 }
924
925 if (!rth->dump_fp) {
926 err = a->filter(h, a->arg1);
927 if (err < 0) {
928 free(buf);
929 return err;
930 }
931 }
932
933skip_it:
934 h = NLMSG_NEXT(h, msglen);
935 }
936 }
937 free(buf);
938
939 if (found_done) {
940 if (dump_intr)
941 fprintf(stderr,
942 "Dump was interrupted and may be inconsistent.\n");
943 return 0;
944 }
945
946 if (msg.msg_flags & MSG_TRUNC) {
947 fprintf(stderr, "Message truncated\n");
948 continue;
949 }
950 if (msglen) {
951 fprintf(stderr, "!!!Remnant of size %d\n", msglen);
952 exit(1);
953 }
954 }
955}
956
957int rtnl_dump_filter_nc(struct rtnl_handle *rth,
958 rtnl_filter_t filter,
959 void *arg1, __u16 nc_flags)
960{
961 const struct rtnl_dump_filter_arg a[] = {
962 {
963 .filter = filter, .arg1 = arg1,
964 .nc_flags = nc_flags,
965 },
966 { },
967 };
968
969 return rtnl_dump_filter_l(rth, a);
970}
971
972int rtnl_dump_filter_errhndlr_nc(struct rtnl_handle *rth,
973 rtnl_filter_t filter,
974 void *arg1,
975 rtnl_err_hndlr_t errhndlr,
976 void *arg2,
977 __u16 nc_flags)
978{
979 const struct rtnl_dump_filter_arg a[] = {
980 {
981 .filter = filter, .arg1 = arg1,
982 .errhndlr = errhndlr, .arg2 = arg2,
983 .nc_flags = nc_flags,
984 },
985 { },
986 };
987
988 return rtnl_dump_filter_l(rth, a);
989}
990
991static void rtnl_talk_error(struct nlmsghdr *h, struct nlmsgerr *err,
992 nl_ext_ack_fn_t errfn)
993{
994 if (nl_dump_ext_ack(h, errfn))
995 return;
996
997 fprintf(stderr, "RTNETLINK answers: %s\n",
998 strerror(-err->error));
999}
1000
1001
1002static int __rtnl_talk_iov(struct rtnl_handle *rtnl, struct iovec *iov,
1003 size_t iovlen, struct nlmsghdr **answer,
1004 bool show_rtnl_err, nl_ext_ack_fn_t errfn)
1005{
1006 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
1007 struct iovec riov;
1008 struct msghdr msg = {
1009 .msg_name = &nladdr,
1010 .msg_namelen = sizeof(nladdr),
1011 .msg_iov = iov,
1012 .msg_iovlen = iovlen,
1013 };
1014 unsigned int seq = 0;
1015 struct nlmsghdr *h;
1016 int i, status;
1017 char *buf;
1018
1019 for (i = 0; i < iovlen; i++) {
1020 h = iov[i].iov_base;
1021 h->nlmsg_seq = seq = ++rtnl->seq;
1022 if (answer == NULL)
1023 h->nlmsg_flags |= NLM_F_ACK;
1024 }
1025
1026 status = sendmsg(rtnl->fd, &msg, 0);
1027 if (status < 0) {
1028 perror("Cannot talk to rtnetlink");
1029 return -1;
1030 }
1031
1032
1033 msg.msg_iov = &riov;
1034 msg.msg_iovlen = 1;
1035 i = 0;
1036 while (1) {
1037next:
1038 status = rtnl_recvmsg(rtnl->fd, &msg, &buf);
1039 ++i;
1040
1041 if (status < 0)
1042 return status;
1043
1044 if (msg.msg_namelen != sizeof(nladdr)) {
1045 fprintf(stderr,
1046 "sender address length == %d\n",
1047 msg.msg_namelen);
1048 exit(1);
1049 }
1050 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
1051 int len = h->nlmsg_len;
1052 int l = len - sizeof(*h);
1053
1054 if (l < 0 || len > status) {
1055 if (msg.msg_flags & MSG_TRUNC) {
1056 fprintf(stderr, "Truncated message\n");
1057 free(buf);
1058 return -1;
1059 }
1060 fprintf(stderr,
1061 "!!!malformed message: len=%d\n",
1062 len);
1063 exit(1);
1064 }
1065
1066 if (nladdr.nl_pid != 0 ||
1067 h->nlmsg_pid != rtnl->local.nl_pid ||
1068 h->nlmsg_seq > seq || h->nlmsg_seq < seq - iovlen) {
1069
1070 status -= NLMSG_ALIGN(len);
1071 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
1072 continue;
1073 }
1074
1075 if (h->nlmsg_type == NLMSG_ERROR) {
1076 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
1077 int error = err->error;
1078
1079 if (l < sizeof(struct nlmsgerr)) {
1080 fprintf(stderr, "ERROR truncated\n");
1081 free(buf);
1082 return -1;
1083 }
1084
1085 if (!error) {
1086
1087 nl_dump_ext_ack(h, errfn);
1088 } else {
1089 errno = -error;
1090
1091 if (rtnl->proto != NETLINK_SOCK_DIAG &&
1092 show_rtnl_err)
1093 rtnl_talk_error(h, err, errfn);
1094 }
1095
1096 if (i < iovlen) {
1097 free(buf);
1098 goto next;
1099 }
1100
1101 if (error) {
1102 free(buf);
1103 return -i;
1104 }
1105
1106 if (answer)
1107 *answer = (struct nlmsghdr *)buf;
1108 else
1109 free(buf);
1110 return 0;
1111 }
1112
1113 if (answer) {
1114 *answer = (struct nlmsghdr *)buf;
1115 return 0;
1116 }
1117
1118 fprintf(stderr, "Unexpected reply!!!\n");
1119
1120 status -= NLMSG_ALIGN(len);
1121 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
1122 }
1123 free(buf);
1124
1125 if (msg.msg_flags & MSG_TRUNC) {
1126 fprintf(stderr, "Message truncated\n");
1127 continue;
1128 }
1129
1130 if (status) {
1131 fprintf(stderr, "!!!Remnant of size %d\n", status);
1132 exit(1);
1133 }
1134 }
1135}
1136
1137static int __rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
1138 struct nlmsghdr **answer,
1139 bool show_rtnl_err, nl_ext_ack_fn_t errfn)
1140{
1141 struct iovec iov = {
1142 .iov_base = n,
1143 .iov_len = n->nlmsg_len
1144 };
1145
1146 return __rtnl_talk_iov(rtnl, &iov, 1, answer, show_rtnl_err, errfn);
1147}
1148
1149int rtnl_echo_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, int json,
1150 int (*print_info)(struct nlmsghdr *n, void *arg))
1151{
1152 struct nlmsghdr *answer;
1153 int ret;
1154
1155 n->nlmsg_flags |= NLM_F_ECHO | NLM_F_ACK;
1156
1157 ret = rtnl_talk(rtnl, n, &answer);
1158 if (ret)
1159 return ret;
1160
1161 new_json_obj(json);
1162 open_json_object(NULL);
1163 print_info(answer, stdout);
1164 close_json_object();
1165 delete_json_obj();
1166 free(answer);
1167
1168 return 0;
1169}
1170
1171int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n,
1172 struct nlmsghdr **answer)
1173{
1174 return __rtnl_talk(rtnl, n, answer, true, NULL);
1175}
1176
1177int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle *rtnl, struct nlmsghdr *n,
1178 struct nlmsghdr **answer)
1179{
1180 return __rtnl_talk(rtnl, n, answer, false, NULL);
1181}
1182
1183int rtnl_listen_all_nsid(struct rtnl_handle *rth)
1184{
1185 unsigned int on = 1;
1186
1187 if (setsockopt(rth->fd, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, &on,
1188 sizeof(on)) < 0) {
1189 perror("NETLINK_LISTEN_ALL_NSID");
1190 return -1;
1191 }
1192 rth->flags |= RTNL_HANDLE_F_LISTEN_ALL_NSID;
1193 return 0;
1194}
1195
1196int rtnl_listen(struct rtnl_handle *rtnl,
1197 rtnl_listen_filter_t handler,
1198 void *jarg)
1199{
1200 int status;
1201 struct nlmsghdr *h;
1202 struct sockaddr_nl nladdr = { .nl_family = AF_NETLINK };
1203 struct iovec iov;
1204 struct msghdr msg = {
1205 .msg_name = &nladdr,
1206 .msg_namelen = sizeof(nladdr),
1207 .msg_iov = &iov,
1208 .msg_iovlen = 1,
1209 };
1210 char buf[16384];
1211 char cmsgbuf[BUFSIZ];
1212
1213 iov.iov_base = buf;
1214 while (1) {
1215 struct rtnl_ctrl_data ctrl;
1216 struct cmsghdr *cmsg;
1217
1218 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
1219 msg.msg_control = &cmsgbuf;
1220 msg.msg_controllen = sizeof(cmsgbuf);
1221 }
1222
1223 iov.iov_len = sizeof(buf);
1224 status = recvmsg(rtnl->fd, &msg, 0);
1225
1226 if (status < 0) {
1227 if (errno == EINTR || errno == EAGAIN)
1228 continue;
1229 fprintf(stderr, "netlink receive error %s (%d)\n",
1230 strerror(errno), errno);
1231 if (errno == ENOBUFS)
1232 continue;
1233 return -1;
1234 }
1235 if (status == 0) {
1236 fprintf(stderr, "EOF on netlink\n");
1237 return -1;
1238 }
1239 if (msg.msg_namelen != sizeof(nladdr)) {
1240 fprintf(stderr,
1241 "Sender address length == %d\n",
1242 msg.msg_namelen);
1243 exit(1);
1244 }
1245
1246 if (rtnl->flags & RTNL_HANDLE_F_LISTEN_ALL_NSID) {
1247 memset(&ctrl, 0, sizeof(ctrl));
1248 ctrl.nsid = -1;
1249 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
1250 cmsg = CMSG_NXTHDR(&msg, cmsg))
1251 if (cmsg->cmsg_level == SOL_NETLINK &&
1252 cmsg->cmsg_type == NETLINK_LISTEN_ALL_NSID &&
1253 cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
1254 int *data = (int *)CMSG_DATA(cmsg);
1255
1256 ctrl.nsid = *data;
1257 }
1258 }
1259
1260 for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
1261 int err;
1262 int len = h->nlmsg_len;
1263 int l = len - sizeof(*h);
1264
1265 if (l < 0 || len > status) {
1266 if (msg.msg_flags & MSG_TRUNC) {
1267 fprintf(stderr, "Truncated message\n");
1268 return -1;
1269 }
1270 fprintf(stderr,
1271 "!!!malformed message: len=%d\n",
1272 len);
1273 exit(1);
1274 }
1275
1276 err = handler(&ctrl, h, jarg);
1277 if (err < 0)
1278 return err;
1279
1280 status -= NLMSG_ALIGN(len);
1281 h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
1282 }
1283 if (msg.msg_flags & MSG_TRUNC) {
1284 fprintf(stderr, "Message truncated\n");
1285 continue;
1286 }
1287 if (status) {
1288 fprintf(stderr, "!!!Remnant of size %d\n", status);
1289 exit(1);
1290 }
1291 }
1292}
1293
1294int rtnl_from_file(FILE *rtnl, rtnl_listen_filter_t handler,
1295 void *jarg)
1296{
1297 size_t status;
1298 char buf[16384];
1299 struct nlmsghdr *h = (struct nlmsghdr *)buf;
1300
1301 while (1) {
1302 int err, len;
1303 int l;
1304
1305 status = fread(&buf, 1, sizeof(*h), rtnl);
1306
1307 if (status == 0 && feof(rtnl))
1308 return 0;
1309 if (status != sizeof(*h)) {
1310 if (ferror(rtnl))
1311 perror("rtnl_from_file: fread");
1312 if (feof(rtnl))
1313 fprintf(stderr, "rtnl-from_file: truncated message\n");
1314 return -1;
1315 }
1316
1317 len = h->nlmsg_len;
1318 l = len - sizeof(*h);
1319
1320 if (l < 0 || len > sizeof(buf)) {
1321 fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
1322 len, ftell(rtnl));
1323 return -1;
1324 }
1325
1326 status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
1327
1328 if (status != NLMSG_ALIGN(l)) {
1329 if (ferror(rtnl))
1330 perror("rtnl_from_file: fread");
1331 if (feof(rtnl))
1332 fprintf(stderr, "rtnl-from_file: truncated message\n");
1333 return -1;
1334 }
1335
1336 err = handler(NULL, h, jarg);
1337 if (err < 0)
1338 return err;
1339 }
1340}
1341
1342int addattr(struct nlmsghdr *n, int maxlen, int type)
1343{
1344 return addattr_l(n, maxlen, type, NULL, 0);
1345}
1346
1347int addattr8(struct nlmsghdr *n, int maxlen, int type, __u8 data)
1348{
1349 return addattr_l(n, maxlen, type, &data, sizeof(__u8));
1350}
1351
1352int addattr16(struct nlmsghdr *n, int maxlen, int type, __u16 data)
1353{
1354 return addattr_l(n, maxlen, type, &data, sizeof(__u16));
1355}
1356
1357int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
1358{
1359 return addattr_l(n, maxlen, type, &data, sizeof(__u32));
1360}
1361
1362int addattr64(struct nlmsghdr *n, int maxlen, int type, __u64 data)
1363{
1364 return addattr_l(n, maxlen, type, &data, sizeof(__u64));
1365}
1366
1367int addattrstrz(struct nlmsghdr *n, int maxlen, int type, const char *str)
1368{
1369 return addattr_l(n, maxlen, type, str, strlen(str)+1);
1370}
1371
1372int addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data,
1373 int alen)
1374{
1375 int len = RTA_LENGTH(alen);
1376 struct rtattr *rta;
1377
1378 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) {
1379 fprintf(stderr,
1380 "addattr_l ERROR: message exceeded bound of %d\n",
1381 maxlen);
1382 return -1;
1383 }
1384 rta = NLMSG_TAIL(n);
1385 rta->rta_type = type;
1386 rta->rta_len = len;
1387 if (alen)
1388 memcpy(RTA_DATA(rta), data, alen);
1389 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
1390 return 0;
1391}
1392
1393int addraw_l(struct nlmsghdr *n, int maxlen, const void *data, int len)
1394{
1395 if (NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len) > maxlen) {
1396 fprintf(stderr,
1397 "addraw_l ERROR: message exceeded bound of %d\n",
1398 maxlen);
1399 return -1;
1400 }
1401
1402 memcpy(NLMSG_TAIL(n), data, len);
1403 memset((void *) NLMSG_TAIL(n) + len, 0, NLMSG_ALIGN(len) - len);
1404 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + NLMSG_ALIGN(len);
1405 return 0;
1406}
1407
1408struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
1409{
1410 struct rtattr *nest = NLMSG_TAIL(n);
1411
1412 addattr_l(n, maxlen, type, NULL, 0);
1413 return nest;
1414}
1415
1416int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest)
1417{
1418 nest->rta_len = (void *)NLMSG_TAIL(n) - (void *)nest;
1419 return n->nlmsg_len;
1420}
1421
1422struct rtattr *addattr_nest_compat(struct nlmsghdr *n, int maxlen, int type,
1423 const void *data, int len)
1424{
1425 struct rtattr *start = NLMSG_TAIL(n);
1426
1427 addattr_l(n, maxlen, type, data, len);
1428 addattr_nest(n, maxlen, type);
1429 return start;
1430}
1431
1432int addattr_nest_compat_end(struct nlmsghdr *n, struct rtattr *start)
1433{
1434 struct rtattr *nest = (void *)start + NLMSG_ALIGN(start->rta_len);
1435
1436 start->rta_len = (void *)NLMSG_TAIL(n) - (void *)start;
1437 addattr_nest_end(n, nest);
1438 return n->nlmsg_len;
1439}
1440
1441int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
1442{
1443 int len = RTA_LENGTH(4);
1444 struct rtattr *subrta;
1445
1446 if (RTA_ALIGN(rta->rta_len) + len > maxlen) {
1447 fprintf(stderr,
1448 "rta_addattr32: Error! max allowed bound %d exceeded\n",
1449 maxlen);
1450 return -1;
1451 }
1452 subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
1453 subrta->rta_type = type;
1454 subrta->rta_len = len;
1455 memcpy(RTA_DATA(subrta), &data, 4);
1456 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
1457 return 0;
1458}
1459
1460int rta_addattr_l(struct rtattr *rta, int maxlen, int type,
1461 const void *data, int alen)
1462{
1463 struct rtattr *subrta;
1464 int len = RTA_LENGTH(alen);
1465
1466 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) {
1467 fprintf(stderr,
1468 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
1469 maxlen);
1470 return -1;
1471 }
1472 subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len));
1473 subrta->rta_type = type;
1474 subrta->rta_len = len;
1475 if (alen)
1476 memcpy(RTA_DATA(subrta), data, alen);
1477 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len);
1478 return 0;
1479}
1480
1481int rta_addattr8(struct rtattr *rta, int maxlen, int type, __u8 data)
1482{
1483 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u8));
1484}
1485
1486int rta_addattr16(struct rtattr *rta, int maxlen, int type, __u16 data)
1487{
1488 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u16));
1489}
1490
1491int rta_addattr64(struct rtattr *rta, int maxlen, int type, __u64 data)
1492{
1493 return rta_addattr_l(rta, maxlen, type, &data, sizeof(__u64));
1494}
1495
1496struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type)
1497{
1498 struct rtattr *nest = RTA_TAIL(rta);
1499
1500 rta_addattr_l(rta, maxlen, type, NULL, 0);
1501 nest->rta_type |= NLA_F_NESTED;
1502
1503 return nest;
1504}
1505
1506int rta_nest_end(struct rtattr *rta, struct rtattr *nest)
1507{
1508 nest->rta_len = (void *)RTA_TAIL(rta) - (void *)nest;
1509
1510 return rta->rta_len;
1511}
1512
1513int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
1514{
1515 return parse_rtattr_flags(tb, max, rta, len, 0);
1516}
1517
1518int parse_rtattr_flags(struct rtattr *tb[], int max, struct rtattr *rta,
1519 int len, unsigned short flags)
1520{
1521 unsigned short type;
1522
1523 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
1524 while (RTA_OK(rta, len)) {
1525 type = rta->rta_type & ~flags;
1526 if ((type <= max) && (!tb[type]))
1527 tb[type] = rta;
1528 rta = RTA_NEXT(rta, len);
1529 }
1530 if (len)
1531 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
1532 len, rta->rta_len);
1533 return 0;
1534}
1535
1536struct rtattr *parse_rtattr_one(int type, struct rtattr *rta, int len)
1537{
1538 while (RTA_OK(rta, len)) {
1539 if (rta->rta_type == type)
1540 return rta;
1541 rta = RTA_NEXT(rta, len);
1542 }
1543
1544 if (len)
1545 fprintf(stderr, "!!!Deficit %d, rta_len=%d\n",
1546 len, rta->rta_len);
1547 return NULL;
1548}
1549
1550int __parse_rtattr_nested_compat(struct rtattr *tb[], int max,
1551 struct rtattr *rta,
1552 int len)
1553{
1554 if (RTA_PAYLOAD(rta) < len)
1555 return -1;
1556 if (RTA_PAYLOAD(rta) >= RTA_ALIGN(len) + sizeof(struct rtattr)) {
1557 rta = RTA_DATA(rta) + RTA_ALIGN(len);
1558 return parse_rtattr_nested(tb, max, rta);
1559 }
1560 memset(tb, 0, sizeof(struct rtattr *) * (max + 1));
1561 return 0;
1562}
1563
1564static const char *get_nla_type_str(unsigned int attr)
1565{
1566 switch (attr) {
1567#define C(x) case NL_ATTR_TYPE_ ## x: return #x
1568 C(U8);
1569 C(U16);
1570 C(U32);
1571 C(U64);
1572 C(STRING);
1573 C(FLAG);
1574 C(NESTED);
1575 C(NESTED_ARRAY);
1576 C(NUL_STRING);
1577 C(BINARY);
1578 C(S8);
1579 C(S16);
1580 C(S32);
1581 C(S64);
1582 C(BITFIELD32);
1583 default:
1584 return "unknown";
1585 }
1586}
1587
1588void nl_print_policy(const struct rtattr *attr, FILE *fp)
1589{
1590 const struct rtattr *pos;
1591
1592 rtattr_for_each_nested(pos, attr) {
1593 const struct rtattr *attr;
1594
1595 fprintf(fp, " policy[%u]:", pos->rta_type & ~NLA_F_NESTED);
1596
1597 rtattr_for_each_nested(attr, pos) {
1598 struct rtattr *tp[NL_POLICY_TYPE_ATTR_MAX + 1];
1599
1600 parse_rtattr_nested(tp, ARRAY_SIZE(tp) - 1, attr);
1601
1602 if (tp[NL_POLICY_TYPE_ATTR_TYPE])
1603 fprintf(fp, "attr[%u]: type=%s",
1604 attr->rta_type & ~NLA_F_NESTED,
1605 get_nla_type_str(rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_TYPE])));
1606
1607 if (tp[NL_POLICY_TYPE_ATTR_POLICY_IDX])
1608 fprintf(fp, " policy:%u",
1609 rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_POLICY_IDX]));
1610
1611 if (tp[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE])
1612 fprintf(fp, " maxattr:%u",
1613 rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE]));
1614
1615 if (tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_S] && tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_S])
1616 fprintf(fp, " range:[%lld,%lld]",
1617 (signed long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_S]),
1618 (signed long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_S]));
1619
1620 if (tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_U] && tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_U])
1621 fprintf(fp, " range:[%llu,%llu]",
1622 (unsigned long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MIN_VALUE_U]),
1623 (unsigned long long)rta_getattr_u64(tp[NL_POLICY_TYPE_ATTR_MAX_VALUE_U]));
1624
1625 if (tp[NL_POLICY_TYPE_ATTR_MIN_LENGTH])
1626 fprintf(fp, " min len:%u",
1627 rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_MIN_LENGTH]));
1628
1629 if (tp[NL_POLICY_TYPE_ATTR_MAX_LENGTH])
1630 fprintf(fp, " max len:%u",
1631 rta_getattr_u32(tp[NL_POLICY_TYPE_ATTR_MAX_LENGTH]));
1632 }
1633 }
1634}
1635
1636int rtnl_tunneldump_req(struct rtnl_handle *rth, int family, int ifindex,
1637 __u8 flags)
1638{
1639 struct {
1640 struct nlmsghdr nlh;
1641 struct tunnel_msg tmsg;
1642 char buf[256];
1643 } req = {
1644 .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct tunnel_msg)),
1645 .nlh.nlmsg_type = RTM_GETTUNNEL,
1646 .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
1647 .nlh.nlmsg_seq = rth->dump = ++rth->seq,
1648 .tmsg.family = family,
1649 .tmsg.flags = flags,
1650 .tmsg.ifindex = ifindex,
1651 };
1652
1653 return send(rth->fd, &req, sizeof(req), 0);
1654}
1655