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>
19 #include <net/if_arp.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
27 #include "libnetlink.h"
30 #define SOL_NETLINK 270
34 #define MIN(a, b) ((a) < (b) ? (a) : (b))
37 int rcvbuf
= 1024 * 1024;
40 #include <libmnl/libmnl.h>
42 static const enum mnl_attr_data_type extack_policy
[NLMSGERR_ATTR_MAX
+ 1] = {
43 [NLMSGERR_ATTR_MSG
] = MNL_TYPE_NUL_STRING
,
44 [NLMSGERR_ATTR_OFFS
] = MNL_TYPE_U32
,
47 static int err_attr_cb(const struct nlattr
*attr
, void *data
)
49 const struct nlattr
**tb
= data
;
52 if (mnl_attr_type_valid(attr
, NLMSGERR_ATTR_MAX
) < 0)
55 type
= mnl_attr_get_type(attr
);
56 if (mnl_attr_validate(attr
, extack_policy
[type
]) < 0)
64 /* dump netlink extended ack error message */
65 static int nl_dump_ext_err(const struct nlmsghdr
*nlh
, nl_ext_ack_fn_t errfn
)
67 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1];
68 const struct nlmsgerr
*err
= mnl_nlmsg_get_payload(nlh
);
69 const struct nlmsghdr
*err_nlh
= NULL
;
70 unsigned int hlen
= sizeof(*err
);
71 const char *errmsg
= NULL
;
74 /* no TLVs, nothing to do here */
75 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
78 /* if NLM_F_CAPPED is set then the inner err msg was capped */
79 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
80 hlen
+= mnl_nlmsg_get_payload_len(&err
->msg
);
82 mnl_attr_parse(nlh
, hlen
, err_attr_cb
, tb
);
84 if (tb
[NLMSGERR_ATTR_MSG
])
85 errmsg
= mnl_attr_get_str(tb
[NLMSGERR_ATTR_MSG
]);
87 if (tb
[NLMSGERR_ATTR_OFFS
]) {
88 off
= mnl_attr_get_u32(tb
[NLMSGERR_ATTR_OFFS
]);
90 if (off
> nlh
->nlmsg_len
) {
92 "Invalid offset for NLMSGERR_ATTR_OFFS\n");
94 } else if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
99 return errfn(errmsg
, off
, err_nlh
);
101 if (errmsg
&& *errmsg
!= '\0') {
102 fprintf(stderr
, "Error: %s", errmsg
);
103 if (errmsg
[strlen(errmsg
) - 1] != '.')
104 fprintf(stderr
, ".");
105 fprintf(stderr
, "\n");
113 #warning "libmnl required for error support"
115 /* No extended error ack without libmnl */
116 static int nl_dump_ext_err(const struct nlmsghdr
*nlh
, nl_ext_ack_fn_t errfn
)
122 void rtnl_close(struct rtnl_handle
*rth
)
130 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned int subscriptions
,
137 memset(rth
, 0, sizeof(*rth
));
139 rth
->proto
= protocol
;
140 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
142 perror("Cannot open netlink socket");
146 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
,
147 &sndbuf
, sizeof(sndbuf
)) < 0) {
152 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
,
153 &rcvbuf
, sizeof(rcvbuf
)) < 0) {
158 /* Older kernels may no support extended ACK reporting */
159 setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_EXT_ACK
,
162 memset(&rth
->local
, 0, sizeof(rth
->local
));
163 rth
->local
.nl_family
= AF_NETLINK
;
164 rth
->local
.nl_groups
= subscriptions
;
166 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
,
167 sizeof(rth
->local
)) < 0) {
168 perror("Cannot bind netlink socket");
171 addr_len
= sizeof(rth
->local
);
172 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
,
174 perror("Cannot getsockname");
177 if (addr_len
!= sizeof(rth
->local
)) {
178 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
181 if (rth
->local
.nl_family
!= AF_NETLINK
) {
182 fprintf(stderr
, "Wrong address family %d\n",
183 rth
->local
.nl_family
);
186 rth
->seq
= time(NULL
);
190 int rtnl_open(struct rtnl_handle
*rth
, unsigned int subscriptions
)
192 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
195 int rtnl_wilddump_request(struct rtnl_handle
*rth
, int family
, int type
)
197 return rtnl_wilddump_req_filter(rth
, family
, type
, RTEXT_FILTER_VF
);
200 int rtnl_wilddump_req_filter(struct rtnl_handle
*rth
, int family
, int type
,
205 struct ifinfomsg ifm
;
206 /* attribute has to be NLMSG aligned */
207 struct rtattr ext_req
__attribute__ ((aligned(NLMSG_ALIGNTO
)));
208 __u32 ext_filter_mask
;
210 .nlh
.nlmsg_len
= sizeof(req
),
211 .nlh
.nlmsg_type
= type
,
212 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
213 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
214 .ifm
.ifi_family
= family
,
215 .ext_req
.rta_type
= IFLA_EXT_MASK
,
216 .ext_req
.rta_len
= RTA_LENGTH(sizeof(__u32
)),
217 .ext_filter_mask
= filt_mask
,
220 return send(rth
->fd
, &req
, sizeof(req
), 0);
223 int rtnl_wilddump_req_filter_fn(struct rtnl_handle
*rth
, int family
, int type
,
224 req_filter_fn_t filter_fn
)
228 struct ifinfomsg ifm
;
231 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
232 .nlh
.nlmsg_type
= type
,
233 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
234 .nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
,
235 .ifm
.ifi_family
= family
,
242 err
= filter_fn(&req
.nlh
, sizeof(req
));
246 return send(rth
->fd
, &req
, req
.nlh
.nlmsg_len
, 0);
249 int rtnl_wilddump_stats_req_filter(struct rtnl_handle
*rth
, int fam
, int type
,
254 struct if_stats_msg ifsm
;
257 memset(&req
, 0, sizeof(req
));
258 req
.nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct if_stats_msg
));
259 req
.nlh
.nlmsg_type
= type
;
260 req
.nlh
.nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
261 req
.nlh
.nlmsg_pid
= 0;
262 req
.nlh
.nlmsg_seq
= rth
->dump
= ++rth
->seq
;
263 req
.ifsm
.family
= fam
;
264 req
.ifsm
.filter_mask
= filt_mask
;
266 return send(rth
->fd
, &req
, sizeof(req
), 0);
269 int rtnl_send(struct rtnl_handle
*rth
, const void *buf
, int len
)
271 return send(rth
->fd
, buf
, len
, 0);
274 int rtnl_send_check(struct rtnl_handle
*rth
, const void *buf
, int len
)
280 status
= send(rth
->fd
, buf
, len
, 0);
284 /* Check for immediate errors */
285 status
= recv(rth
->fd
, resp
, sizeof(resp
), MSG_DONTWAIT
|MSG_PEEK
);
292 for (h
= (struct nlmsghdr
*)resp
; NLMSG_OK(h
, status
);
293 h
= NLMSG_NEXT(h
, status
)) {
294 if (h
->nlmsg_type
== NLMSG_ERROR
) {
295 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
297 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
298 fprintf(stderr
, "ERROR truncated\n");
308 int rtnl_dump_request(struct rtnl_handle
*rth
, int type
, void *req
, int len
)
310 struct nlmsghdr nlh
= {
311 .nlmsg_len
= NLMSG_LENGTH(len
),
313 .nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
314 .nlmsg_seq
= rth
->dump
= ++rth
->seq
,
316 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
317 struct iovec iov
[2] = {
318 { .iov_base
= &nlh
, .iov_len
= sizeof(nlh
) },
319 { .iov_base
= req
, .iov_len
= len
}
321 struct msghdr msg
= {
323 .msg_namelen
= sizeof(nladdr
),
328 return sendmsg(rth
->fd
, &msg
, 0);
331 int rtnl_dump_request_n(struct rtnl_handle
*rth
, struct nlmsghdr
*n
)
333 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
336 .iov_len
= n
->nlmsg_len
338 struct msghdr msg
= {
340 .msg_namelen
= sizeof(nladdr
),
345 n
->nlmsg_flags
= NLM_F_DUMP
|NLM_F_REQUEST
;
347 n
->nlmsg_seq
= rth
->dump
= ++rth
->seq
;
349 return sendmsg(rth
->fd
, &msg
, 0);
352 static int rtnl_dump_done(const struct rtnl_handle
*rth
,
355 int len
= *(int *)NLMSG_DATA(h
);
357 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(int))) {
358 fprintf(stderr
, "DONE truncated\n");
370 "Error: Buffer too small for object.\n");
373 perror("RTNETLINK answers");
381 static void rtnl_dump_error(const struct rtnl_handle
*rth
,
385 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
))) {
386 fprintf(stderr
, "ERROR truncated\n");
388 const struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
391 if (rth
->proto
== NETLINK_SOCK_DIAG
&&
393 errno
== EOPNOTSUPP
))
396 if (!(rth
->flags
& RTNL_HANDLE_F_SUPPRESS_NLERR
))
397 perror("RTNETLINK answers");
401 int rtnl_dump_filter_l(struct rtnl_handle
*rth
,
402 const struct rtnl_dump_filter_arg
*arg
)
404 struct sockaddr_nl nladdr
;
406 struct msghdr msg
= {
408 .msg_namelen
= sizeof(nladdr
),
418 const struct rtnl_dump_filter_arg
*a
;
422 iov
.iov_len
= sizeof(buf
);
423 status
= recvmsg(rth
->fd
, &msg
, 0);
426 if (errno
== EINTR
|| errno
== EAGAIN
)
428 fprintf(stderr
, "netlink receive error %s (%d)\n",
429 strerror(errno
), errno
);
434 fprintf(stderr
, "EOF on netlink\n");
439 fwrite(buf
, 1, NLMSG_ALIGN(status
), rth
->dump_fp
);
441 for (a
= arg
; a
->filter
; a
++) {
442 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
446 while (NLMSG_OK(h
, msglen
)) {
449 h
->nlmsg_flags
&= ~a
->nc_flags
;
451 if (nladdr
.nl_pid
!= 0 ||
452 h
->nlmsg_pid
!= rth
->local
.nl_pid
||
453 h
->nlmsg_seq
!= rth
->dump
)
456 if (h
->nlmsg_flags
& NLM_F_DUMP_INTR
)
459 if (h
->nlmsg_type
== NLMSG_DONE
) {
460 err
= rtnl_dump_done(rth
, h
);
465 break; /* process next filter */
468 if (h
->nlmsg_type
== NLMSG_ERROR
) {
469 rtnl_dump_error(rth
, h
);
474 err
= a
->filter(&nladdr
, h
, a
->arg1
);
480 h
= NLMSG_NEXT(h
, msglen
);
487 "Dump was interrupted and may be inconsistent.\n");
491 if (msg
.msg_flags
& MSG_TRUNC
) {
492 fprintf(stderr
, "Message truncated\n");
496 fprintf(stderr
, "!!!Remnant of size %d\n", msglen
);
502 int rtnl_dump_filter_nc(struct rtnl_handle
*rth
,
503 rtnl_filter_t filter
,
504 void *arg1
, __u16 nc_flags
)
506 const struct rtnl_dump_filter_arg a
[2] = {
507 { .filter
= filter
, .arg1
= arg1
, .nc_flags
= nc_flags
, },
508 { .filter
= NULL
, .arg1
= NULL
, .nc_flags
= 0, },
511 return rtnl_dump_filter_l(rth
, a
);
514 static void rtnl_talk_error(struct nlmsghdr
*h
, struct nlmsgerr
*err
,
515 nl_ext_ack_fn_t errfn
)
517 if (nl_dump_ext_err(h
, errfn
))
520 fprintf(stderr
, "RTNETLINK answers: %s\n",
521 strerror(-err
->error
));
524 static int __rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
525 struct nlmsghdr
*answer
, size_t maxlen
,
526 bool show_rtnl_err
, nl_ext_ack_fn_t errfn
)
531 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
534 .iov_len
= n
->nlmsg_len
536 struct msghdr msg
= {
538 .msg_namelen
= sizeof(nladdr
),
542 char buf
[32768] = {};
544 n
->nlmsg_seq
= seq
= ++rtnl
->seq
;
547 n
->nlmsg_flags
|= NLM_F_ACK
;
549 status
= sendmsg(rtnl
->fd
, &msg
, 0);
551 perror("Cannot talk to rtnetlink");
557 iov
.iov_len
= sizeof(buf
);
558 status
= recvmsg(rtnl
->fd
, &msg
, 0);
561 if (errno
== EINTR
|| errno
== EAGAIN
)
563 fprintf(stderr
, "netlink receive error %s (%d)\n",
564 strerror(errno
), errno
);
568 fprintf(stderr
, "EOF on netlink\n");
571 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
573 "sender address length == %d\n",
577 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
578 int len
= h
->nlmsg_len
;
579 int l
= len
- sizeof(*h
);
581 if (l
< 0 || len
> status
) {
582 if (msg
.msg_flags
& MSG_TRUNC
) {
583 fprintf(stderr
, "Truncated message\n");
587 "!!!malformed message: len=%d\n",
592 if (nladdr
.nl_pid
!= 0 ||
593 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
594 h
->nlmsg_seq
!= seq
) {
595 /* Don't forget to skip that message. */
596 status
-= NLMSG_ALIGN(len
);
597 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
601 if (h
->nlmsg_type
== NLMSG_ERROR
) {
602 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
604 if (l
< sizeof(struct nlmsgerr
)) {
605 fprintf(stderr
, "ERROR truncated\n");
606 } else if (!err
->error
) {
609 MIN(maxlen
, h
->nlmsg_len
));
613 if (rtnl
->proto
!= NETLINK_SOCK_DIAG
&&
615 rtnl_talk_error(h
, err
, errfn
);
623 MIN(maxlen
, h
->nlmsg_len
));
627 fprintf(stderr
, "Unexpected reply!!!\n");
629 status
-= NLMSG_ALIGN(len
);
630 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
633 if (msg
.msg_flags
& MSG_TRUNC
) {
634 fprintf(stderr
, "Message truncated\n");
639 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
645 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
646 struct nlmsghdr
*answer
, size_t maxlen
)
648 return __rtnl_talk(rtnl
, n
, answer
, maxlen
, true, NULL
);
651 int rtnl_talk_extack(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
652 struct nlmsghdr
*answer
, size_t maxlen
,
653 nl_ext_ack_fn_t errfn
)
655 return __rtnl_talk(rtnl
, n
, answer
, maxlen
, true, errfn
);
658 int rtnl_talk_suppress_rtnl_errmsg(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
659 struct nlmsghdr
*answer
, size_t maxlen
)
661 return __rtnl_talk(rtnl
, n
, answer
, maxlen
, false, NULL
);
664 int rtnl_listen_all_nsid(struct rtnl_handle
*rth
)
668 if (setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_LISTEN_ALL_NSID
, &on
,
670 perror("NETLINK_LISTEN_ALL_NSID");
673 rth
->flags
|= RTNL_HANDLE_F_LISTEN_ALL_NSID
;
677 int rtnl_listen(struct rtnl_handle
*rtnl
,
678 rtnl_listen_filter_t handler
,
683 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
685 struct msghdr msg
= {
687 .msg_namelen
= sizeof(nladdr
),
692 char cmsgbuf
[BUFSIZ
];
694 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
695 msg
.msg_control
= &cmsgbuf
;
696 msg
.msg_controllen
= sizeof(cmsgbuf
);
701 struct rtnl_ctrl_data ctrl
;
702 struct cmsghdr
*cmsg
;
704 iov
.iov_len
= sizeof(buf
);
705 status
= recvmsg(rtnl
->fd
, &msg
, 0);
708 if (errno
== EINTR
|| errno
== EAGAIN
)
710 fprintf(stderr
, "netlink receive error %s (%d)\n",
711 strerror(errno
), errno
);
712 if (errno
== ENOBUFS
)
717 fprintf(stderr
, "EOF on netlink\n");
720 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
722 "Sender address length == %d\n",
727 if (rtnl
->flags
& RTNL_HANDLE_F_LISTEN_ALL_NSID
) {
728 memset(&ctrl
, 0, sizeof(ctrl
));
730 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
;
731 cmsg
= CMSG_NXTHDR(&msg
, cmsg
))
732 if (cmsg
->cmsg_level
== SOL_NETLINK
&&
733 cmsg
->cmsg_type
== NETLINK_LISTEN_ALL_NSID
&&
734 cmsg
->cmsg_len
== CMSG_LEN(sizeof(int))) {
735 int *data
= (int *)CMSG_DATA(cmsg
);
741 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
743 int len
= h
->nlmsg_len
;
744 int l
= len
- sizeof(*h
);
746 if (l
< 0 || len
> status
) {
747 if (msg
.msg_flags
& MSG_TRUNC
) {
748 fprintf(stderr
, "Truncated message\n");
752 "!!!malformed message: len=%d\n",
757 err
= handler(&nladdr
, &ctrl
, h
, jarg
);
761 status
-= NLMSG_ALIGN(len
);
762 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
764 if (msg
.msg_flags
& MSG_TRUNC
) {
765 fprintf(stderr
, "Message truncated\n");
769 fprintf(stderr
, "!!!Remnant of size %d\n", status
);
775 int rtnl_from_file(FILE *rtnl
, rtnl_listen_filter_t handler
,
779 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
781 struct nlmsghdr
*h
= (struct nlmsghdr
*)buf
;
787 status
= fread(&buf
, 1, sizeof(*h
), rtnl
);
792 perror("rtnl_from_file: fread");
799 l
= len
- sizeof(*h
);
801 if (l
< 0 || len
> sizeof(buf
)) {
802 fprintf(stderr
, "!!!malformed message: len=%d @%lu\n",
807 status
= fread(NLMSG_DATA(h
), 1, NLMSG_ALIGN(l
), rtnl
);
810 perror("rtnl_from_file: fread");
814 fprintf(stderr
, "rtnl-from_file: truncated message\n");
818 err
= handler(&nladdr
, NULL
, h
, jarg
);
824 int addattr(struct nlmsghdr
*n
, int maxlen
, int type
)
826 return addattr_l(n
, maxlen
, type
, NULL
, 0);
829 int addattr8(struct nlmsghdr
*n
, int maxlen
, int type
, __u8 data
)
831 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u8
));
834 int addattr16(struct nlmsghdr
*n
, int maxlen
, int type
, __u16 data
)
836 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u16
));
839 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
841 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u32
));
844 int addattr64(struct nlmsghdr
*n
, int maxlen
, int type
, __u64 data
)
846 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u64
));
849 int addattrstrz(struct nlmsghdr
*n
, int maxlen
, int type
, const char *str
)
851 return addattr_l(n
, maxlen
, type
, str
, strlen(str
)+1);
854 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
857 int len
= RTA_LENGTH(alen
);
860 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
862 "addattr_l ERROR: message exceeded bound of %d\n",
867 rta
->rta_type
= type
;
869 memcpy(RTA_DATA(rta
), data
, alen
);
870 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
874 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
876 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
878 "addraw_l ERROR: message exceeded bound of %d\n",
883 memcpy(NLMSG_TAIL(n
), data
, len
);
884 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
885 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
889 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
891 struct rtattr
*nest
= NLMSG_TAIL(n
);
893 addattr_l(n
, maxlen
, type
, NULL
, 0);
897 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
899 nest
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)nest
;
903 struct rtattr
*addattr_nest_compat(struct nlmsghdr
*n
, int maxlen
, int type
,
904 const void *data
, int len
)
906 struct rtattr
*start
= NLMSG_TAIL(n
);
908 addattr_l(n
, maxlen
, type
, data
, len
);
909 addattr_nest(n
, maxlen
, type
);
913 int addattr_nest_compat_end(struct nlmsghdr
*n
, struct rtattr
*start
)
915 struct rtattr
*nest
= (void *)start
+ NLMSG_ALIGN(start
->rta_len
);
917 start
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)start
;
918 addattr_nest_end(n
, nest
);
922 int rta_addattr32(struct rtattr
*rta
, int maxlen
, int type
, __u32 data
)
924 int len
= RTA_LENGTH(4);
925 struct rtattr
*subrta
;
927 if (RTA_ALIGN(rta
->rta_len
) + len
> maxlen
) {
929 "rta_addattr32: Error! max allowed bound %d exceeded\n",
933 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
934 subrta
->rta_type
= type
;
935 subrta
->rta_len
= len
;
936 memcpy(RTA_DATA(subrta
), &data
, 4);
937 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + len
;
941 int rta_addattr_l(struct rtattr
*rta
, int maxlen
, int type
,
942 const void *data
, int alen
)
944 struct rtattr
*subrta
;
945 int len
= RTA_LENGTH(alen
);
947 if (RTA_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
) > maxlen
) {
949 "rta_addattr_l: Error! max allowed bound %d exceeded\n",
953 subrta
= (struct rtattr
*)(((char *)rta
) + RTA_ALIGN(rta
->rta_len
));
954 subrta
->rta_type
= type
;
955 subrta
->rta_len
= len
;
956 memcpy(RTA_DATA(subrta
), data
, alen
);
957 rta
->rta_len
= NLMSG_ALIGN(rta
->rta_len
) + RTA_ALIGN(len
);
961 int rta_addattr8(struct rtattr
*rta
, int maxlen
, int type
, __u8 data
)
963 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u8
));
966 int rta_addattr16(struct rtattr
*rta
, int maxlen
, int type
, __u16 data
)
968 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u16
));
971 int rta_addattr64(struct rtattr
*rta
, int maxlen
, int type
, __u64 data
)
973 return rta_addattr_l(rta
, maxlen
, type
, &data
, sizeof(__u64
));
976 struct rtattr
*rta_nest(struct rtattr
*rta
, int maxlen
, int type
)
978 struct rtattr
*nest
= RTA_TAIL(rta
);
980 rta_addattr_l(rta
, maxlen
, type
, NULL
, 0);
985 int rta_nest_end(struct rtattr
*rta
, struct rtattr
*nest
)
987 nest
->rta_len
= (void *)RTA_TAIL(rta
) - (void *)nest
;
992 int parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
994 return parse_rtattr_flags(tb
, max
, rta
, len
, 0);
997 int parse_rtattr_flags(struct rtattr
*tb
[], int max
, struct rtattr
*rta
,
998 int len
, unsigned short flags
)
1000 unsigned short type
;
1002 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));
1003 while (RTA_OK(rta
, len
)) {
1004 type
= rta
->rta_type
& ~flags
;
1005 if ((type
<= max
) && (!tb
[type
]))
1007 rta
= RTA_NEXT(rta
, len
);
1010 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1015 int parse_rtattr_byindex(struct rtattr
*tb
[], int max
,
1016 struct rtattr
*rta
, int len
)
1020 memset(tb
, 0, sizeof(struct rtattr
*) * max
);
1021 while (RTA_OK(rta
, len
)) {
1022 if (rta
->rta_type
<= max
&& i
< max
)
1024 rta
= RTA_NEXT(rta
, len
);
1027 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1032 struct rtattr
*parse_rtattr_one(int type
, struct rtattr
*rta
, int len
)
1034 while (RTA_OK(rta
, len
)) {
1035 if (rta
->rta_type
== type
)
1037 rta
= RTA_NEXT(rta
, len
);
1041 fprintf(stderr
, "!!!Deficit %d, rta_len=%d\n",
1046 int __parse_rtattr_nested_compat(struct rtattr
*tb
[], int max
,
1050 if (RTA_PAYLOAD(rta
) < len
)
1052 if (RTA_PAYLOAD(rta
) >= RTA_ALIGN(len
) + sizeof(struct rtattr
)) {
1053 rta
= RTA_DATA(rta
) + RTA_ALIGN(len
);
1054 return parse_rtattr_nested(tb
, max
, rta
);
1056 memset(tb
, 0, sizeof(struct rtattr
*) * (max
+ 1));