]>
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 size_t nlmsg_len(const struct nlmsg
*nlmsg
)
24 return nlmsg
->nlmsghdr
->nlmsg_len
- NLMSG_HDRLEN
;
27 void *nlmsg_data(struct nlmsg
*nlmsg
)
31 data
= ((char *)nlmsg
) + NLMSG_HDRLEN
;
32 if (!nlmsg_len(nlmsg
))
33 return ret_set_errno(NULL
, EINVAL
);
38 static int nla_put(struct nlmsg
*nlmsg
, int attr
,
39 const void *data
, size_t len
)
42 size_t rtalen
= RTA_LENGTH(len
);
43 size_t tlen
= NLMSG_ALIGN(nlmsg
->nlmsghdr
->nlmsg_len
) + RTA_ALIGN(rtalen
);
45 if (tlen
> nlmsg
->cap
)
46 return ret_errno(ENOMEM
);
48 rta
= NLMSG_TAIL(nlmsg
->nlmsghdr
);
50 rta
->rta_len
= rtalen
;
52 memcpy(RTA_DATA(rta
), data
, len
);
53 nlmsg
->nlmsghdr
->nlmsg_len
= tlen
;
58 int nla_put_buffer(struct nlmsg
*nlmsg
, int attr
, const void *data
, size_t size
)
60 return nla_put(nlmsg
, attr
, data
, size
);
63 int nla_put_string(struct nlmsg
*nlmsg
, int attr
, const char *string
)
65 return nla_put(nlmsg
, attr
, string
, strlen(string
) + 1);
68 int nla_put_u32(struct nlmsg
*nlmsg
, int attr
, int value
)
70 return nla_put(nlmsg
, attr
, &value
, sizeof(value
));
73 int nla_put_u16(struct nlmsg
*nlmsg
, int attr
, unsigned short value
)
75 return nla_put(nlmsg
, attr
, &value
, 2);
78 int nla_put_attr(struct nlmsg
*nlmsg
, int attr
)
80 return nla_put(nlmsg
, attr
, NULL
, 0);
83 struct rtattr
*nla_begin_nested(struct nlmsg
*nlmsg
, int attr
)
85 struct rtattr
*rtattr
;
87 rtattr
= NLMSG_TAIL(nlmsg
->nlmsghdr
);
88 if (nla_put_attr(nlmsg
, attr
))
89 return ret_set_errno(NULL
, ENOMEM
);
94 void nla_end_nested(struct nlmsg
*nlmsg
, struct rtattr
*attr
)
96 attr
->rta_len
= (void *)NLMSG_TAIL(nlmsg
->nlmsghdr
) - (void *)attr
;
99 struct nlmsg
*nlmsg_alloc(size_t size
)
101 __do_free
struct nlmsg
*nlmsg
= NULL
;
102 size_t len
= NLMSG_HDRLEN
+ NLMSG_ALIGN(size
);
104 nlmsg
= malloc(sizeof(struct nlmsg
));
106 return ret_set_errno(NULL
, ENOMEM
);
108 nlmsg
->nlmsghdr
= malloc(len
);
109 if (!nlmsg
->nlmsghdr
)
110 return ret_set_errno(NULL
, ENOMEM
);
112 memset(nlmsg
->nlmsghdr
, 0, len
);
114 nlmsg
->nlmsghdr
->nlmsg_len
= NLMSG_HDRLEN
;
116 return move_ptr(nlmsg
);
119 void *nlmsg_reserve(struct nlmsg
*nlmsg
, size_t len
)
122 size_t nlmsg_len
= nlmsg
->nlmsghdr
->nlmsg_len
;
123 size_t tlen
= NLMSG_ALIGN(len
);
125 if (nlmsg_len
+ tlen
> nlmsg
->cap
)
126 return ret_set_errno(NULL
, ENOMEM
);
128 buf
= ((char *)(nlmsg
->nlmsghdr
)) + nlmsg_len
;
129 nlmsg
->nlmsghdr
->nlmsg_len
+= tlen
;
132 memset(buf
+ len
, 0, tlen
- len
);
137 struct nlmsg
*nlmsg_alloc_reserve(size_t size
)
141 nlmsg
= nlmsg_alloc(size
);
143 return ret_set_errno(NULL
, ENOMEM
);
145 /* Just set message length to cap directly. */
146 nlmsg
->nlmsghdr
->nlmsg_len
= nlmsg
->cap
;
150 void nlmsg_free(struct nlmsg
*nlmsg
)
153 free(nlmsg
->nlmsghdr
);
158 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);
185 return ret_errno(errno
);
191 if (msg
.msg_flags
& MSG_TRUNC
&& (ret
== nlmsghdr
->nlmsg_len
))
192 return ret_errno(EMSGSIZE
);
197 int netlink_rcv(struct nl_handler
*handler
, struct nlmsg
*answer
)
199 return __netlink_recv(handler
, answer
->nlmsghdr
);
202 int __netlink_send(struct nl_handler
*handler
, struct nlmsghdr
*nlmsghdr
)
205 struct sockaddr_nl nladdr
;
207 .iov_base
= nlmsghdr
,
208 .iov_len
= nlmsghdr
->nlmsg_len
,
210 struct msghdr msg
= {
212 .msg_namelen
= sizeof(nladdr
),
217 memset(&nladdr
, 0, sizeof(nladdr
));
218 nladdr
.nl_family
= AF_NETLINK
;
220 nladdr
.nl_groups
= 0;
222 ret
= sendmsg(handler
->fd
, &msg
, MSG_NOSIGNAL
);
224 return ret_errno(errno
);
229 extern int netlink_send(struct nl_handler
*handler
, struct nlmsg
*nlmsg
)
231 return __netlink_send(handler
, nlmsg
->nlmsghdr
);
234 extern int __netlink_transaction(struct nl_handler
*handler
,
235 struct nlmsghdr
*request
,
236 struct nlmsghdr
*answer
)
240 ret
= __netlink_send(handler
, request
);
244 ret
= __netlink_recv(handler
, answer
);
248 if (answer
->nlmsg_type
== NLMSG_ERROR
) {
249 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(answer
);
251 return ret_errno(-err
->error
);
257 extern int netlink_transaction(struct nl_handler
*handler
,
258 struct nlmsg
*request
, struct nlmsg
*answer
)
260 return __netlink_transaction(handler
, request
->nlmsghdr
,
264 extern int netlink_open(struct nl_handler
*handler
, int protocol
)
266 __do_close
int fd
= -EBADF
;
271 memset(handler
, 0, sizeof(*handler
));
272 handler
->fd
= -EBADF
;
274 fd
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, protocol
);
276 return ret_errno(errno
);
278 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &sndbuf
, sizeof(sndbuf
)) < 0)
279 return ret_errno(errno
);
281 if (setsockopt(fd
, SOL_SOCKET
, SO_RCVBUF
, &rcvbuf
,sizeof(rcvbuf
)) < 0)
282 return ret_errno(errno
);
284 memset(&handler
->local
, 0, sizeof(handler
->local
));
285 handler
->local
.nl_family
= AF_NETLINK
;
286 handler
->local
.nl_groups
= 0;
288 if (bind(fd
, (struct sockaddr
*)&handler
->local
, sizeof(handler
->local
)) < 0)
289 return ret_errno(errno
);
291 socklen
= sizeof(handler
->local
);
292 if (getsockname(fd
, (struct sockaddr
*)&handler
->local
, &socklen
) < 0)
293 return ret_errno(errno
);
295 if (socklen
!= sizeof(handler
->local
))
296 return ret_errno(EINVAL
);
298 if (handler
->local
.nl_family
!= AF_NETLINK
)
299 return ret_errno(EINVAL
);
301 handler
->seq
= time(NULL
);
302 handler
->fd
= move_fd(fd
);
306 extern void netlink_close(struct nl_handler
*handler
)
308 close_prot_errno_disarm(handler
->fd
);
311 int addattr(struct nlmsghdr
*n
, size_t maxlen
, int type
, const void *data
,
314 int len
= RTA_LENGTH(alen
);
317 if (NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
) > maxlen
)
318 return ret_errno(EMSGSIZE
);
321 rta
->rta_type
= type
;
324 memcpy(RTA_DATA(rta
), data
, alen
);
325 n
->nlmsg_len
= NLMSG_ALIGN(n
->nlmsg_len
) + RTA_ALIGN(len
);