2 * libnetlink.c RTnetlink service routines.
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
18 #include <net/if_arp.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
26 #include "libnetlink.h"
29 #define SOL_NETLINK 270
33 #define MIN(a, b) ((a) < (b) ? (a) : (b))
36 int rcvbuf
= 1024 * 1024;
39 #include <libmnl/libmnl.h>
41 static const enum mnl_attr_data_type extack_policy
[NLMSGERR_ATTR_MAX
+ 1] = {
42 [NLMSGERR_ATTR_MSG
] = MNL_TYPE_NUL_STRING
,
43 [NLMSGERR_ATTR_OFFS
] = MNL_TYPE_U32
,
46 static int err_attr_cb(const struct nlattr
*attr
, void *data
)
48 const struct nlattr
**tb
= data
;
51 if (mnl_attr_type_valid(attr
, NLMSGERR_ATTR_MAX
) < 0) {
52 fprintf(stderr
, "Invalid extack attribute\n");
56 type
= mnl_attr_get_type(attr
);
57 if (mnl_attr_validate(attr
, extack_policy
[type
]) < 0) {
58 fprintf(stderr
, "extack attribute %d failed validation\n",
67 /* dump netlink extended ack error message */
68 int nl_dump_ext_ack(const struct nlmsghdr
*nlh
, nl_ext_ack_fn_t errfn
)
70 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1] = {};
71 const struct nlmsgerr
*err
= mnl_nlmsg_get_payload(nlh
);
72 const struct nlmsghdr
*err_nlh
= NULL
;
73 unsigned int hlen
= sizeof(*err
);
74 const char *msg
= NULL
;
77 /* no TLVs, nothing to do here */
78 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
81 /* if NLM_F_CAPPED is set then the inner err msg was capped */
82 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
83 hlen
+= mnl_nlmsg_get_payload_len(&err
->msg
);
85 if (mnl_attr_parse(nlh
, hlen
, err_attr_cb
, tb
) != MNL_CB_OK
)
88 if (tb
[NLMSGERR_ATTR_MSG
])
89 msg
= mnl_attr_get_str(tb
[NLMSGERR_ATTR_MSG
]);
91 if (tb
[NLMSGERR_ATTR_OFFS
]) {
92 off
= mnl_attr_get_u32(tb
[NLMSGERR_ATTR_OFFS
]);
94 if (off
> nlh
->nlmsg_len
) {
96 "Invalid offset for NLMSGERR_ATTR_OFFS\n");
98 } else if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
103 return errfn(msg
, off
, err_nlh
);
105 if (msg
&& *msg
!= '\0') {
106 bool is_err
= !!err
->error
;
108 fprintf(stderr
, "%s: %s",
109 is_err
? "Error" : "Warning", msg
);
110 if (msg
[strlen(msg
) - 1] != '.')
111 fprintf(stderr
, ".");
112 fprintf(stderr
, "\n");
114 return is_err
? 1 : 0;
120 #warning "libmnl required for error support"
122 /* No extended error ack without libmnl */
123 int nl_dump_ext_ack(const struct nlmsghdr
*nlh
, nl_ext_ack_fn_t errfn
)
129 void rtnl_close(struct rtnl_handle
*rth
)
137 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned int subscriptions
,
144 memset(rth
, 0, sizeof(*rth
));
146 rth
->proto
= protocol
;
147 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
149 perror("Cannot open netlink socket");
153 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
,
154 &sndbuf
, sizeof(sndbuf
)) < 0) {
159 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
,
160 &rcvbuf
, sizeof(rcvbuf
)) < 0) {
165 /* Older kernels may no support extended ACK reporting */
166 setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_EXT_ACK
,
169 memset(&rth
->local
, 0, sizeof(rth
->local
));
170 rth
->local
.nl_family
= AF_NETLINK
;
171 rth
->local
.nl_groups
= subscriptions
;
173 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
,
174 sizeof(rth
->local
)) < 0) {
175 perror("Cannot bind netlink socket");
178 addr_len
= sizeof(rth
->local
);
179 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
,
181 perror("Cannot getsockname");
184 if (addr_len
!= sizeof(rth
->local
)) {
185 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
188 if (rth
->local
.nl_family
!= AF_NETLINK
) {
189 fprintf(stderr
, "Wrong address family %d\n",
190 rth
->local
.nl_family
);
193 rth
->seq
= time(NULL
);
197 int rtnl_open(struct rtnl_handle
*rth
, unsigned int subscriptions
)
199 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
202 int rtnl_addrdump_req(struct rtnl_handle
*rth
, int family
)
206 struct ifaddrmsg ifm
;
208 .nlh
.nlmsg_len
= sizeof(req
),
209 .nlh
.nlmsg_type
= RTM_GETADDR
,
210 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
211 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
212 .ifm
.ifa_family
= family
,
215 return send(rth
->fd
, &req
, sizeof(req
), 0);
218 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
220 return rtnl_wilddump_req_filter(rth
, family
, type
, RTEXT_FILTER_VF
);
223 int rtnl_wilddump_req_filter(struct rtnl_handle
*rth
, int family
, int type
,
228 struct ifinfomsg ifm
;
229 /* attribute has to be NLMSG aligned */
230 struct rtattr ext_req
__attribute__ ((aligned(NLMSG_ALIGNTO
)));
231 __u32 ext_filter_mask
;
233 .nlh
.nlmsg_len
= sizeof(req
),
234 .nlh
.nlmsg_type
= type
,
235 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
236 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
237 .ifm
.ifi_family
= family
,
238 .ext_req
.rta_type
= IFLA_EXT_MASK
,
239 .ext_req
.rta_len
= RTA_LENGTH(sizeof(__u32
)),
240 .ext_filter_mask
= filt_mask
,
243 return send(rth
->fd
, &req
, sizeof(req
), 0);
246 int rtnl_wilddump_req_filter_fn(struct rtnl_handle
*rth
, int family
, int type
,
247 req_filter_fn_t filter_fn
)
251 struct ifinfomsg ifm
;
254 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
255 .nlh
.nlmsg_type
= type
,
256 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
257 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
258 .ifm
.ifi_family
= family
,
265 err
= filter_fn(&req
.nlh
, sizeof(req
));
269 return send(rth
->fd
, &req
, req
.nlh
.nlmsg_len
, 0);
272 int rtnl_wilddump_stats_req_filter(struct rtnl_handle
*rth
, int fam
, int type
,
277 struct if_stats_msg ifsm
;
280 memset(&req
, 0, sizeof(req
));
281 req
.nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct if_stats_msg
));
282 req
.nlh
.nlmsg_type
= type
;
283 req
.nlh
.nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
284 req
.nlh
.nlmsg_pid
= 0;
285 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
286 req
.ifsm
.family
= fam
;
287 req
.ifsm
.filter_mask
= filt_mask
;
289 return send(rth
->fd
, &req
, sizeof(req
), 0);
292 int rtnl_send(struct rtnl_handle
*rth
, const void *buf
, int len
)
294 return send(rth
->fd
, buf
, len
, 0);
297 int rtnl_send_check(struct rtnl_handle
*rth
, const void *buf
, int len
)
303 status
= send(rth
->fd
, buf
, len
, 0);
307 /* Check for immediate errors */
308 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
|MSG_PEEK
);
315 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, status
);
316 h
= NLMSG_NEXT(h
, status
)) {
317 if (h
->nlmsg_type
== NLMSG_ERROR
) {
318 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
320 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
321 fprintf(stderr
, "ERROR truncated\n");
331 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
333 struct nlmsghdr nlh
= {
334 .nlmsg_len
= NLMSG_LENGTH(len
),
336 .nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
337 .nlmsg_seq
= rth
->dump
= ++rth
->seq
,
339 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
340 struct iovec iov
[2] = {
341 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
342 { .iov_base
= req
, .iov_len
= len
}
344 struct msghdr msg
= {
346 .msg_namelen
= sizeof(nladdr
),
351 return sendmsg(rth
->fd
, &msg
, 0);
354 int rtnl_dump_request_n(struct rtnl_handle
*rth
, struct nlmsghdr
*n
)
356 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
359 .iov_len
= n
->nlmsg_len
361 struct msghdr msg
= {
363 .msg_namelen
= sizeof(nladdr
),
368 n
->nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
370 n
->nlmsg_seq
= rth
->dump
= ++rth
->seq
;
372 return sendmsg(rth
->fd
, &msg
, 0);
375 static int rtnl_dump_done(struct nlmsghdr
*h
)
377 int len
= *(int *)NLMSG_DATA(h
);
379 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(int))) {
380 fprintf(stderr
, "DONE truncated\n");
392 "Error: Buffer too small for object.\n");
395 perror("RTNETLINK answers");
400 /* check for any messages returned from kernel */
401 nl_dump_ext_ack(h
, NULL
);
406 static void rtnl_dump_error(const struct rtnl_handle
*rth
,
410 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
411 fprintf(stderr
, "ERROR truncated\n");
413 const struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
416 if (rth
->proto
== NETLINK_SOCK_DIAG
&&
418 errno
== EOPNOTSUPP
))
421 if (!(rth
->flags
& RTNL_HANDLE_F_SUPPRESS_NLERR
))
422 perror("RTNETLINK answers");
426 static int __rtnl_recvmsg(int fd
, struct msghdr
*msg
, int flags
)
431 len
= recvmsg(fd
, msg
, flags
);
432 } while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
435 fprintf(stderr
, "netlink receive error %s (%d)\n",
436 strerror(errno
), errno
);
441 fprintf(stderr
, "EOF on netlink\n");
448 static int rtnl_recvmsg(int fd
, struct msghdr
*msg
, char **answer
)
450 struct iovec
*iov
= msg
->msg_iov
;
454 iov
->iov_base
= NULL
;
457 len
= __rtnl_recvmsg(fd
, msg
, MSG_PEEK
| MSG_TRUNC
);
463 fprintf(stderr
, "malloc error: not enough buffer\n");
470 len
= __rtnl_recvmsg(fd
, msg
, 0);
484 int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
485 const struct rtnl_dump_filter_arg
*arg
)
487 struct sockaddr_nl nladdr
;
489 struct msghdr msg
= {
491 .msg_namelen
= sizeof(nladdr
),
500 const struct rtnl_dump_filter_arg
*a
;
504 status
= rtnl_recvmsg(rth
->fd
, &msg
, &buf
);
509 fwrite(buf
, 1, NLMSG_ALIGN(status
), rth
->dump_fp
);
511 for (a
= arg
; a
->filter
; a
++) {
512 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
516 while (NLMSG_OK(h
, msglen
)) {
519 h
->nlmsg_flags
&= ~a
->nc_flags
;
521 if (nladdr
.nl_pid
!= 0 ||
522 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
523 h
->nlmsg_seq
!= rth
->dump
)
526 if (h
->nlmsg_flags
& NLM_F_DUMP_INTR
)
529 if (h
->nlmsg_type
== NLMSG_DONE
) {
530 err
= rtnl_dump_done(h
);
537 break; /* process next filter */
540 if (h
->nlmsg_type
== NLMSG_ERROR
) {
541 rtnl_dump_error(rth
, h
);
547 err
= a
->filter(&nladdr
, h
, a
->arg1
);
555 h
= NLMSG_NEXT(h
, msglen
);
563 "Dump was interrupted and may be inconsistent.\n");
567 if (msg
.msg_flags
& MSG_TRUNC
) {
568 fprintf(stderr
, "Message truncated\n");
572 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
578 int rtnl_dump_filter_nc(struct rtnl_handle
*rth
,
579 rtnl_filter_t filter
,
580 void *arg1
, __u16 nc_flags
)
582 const struct rtnl_dump_filter_arg a
[2] = {
583 { .filter
= filter
, .arg1
= arg1
, .nc_flags
= nc_flags
, },
584 { .filter
= NULL
, .arg1
= NULL
, .nc_flags
= 0, },
587 return rtnl_dump_filter_l(rth
, a
);
590 static void rtnl_talk_error(struct nlmsghdr
*h
, struct nlmsgerr
*err
,
591 nl_ext_ack_fn_t errfn
)
593 if (nl_dump_ext_ack(h
, errfn
))
596 fprintf(stderr
, "RTNETLINK answers: %s\n",
597 strerror(-err
->error
));
601 static int __rtnl_talk_iov(struct rtnl_handle
*rtnl
, struct iovec
*iov
,
602 size_t iovlen
, struct nlmsghdr
**answer
,
603 bool show_rtnl_err
, nl_ext_ack_fn_t errfn
)
605 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
607 struct msghdr msg
= {
609 .msg_namelen
= sizeof(nladdr
),
611 .msg_iovlen
= iovlen
,
613 unsigned int seq
= 0;
618 for (i
= 0; i
< iovlen
; i
++) {
620 h
->nlmsg_seq
= seq
= ++rtnl
->seq
;
622 h
->nlmsg_flags
|= NLM_F_ACK
;
625 status
= sendmsg(rtnl
->fd
, &msg
, 0);
627 perror("Cannot talk to rtnetlink");
631 /* change msg to use the response iov */
636 status
= rtnl_recvmsg(rtnl
->fd
, &msg
, &buf
);
642 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
644 "sender address length == %d\n",
648 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
649 int len
= h
->nlmsg_len
;
650 int l
= len
- sizeof(*h
);
652 if (l
< 0 || len
> status
) {
653 if (msg
.msg_flags
& MSG_TRUNC
) {
654 fprintf(stderr
, "Truncated message\n");
659 "!!!malformed message: len=%d\n",
664 if (nladdr
.nl_pid
!= 0 ||
665 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
666 h
->nlmsg_seq
> seq
|| h
->nlmsg_seq
< seq
- iovlen
) {
667 /* Don't forget to skip that message. */
668 status
-= NLMSG_ALIGN(len
);
669 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
673 if (h
->nlmsg_type
== NLMSG_ERROR
) {
674 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
676 if (l
< sizeof(struct nlmsgerr
)) {
677 fprintf(stderr
, "ERROR truncated\n");
683 /* check messages from kernel */
684 nl_dump_ext_ack(h
, errfn
);
688 if (rtnl
->proto
!= NETLINK_SOCK_DIAG
&&
690 rtnl_talk_error(h
, err
, errfn
);
694 *answer
= (struct nlmsghdr
*)buf
;
698 return err
->error
? -i
: 0;
702 *answer
= (struct nlmsghdr
*)buf
;
706 fprintf(stderr
, "Unexpected reply!!!\n");
708 status
-= NLMSG_ALIGN(len
);
709 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
713 if (msg
.msg_flags
& MSG_TRUNC
) {
714 fprintf(stderr
, "Message truncated\n");
719 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
725 static int __rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
726 struct nlmsghdr
**answer
,
727 bool show_rtnl_err
, nl_ext_ack_fn_t errfn
)
731 .iov_len
= n
->nlmsg_len
734 return __rtnl_talk_iov(rtnl
, &iov
, 1, answer
, show_rtnl_err
, errfn
);
737 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
738 struct nlmsghdr
**answer
)
740 return __rtnl_talk(rtnl
, n
, answer
, true, NULL
);
743 int rtnl_talk_iov(struct rtnl_handle
*rtnl
, struct iovec
*iovec
, size_t iovlen
,
744 struct nlmsghdr
**answer
)
746 return __rtnl_talk_iov(rtnl
, iovec
, iovlen
, answer
, true, NULL
);
749 int rtnl_talk_extack(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
750 struct nlmsghdr
**answer
,
751 nl_ext_ack_fn_t errfn
)
753 return __rtnl_talk(rtnl
, n
, answer
, true, errfn
);
756 int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
757 struct nlmsghdr
**answer
)
759 return __rtnl_talk(rtnl
, n
, answer
, false, NULL
);
762 int rtnl_listen_all_nsid(struct rtnl_handle
*rth
)
766 if (setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_LISTEN_ALL_NSID
, &on
,
768 perror("NETLINK_LISTEN_ALL_NSID");
771 rth
->flags
|= RTNL_HANDLE_F_LISTEN_ALL_NSID
;
775 int rtnl_listen(struct rtnl_handle
*rtnl
,
776 rtnl_listen_filter_t handler
,
781 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
783 struct msghdr msg
= {
785 .msg_namelen
= sizeof(nladdr
),
790 char cmsgbuf
[BUFSIZ
];
792 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
793 msg
.msg_control
= &cmsgbuf
;
794 msg
.msg_controllen
= sizeof(cmsgbuf
);
799 struct rtnl_ctrl_data ctrl
;
800 struct cmsghdr
*cmsg
;
802 iov
.iov_len
= sizeof(buf
);
803 status
= recvmsg(rtnl
->fd
, &msg
, 0);
806 if (errno
== EINTR
|| errno
== EAGAIN
)
808 fprintf(stderr
, "netlink receive error %s (%d)\n",
809 strerror(errno
), errno
);
810 if (errno
== ENOBUFS
)
815 fprintf(stderr
, "EOF on netlink\n");
818 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
820 "Sender address length == %d\n",
825 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
826 memset(&ctrl
, 0, sizeof(ctrl
));
828 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
;
829 cmsg
= CMSG_NXTHDR(&msg
, cmsg
))
830 if (cmsg
->cmsg_level
== SOL_NETLINK
&&
831 cmsg
->cmsg_type
== NETLINK_LISTEN_ALL_NSID
&&
832 cmsg
->cmsg_len
== CMSG_LEN(sizeof(int))) {
833 int *data
= (int *)CMSG_DATA(cmsg
);
839 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
841 int len
= h
->nlmsg_len
;
842 int l
= len
- sizeof(*h
);
844 if (l
< 0 || len
> status
) {
845 if (msg
.msg_flags
& MSG_TRUNC
) {
846 fprintf(stderr
, "Truncated message\n");
850 "!!!malformed message: len=%d\n",
855 err
= handler(&nladdr
, &ctrl
, h
, jarg
);
859 status
-= NLMSG_ALIGN(len
);
860 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
862 if (msg
.msg_flags
& MSG_TRUNC
) {
863 fprintf(stderr
, "Message truncated\n");
867 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
873 int rtnl_from_file(FILE *rtnl
, rtnl_listen_filter_t handler
,
877 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
879 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
885 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
890 perror("rtnl_from_file: fread");
897 l
= len
- sizeof(*h
);
899 if (l
< 0 || len
> sizeof(buf
)) {
900 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
905 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
908 perror("rtnl_from_file: fread");
912 fprintf(stderr
, "rtnl-from_file: truncated message\n");
916 err
= handler(&nladdr
, NULL
, h
, jarg
);
922 int addattr(struct nlmsghdr
*n
, int maxlen
, int type
)
924 return addattr_l(n
, maxlen
, type
, NULL
, 0);
927 int addattr8(struct nlmsghdr
*n
, int maxlen
, int type
, __u8 data
)
929 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u8
));
932 int addattr16(struct nlmsghdr
*n
, int maxlen
, int type
, __u16 data
)
934 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u16
));
937 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
939 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u32
));
942 int addattr64(struct nlmsghdr
*n
, int maxlen
, int type
, __u64 data
)
944 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u64
));
947 int addattrstrz(struct nlmsghdr
*n
, int maxlen
, int type
, const char *str
)
949 return addattr_l(n
, maxlen
, type
, str
, strlen(str
)+1);
952 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
955 int len
= RTA_LENGTH(alen
);
958 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
960 "addattr_l ERROR: message exceeded bound of %d\n",
965 rta
->rta_type
= type
;
968 memcpy(RTA_DATA(rta
), data
, alen
);
969 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
973 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
975 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
977 "addraw_l ERROR: message exceeded bound of %d\n",
982 memcpy(NLMSG_TAIL(n
), data
, len
);
983 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
984 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
988 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
990 struct rtattr
*nest
= NLMSG_TAIL(n
);
992 addattr_l(n
, maxlen
, type
, NULL
, 0);
996 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
998 nest
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)nest
;
1002 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
1003 const void *data
, int len
)
1005 struct rtattr
*start
= NLMSG_TAIL(n
);
1007 addattr_l(n
, maxlen
, type
, data
, len
);
1008 addattr_nest(n
, maxlen
, type
);
1012 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
1014 struct rtattr
*nest
= (void *)start
+ NLMSG_ALIGN(start
->rta_len
);
1016 start
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)start
;
1017 addattr_nest_end(n
, nest
);
1018 return n
->nlmsg_len
;
1021 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
1023 int len
= RTA_LENGTH(4);
1024 struct rtattr
*subrta
;
1026 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
1028 "rta_addattr32: Error! max allowed bound %d exceeded\n",
1032 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
1033 subrta
->rta_type
= type
;
1034 subrta
->rta_len
= len
;
1035 memcpy(RTA_DATA(subrta
), &data
, 4);
1036 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
1040 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
1041 const void *data
, int alen
)
1043 struct rtattr
*subrta
;
1044 int len
= RTA_LENGTH(alen
);
1046 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
1048 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
1052 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
1053 subrta
->rta_type
= type
;
1054 subrta
->rta_len
= len
;
1056 memcpy(RTA_DATA(subrta
), data
, alen
);
1057 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
1061 int rta_addattr8(struct rtattr
*rta
, int maxlen
, int type
, __u8 data
)
1063 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u8
));
1066 int rta_addattr16(struct rtattr
*rta
, int maxlen
, int type
, __u16 data
)
1068 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u16
));
1071 int rta_addattr64(struct rtattr
*rta
, int maxlen
, int type
, __u64 data
)
1073 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u64
));
1076 struct rtattr
*rta_nest(struct rtattr
*rta
, int maxlen
, int type
)
1078 struct rtattr
*nest
= RTA_TAIL(rta
);
1080 rta_addattr_l(rta
, maxlen
, type
, NULL
, 0);
1085 int rta_nest_end(struct rtattr
*rta
, struct rtattr
*nest
)
1087 nest
->rta_len
= (void *)RTA_TAIL(rta
) - (void *)nest
;
1089 return rta
->rta_len
;
1092 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
1094 return parse_rtattr_flags(tb
, max
, rta
, len
, 0);
1097 int parse_rtattr_flags(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
1098 int len
, unsigned short flags
)
1100 unsigned short type
;
1102 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
1103 while (RTA_OK(rta
, len
)) {
1104 type
= rta
->rta_type
& ~flags
;
1105 if ((type
<= max
) && (!tb
[type
]))
1107 rta
= RTA_NEXT(rta
, len
);
1110 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1115 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
,
1116 struct rtattr
*rta
, int len
)
1120 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
1121 while (RTA_OK(rta
, len
)) {
1122 if (rta
->rta_type
<= max
&& i
< max
)
1124 rta
= RTA_NEXT(rta
, len
);
1127 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1132 struct rtattr
*parse_rtattr_one(int type
, struct rtattr
*rta
, int len
)
1134 while (RTA_OK(rta
, len
)) {
1135 if (rta
->rta_type
== type
)
1137 rta
= RTA_NEXT(rta
, len
);
1141 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1146 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
,
1150 if (RTA_PAYLOAD(rta
) < len
)
1152 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
1153 rta
= RTA_DATA(rta
) + RTA_ALIGN(len
);
1154 return parse_rtattr_nested(tb
, max
, rta
);
1156 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));