]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/nl.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
7 #include <linux/netlink.h>
8 #include <linux/rtnetlink.h>
12 #include <sys/socket.h>
20 lxc_log_define(nl
, lxc
);
22 extern size_t nlmsg_len(const struct nlmsg
*nlmsg
)
24 return nlmsg
->nlmsghdr
->nlmsg_len
- NLMSG_HDRLEN
;
27 extern void *nlmsg_data(struct nlmsg
*nlmsg
)
29 char *data
= ((char *)nlmsg
) + NLMSG_HDRLEN
;
30 if (!nlmsg_len(nlmsg
))
35 static int nla_put(struct nlmsg
*nlmsg
, int attr
,
36 const void *data
, size_t len
)
39 size_t rtalen
= RTA_LENGTH(len
);
40 size_t tlen
= NLMSG_ALIGN(nlmsg
->nlmsghdr
->nlmsg_len
) + RTA_ALIGN(rtalen
);
42 if (tlen
> nlmsg
->cap
)
45 rta
= NLMSG_TAIL(nlmsg
->nlmsghdr
);
47 rta
->rta_len
= rtalen
;
49 memcpy(RTA_DATA(rta
), data
, len
);
50 nlmsg
->nlmsghdr
->nlmsg_len
= tlen
;
54 extern int nla_put_buffer(struct nlmsg
*nlmsg
, int attr
,
55 const void *data
, size_t size
)
57 return nla_put(nlmsg
, attr
, data
, size
);
60 extern int nla_put_string(struct nlmsg
*nlmsg
, int attr
, const char *string
)
62 return nla_put(nlmsg
, attr
, string
, strlen(string
) + 1);
65 extern int nla_put_u32(struct nlmsg
*nlmsg
, int attr
, int value
)
67 return nla_put(nlmsg
, attr
, &value
, sizeof(value
));
70 extern int nla_put_u16(struct nlmsg
*nlmsg
, int attr
, unsigned short value
)
72 return nla_put(nlmsg
, attr
, &value
, 2);
75 extern int nla_put_attr(struct nlmsg
*nlmsg
, int attr
)
77 return nla_put(nlmsg
, attr
, NULL
, 0);
80 struct rtattr
*nla_begin_nested(struct nlmsg
*nlmsg
, int attr
)
82 struct rtattr
*rtattr
= NLMSG_TAIL(nlmsg
->nlmsghdr
);
84 if (nla_put_attr(nlmsg
, attr
))
90 void nla_end_nested(struct nlmsg
*nlmsg
, struct rtattr
*attr
)
92 attr
->rta_len
= (void *)NLMSG_TAIL(nlmsg
->nlmsghdr
) - (void *)attr
;
95 extern struct nlmsg
*nlmsg_alloc(size_t size
)
98 size_t len
= NLMSG_HDRLEN
+ NLMSG_ALIGN(size
);
100 nlmsg
= (struct nlmsg
*)malloc(sizeof(struct nlmsg
));
104 nlmsg
->nlmsghdr
= (struct nlmsghdr
*)malloc(len
);
105 if (!nlmsg
->nlmsghdr
)
108 memset(nlmsg
->nlmsghdr
, 0, len
);
110 nlmsg
->nlmsghdr
->nlmsg_len
= NLMSG_HDRLEN
;
118 extern void *nlmsg_reserve(struct nlmsg
*nlmsg
, size_t len
)
121 size_t nlmsg_len
= nlmsg
->nlmsghdr
->nlmsg_len
;
122 size_t tlen
= NLMSG_ALIGN(len
);
124 if (nlmsg_len
+ tlen
> nlmsg
->cap
)
127 buf
= ((char *)(nlmsg
->nlmsghdr
)) + nlmsg_len
;
128 nlmsg
->nlmsghdr
->nlmsg_len
+= tlen
;
131 memset(buf
+ len
, 0, tlen
- len
);
136 extern struct nlmsg
*nlmsg_alloc_reserve(size_t size
)
140 nlmsg
= nlmsg_alloc(size
);
144 /* Just set message length to cap directly. */
145 nlmsg
->nlmsghdr
->nlmsg_len
= nlmsg
->cap
;
149 extern void nlmsg_free(struct nlmsg
*nlmsg
)
154 free(nlmsg
->nlmsghdr
);
158 extern int __netlink_recv(struct nl_handler
*handler
, struct nlmsghdr
*nlmsghdr
)
161 struct sockaddr_nl nladdr
;
163 .iov_base
= nlmsghdr
,
164 .iov_len
= nlmsghdr
->nlmsg_len
,
167 struct msghdr msg
= {
169 .msg_namelen
= sizeof(nladdr
),
174 memset(&nladdr
, 0, sizeof(nladdr
));
175 nladdr
.nl_family
= AF_NETLINK
;
177 nladdr
.nl_groups
= 0;
180 ret
= recvmsg(handler
->fd
, &msg
, 0);
191 if (msg
.msg_flags
& MSG_TRUNC
&& (ret
== nlmsghdr
->nlmsg_len
)) {
199 extern int netlink_rcv(struct nl_handler
*handler
, struct nlmsg
*answer
)
201 return __netlink_recv(handler
, answer
->nlmsghdr
);
204 extern int __netlink_send(struct nl_handler
*handler
, struct nlmsghdr
*nlmsghdr
)
207 struct sockaddr_nl nladdr
;
209 .iov_base
= nlmsghdr
,
210 .iov_len
= nlmsghdr
->nlmsg_len
,
212 struct msghdr msg
= {
214 .msg_namelen
= sizeof(nladdr
),
219 memset(&nladdr
, 0, sizeof(nladdr
));
220 nladdr
.nl_family
= AF_NETLINK
;
222 nladdr
.nl_groups
= 0;
224 ret
= sendmsg(handler
->fd
, &msg
, MSG_NOSIGNAL
);
231 extern int netlink_send(struct nl_handler
*handler
, struct nlmsg
*nlmsg
)
233 return __netlink_send(handler
, nlmsg
->nlmsghdr
);
236 extern int __netlink_transaction(struct nl_handler
*handler
,
237 struct nlmsghdr
*request
,
238 struct nlmsghdr
*answer
)
242 ret
= __netlink_send(handler
, request
);
246 ret
= __netlink_recv(handler
, answer
);
251 if (answer
->nlmsg_type
== NLMSG_ERROR
) {
252 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(answer
);
261 extern int netlink_transaction(struct nl_handler
*handler
,
262 struct nlmsg
*request
, struct nlmsg
*answer
)
264 return __netlink_transaction(handler
, request
->nlmsghdr
,
268 extern int netlink_open(struct nl_handler
*handler
, int protocol
)
275 memset(handler
, 0, sizeof(*handler
));
277 handler
->fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
281 if (setsockopt(handler
->fd
, SOL_SOCKET
, SO_SNDBUF
,
282 &sndbuf
, sizeof(sndbuf
)) < 0)
285 if (setsockopt(handler
->fd
, SOL_SOCKET
, SO_RCVBUF
,
286 &rcvbuf
,sizeof(rcvbuf
)) < 0)
289 memset(&handler
->local
, 0, sizeof(handler
->local
));
290 handler
->local
.nl_family
= AF_NETLINK
;
291 handler
->local
.nl_groups
= 0;
293 if (bind(handler
->fd
, (struct sockaddr
*)&handler
->local
,
294 sizeof(handler
->local
)) < 0)
297 socklen
= sizeof(handler
->local
);
298 if (getsockname(handler
->fd
, (struct sockaddr
*)&handler
->local
,
302 if (socklen
!= sizeof(handler
->local
)) {
307 if (handler
->local
.nl_family
!= AF_NETLINK
) {
312 handler
->seq
= time(NULL
);
322 extern int netlink_close(struct nl_handler
*handler
)
329 int addattr(struct nlmsghdr
*n
, size_t maxlen
, int type
, const void *data
,
332 int len
= RTA_LENGTH(alen
);
336 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
)
340 rta
->rta_type
= type
;
343 memcpy(RTA_DATA(rta
), data
, alen
);
344 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);