1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Taken & modified from iproute2's libnetlink.c
3 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 #include <sys/socket.h>
12 #include "netlink_helpers.h"
14 static int rcvbuf
= 1024 * 1024;
16 void rtnl_close(struct rtnl_handle
*rth
)
24 int rtnl_open_byproto(struct rtnl_handle
*rth
, unsigned int subscriptions
,
31 memset(rth
, 0, sizeof(*rth
));
32 rth
->proto
= protocol
;
33 rth
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
35 perror("Cannot open netlink socket");
38 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_SNDBUF
,
39 &sndbuf
, sizeof(sndbuf
)) < 0) {
43 if (setsockopt(rth
->fd
, SOL_SOCKET
, SO_RCVBUF
,
44 &rcvbuf
, sizeof(rcvbuf
)) < 0) {
49 /* Older kernels may no support extended ACK reporting */
50 setsockopt(rth
->fd
, SOL_NETLINK
, NETLINK_EXT_ACK
,
53 memset(&rth
->local
, 0, sizeof(rth
->local
));
54 rth
->local
.nl_family
= AF_NETLINK
;
55 rth
->local
.nl_groups
= subscriptions
;
57 if (bind(rth
->fd
, (struct sockaddr
*)&rth
->local
,
58 sizeof(rth
->local
)) < 0) {
59 perror("Cannot bind netlink socket");
62 addr_len
= sizeof(rth
->local
);
63 if (getsockname(rth
->fd
, (struct sockaddr
*)&rth
->local
,
65 perror("Cannot getsockname");
68 if (addr_len
!= sizeof(rth
->local
)) {
69 fprintf(stderr
, "Wrong address length %d\n", addr_len
);
72 if (rth
->local
.nl_family
!= AF_NETLINK
) {
73 fprintf(stderr
, "Wrong address family %d\n",
74 rth
->local
.nl_family
);
77 rth
->seq
= time(NULL
);
84 int rtnl_open(struct rtnl_handle
*rth
, unsigned int subscriptions
)
86 return rtnl_open_byproto(rth
, subscriptions
, NETLINK_ROUTE
);
89 static int __rtnl_recvmsg(int fd
, struct msghdr
*msg
, int flags
)
94 len
= recvmsg(fd
, msg
, flags
);
95 } while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
97 fprintf(stderr
, "netlink receive error %s (%d)\n",
98 strerror(errno
), errno
);
102 fprintf(stderr
, "EOF on netlink\n");
108 static int rtnl_recvmsg(int fd
, struct msghdr
*msg
, char **answer
)
110 struct iovec
*iov
= msg
->msg_iov
;
114 iov
->iov_base
= NULL
;
117 len
= __rtnl_recvmsg(fd
, msg
, MSG_PEEK
| MSG_TRUNC
);
124 fprintf(stderr
, "malloc error: not enough buffer\n");
129 len
= __rtnl_recvmsg(fd
, msg
, 0);
141 static void rtnl_talk_error(struct nlmsghdr
*h
, struct nlmsgerr
*err
,
142 nl_ext_ack_fn_t errfn
)
144 fprintf(stderr
, "RTNETLINK answers: %s\n",
145 strerror(-err
->error
));
148 static int __rtnl_talk_iov(struct rtnl_handle
*rtnl
, struct iovec
*iov
,
149 size_t iovlen
, struct nlmsghdr
**answer
,
150 bool show_rtnl_err
, nl_ext_ack_fn_t errfn
)
152 struct sockaddr_nl nladdr
= { .nl_family
= AF_NETLINK
};
154 struct msghdr msg
= {
156 .msg_namelen
= sizeof(nladdr
),
158 .msg_iovlen
= iovlen
,
160 unsigned int seq
= 0;
165 for (i
= 0; i
< iovlen
; i
++) {
167 h
->nlmsg_seq
= seq
= ++rtnl
->seq
;
169 h
->nlmsg_flags
|= NLM_F_ACK
;
171 status
= sendmsg(rtnl
->fd
, &msg
, 0);
173 perror("Cannot talk to rtnetlink");
176 /* change msg to use the response iov */
182 status
= rtnl_recvmsg(rtnl
->fd
, &msg
, &buf
);
186 if (msg
.msg_namelen
!= sizeof(nladdr
)) {
188 "Sender address length == %d!\n",
192 for (h
= (struct nlmsghdr
*)buf
; status
>= sizeof(*h
); ) {
193 int len
= h
->nlmsg_len
;
194 int l
= len
- sizeof(*h
);
196 if (l
< 0 || len
> status
) {
197 if (msg
.msg_flags
& MSG_TRUNC
) {
198 fprintf(stderr
, "Truncated message!\n");
203 "Malformed message: len=%d!\n",
207 if (nladdr
.nl_pid
!= 0 ||
208 h
->nlmsg_pid
!= rtnl
->local
.nl_pid
||
209 h
->nlmsg_seq
> seq
|| h
->nlmsg_seq
< seq
- iovlen
) {
210 /* Don't forget to skip that message. */
211 status
-= NLMSG_ALIGN(len
);
212 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
215 if (h
->nlmsg_type
== NLMSG_ERROR
) {
216 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(h
);
217 int error
= err
->error
;
219 if (l
< sizeof(struct nlmsgerr
)) {
220 fprintf(stderr
, "ERROR truncated\n");
226 if (rtnl
->proto
!= NETLINK_SOCK_DIAG
&&
228 rtnl_talk_error(h
, err
, errfn
);
239 *answer
= (struct nlmsghdr
*)buf
;
245 *answer
= (struct nlmsghdr
*)buf
;
248 fprintf(stderr
, "Unexpected reply!\n");
249 status
-= NLMSG_ALIGN(len
);
250 h
= (struct nlmsghdr
*)((char *)h
+ NLMSG_ALIGN(len
));
253 if (msg
.msg_flags
& MSG_TRUNC
) {
254 fprintf(stderr
, "Message truncated!\n");
258 fprintf(stderr
, "Remnant of size %d!\n", status
);
264 static int __rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
265 struct nlmsghdr
**answer
, bool show_rtnl_err
,
266 nl_ext_ack_fn_t errfn
)
270 .iov_len
= n
->nlmsg_len
,
273 return __rtnl_talk_iov(rtnl
, &iov
, 1, answer
, show_rtnl_err
, errfn
);
276 int rtnl_talk(struct rtnl_handle
*rtnl
, struct nlmsghdr
*n
,
277 struct nlmsghdr
**answer
)
279 return __rtnl_talk(rtnl
, n
, answer
, true, NULL
);
282 int addattr(struct nlmsghdr
*n
, int maxlen
, int type
)
284 return addattr_l(n
, maxlen
, type
, NULL
, 0);
287 int addattr8(struct nlmsghdr
*n
, int maxlen
, int type
, __u8 data
)
289 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u8
));
292 int addattr16(struct nlmsghdr
*n
, int maxlen
, int type
, __u16 data
)
294 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u16
));
297 int addattr32(struct nlmsghdr
*n
, int maxlen
, int type
, __u32 data
)
299 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u32
));
302 int addattr64(struct nlmsghdr
*n
, int maxlen
, int type
, __u64 data
)
304 return addattr_l(n
, maxlen
, type
, &data
, sizeof(__u64
));
307 int addattrstrz(struct nlmsghdr
*n
, int maxlen
, int type
, const char *str
)
309 return addattr_l(n
, maxlen
, type
, str
, strlen(str
)+1);
312 int addattr_l(struct nlmsghdr
*n
, int maxlen
, int type
, const void *data
,
315 int len
= RTA_LENGTH(alen
);
318 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
) {
319 fprintf(stderr
, "%s: Message exceeded bound of %d\n",
324 rta
->rta_type
= type
;
327 memcpy(RTA_DATA(rta
), data
, alen
);
328 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);
332 int addraw_l(struct nlmsghdr
*n
, int maxlen
, const void *data
, int len
)
334 if (NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
) > maxlen
) {
335 fprintf(stderr
, "%s: Message exceeded bound of %d\n",
340 memcpy(NLMSG_TAIL(n
), data
, len
);
341 memset((void *) NLMSG_TAIL(n
) + len
, 0, NLMSG_ALIGN(len
) - len
);
342 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + NLMSG_ALIGN(len
);
346 struct rtattr
*addattr_nest(struct nlmsghdr
*n
, int maxlen
, int type
)
348 struct rtattr
*nest
= NLMSG_TAIL(n
);
350 addattr_l(n
, maxlen
, type
, NULL
, 0);
354 int addattr_nest_end(struct nlmsghdr
*n
, struct rtattr
*nest
)
356 nest
->rta_len
= (void *)NLMSG_TAIL(n
) - (void *)nest
;