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