]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/nl.c
Merge pull request #4236 from mihalicyn/github_check_fixes
[mirror_lxc.git] / src / lxc / nl.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
bfcedc7e 2
1160ce89
CB
3#include "config.h"
4
0ad19a3f 5#include <errno.h>
0ad19a3f 6#include <linux/netlink.h>
7#include <linux/rtnetlink.h>
d38dd64a
CB
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/socket.h>
12#include <time.h>
13#include <unistd.h>
f549edcc 14
bfcedc7e 15#include "log.h"
f549edcc 16#include "nl.h"
0ad19a3f 17
bfcedc7e
CB
18lxc_log_define(nl, lxc);
19
6822ba9b 20static size_t nlmsg_len(const struct nlmsg *nlmsg)
0ad19a3f 21{
06f976ca 22 return nlmsg->nlmsghdr->nlmsg_len - NLMSG_HDRLEN;
0ad19a3f 23}
24
19bfd55a 25void *nlmsg_data(struct nlmsg *nlmsg)
0ad19a3f 26{
19bfd55a
CB
27 char *data;
28
29 data = ((char *)nlmsg) + NLMSG_HDRLEN;
0ad19a3f 30 if (!nlmsg_len(nlmsg))
19bfd55a
CB
31 return ret_set_errno(NULL, EINVAL);
32
0ad19a3f 33 return data;
34}
35
f79d43bb 36static int nla_put(struct nlmsg *nlmsg, int attr,
0ad19a3f 37 const void *data, size_t len)
38{
39 struct rtattr *rta;
40 size_t rtalen = RTA_LENGTH(len);
06f976ca 41 size_t tlen = NLMSG_ALIGN(nlmsg->nlmsghdr->nlmsg_len) + RTA_ALIGN(rtalen);
84760c11 42
b608dc2f 43 if (tlen > (size_t)nlmsg->cap)
19bfd55a 44 return ret_errno(ENOMEM);
06f976ca
SZ
45
46 rta = NLMSG_TAIL(nlmsg->nlmsghdr);
47 rta->rta_type = attr;
48 rta->rta_len = rtalen;
c8f05589
RM
49 if (data && len)
50 memcpy(RTA_DATA(rta), data, len);
06f976ca 51 nlmsg->nlmsghdr->nlmsg_len = tlen;
19bfd55a 52
0ad19a3f 53 return 0;
54}
55
19bfd55a 56int nla_put_buffer(struct nlmsg *nlmsg, int attr, const void *data, size_t size)
0ad19a3f 57{
58 return nla_put(nlmsg, attr, data, size);
59}
60
19bfd55a 61int nla_put_string(struct nlmsg *nlmsg, int attr, const char *string)
0ad19a3f 62{
d028235d 63 return nla_put(nlmsg, attr, string, strlen(string) + 1);
0ad19a3f 64}
65
19bfd55a 66int nla_put_u32(struct nlmsg *nlmsg, int attr, int value)
0ad19a3f 67{
68 return nla_put(nlmsg, attr, &value, sizeof(value));
69}
70
19bfd55a 71int nla_put_u16(struct nlmsg *nlmsg, int attr, unsigned short value)
9ddaf3bf
JHS
72{
73 return nla_put(nlmsg, attr, &value, 2);
74}
75
19bfd55a 76int nla_put_attr(struct nlmsg *nlmsg, int attr)
0ad19a3f 77{
78 return nla_put(nlmsg, attr, NULL, 0);
79}
80
81struct rtattr *nla_begin_nested(struct nlmsg *nlmsg, int attr)
82{
19bfd55a 83 struct rtattr *rtattr;
0ad19a3f 84
19bfd55a 85 rtattr = NLMSG_TAIL(nlmsg->nlmsghdr);
0ad19a3f 86 if (nla_put_attr(nlmsg, attr))
19bfd55a 87 return ret_set_errno(NULL, ENOMEM);
0ad19a3f 88
89 return rtattr;
90}
91
92void nla_end_nested(struct nlmsg *nlmsg, struct rtattr *attr)
93{
06f976ca 94 attr->rta_len = (void *)NLMSG_TAIL(nlmsg->nlmsghdr) - (void *)attr;
0ad19a3f 95}
96
19bfd55a 97struct nlmsg *nlmsg_alloc(size_t size)
0ad19a3f 98{
19bfd55a 99 __do_free struct nlmsg *nlmsg = NULL;
b5887164 100 size_t len = NLMSG_HDRLEN + NLMSG_ALIGN(size);
0ad19a3f 101
19bfd55a 102 nlmsg = malloc(sizeof(struct nlmsg));
0ad19a3f 103 if (!nlmsg)
19bfd55a 104 return ret_set_errno(NULL, ENOMEM);
0ad19a3f 105
19bfd55a 106 nlmsg->nlmsghdr = malloc(len);
3d88831c 107 if (!nlmsg->nlmsghdr)
19bfd55a 108 return ret_set_errno(NULL, ENOMEM);
06f976ca
SZ
109
110 memset(nlmsg->nlmsghdr, 0, len);
111 nlmsg->cap = len;
112 nlmsg->nlmsghdr->nlmsg_len = NLMSG_HDRLEN;
0ad19a3f 113
19bfd55a 114 return move_ptr(nlmsg);
06f976ca
SZ
115}
116
19bfd55a 117void *nlmsg_reserve(struct nlmsg *nlmsg, size_t len)
06f976ca
SZ
118{
119 void *buf;
120 size_t nlmsg_len = nlmsg->nlmsghdr->nlmsg_len;
121 size_t tlen = NLMSG_ALIGN(len);
122
b608dc2f 123 if (nlmsg_len + tlen > (size_t)nlmsg->cap)
19bfd55a 124 return ret_set_errno(NULL, ENOMEM);
06f976ca
SZ
125
126 buf = ((char *)(nlmsg->nlmsghdr)) + nlmsg_len;
127 nlmsg->nlmsghdr->nlmsg_len += tlen;
128
129 if (tlen > len)
130 memset(buf + len, 0, tlen - len);
131
132 return buf;
133}
134
19bfd55a 135struct nlmsg *nlmsg_alloc_reserve(size_t size)
06f976ca
SZ
136{
137 struct nlmsg *nlmsg;
138
139 nlmsg = nlmsg_alloc(size);
140 if (!nlmsg)
19bfd55a 141 return ret_set_errno(NULL, ENOMEM);
06f976ca 142
1a0e70ac 143 /* Just set message length to cap directly. */
06f976ca 144 nlmsg->nlmsghdr->nlmsg_len = nlmsg->cap;
0ad19a3f 145 return nlmsg;
146}
147
19bfd55a 148void nlmsg_free(struct nlmsg *nlmsg)
0ad19a3f 149{
19bfd55a
CB
150 if (nlmsg) {
151 free(nlmsg->nlmsghdr);
152 free(nlmsg);
153 }
0ad19a3f 154}
155
19bfd55a 156int __netlink_recv(struct nl_handler *handler, struct nlmsghdr *nlmsghdr)
0ad19a3f 157{
158 int ret;
d028235d
SG
159 struct sockaddr_nl nladdr;
160 struct iovec iov = {
9fbbc427
CB
161 .iov_base = nlmsghdr,
162 .iov_len = nlmsghdr->nlmsg_len,
d028235d 163 };
1a0e70ac 164
0ad19a3f 165 struct msghdr msg = {
9fbbc427
CB
166 .msg_name = &nladdr,
167 .msg_namelen = sizeof(nladdr),
168 .msg_iov = &iov,
169 .msg_iovlen = 1,
d028235d 170 };
1a0e70ac 171
d028235d
SG
172 memset(&nladdr, 0, sizeof(nladdr));
173 nladdr.nl_family = AF_NETLINK;
174 nladdr.nl_pid = 0;
175 nladdr.nl_groups = 0;
0ad19a3f 176
177again:
178 ret = recvmsg(handler->fd, &msg, 0);
179 if (ret < 0) {
180 if (errno == EINTR)
181 goto again;
9fbbc427 182
19bfd55a 183 return ret_errno(errno);
0ad19a3f 184 }
185
186 if (!ret)
187 return 0;
188
b608dc2f 189 if (msg.msg_flags & MSG_TRUNC && ((__u32)ret == nlmsghdr->nlmsg_len))
19bfd55a 190 return ret_errno(EMSGSIZE);
0ad19a3f 191
192 return ret;
193}
194
19bfd55a 195int netlink_rcv(struct nl_handler *handler, struct nlmsg *answer)
9fbbc427
CB
196{
197 return __netlink_recv(handler, answer->nlmsghdr);
198}
199
19bfd55a 200int __netlink_send(struct nl_handler *handler, struct nlmsghdr *nlmsghdr)
0ad19a3f 201{
9fbbc427 202 int ret;
d028235d
SG
203 struct sockaddr_nl nladdr;
204 struct iovec iov = {
9fbbc427
CB
205 .iov_base = nlmsghdr,
206 .iov_len = nlmsghdr->nlmsg_len,
d028235d 207 };
0ad19a3f 208 struct msghdr msg = {
9fbbc427
CB
209 .msg_name = &nladdr,
210 .msg_namelen = sizeof(nladdr),
211 .msg_iov = &iov,
212 .msg_iovlen = 1,
d028235d 213 };
1a0e70ac 214
d028235d
SG
215 memset(&nladdr, 0, sizeof(nladdr));
216 nladdr.nl_family = AF_NETLINK;
217 nladdr.nl_pid = 0;
218 nladdr.nl_groups = 0;
0ad19a3f 219
57b1ab60 220 ret = sendmsg(handler->fd, &msg, MSG_NOSIGNAL);
e239ff31 221 if (ret < 0)
19bfd55a 222 return ret_errno(errno);
0ad19a3f 223
224 return ret;
225}
226
9fbbc427
CB
227extern int netlink_send(struct nl_handler *handler, struct nlmsg *nlmsg)
228{
229 return __netlink_send(handler, nlmsg->nlmsghdr);
230}
231
232extern int __netlink_transaction(struct nl_handler *handler,
233 struct nlmsghdr *request,
234 struct nlmsghdr *answer)
0ad19a3f 235{
0ad19a3f 236 int ret;
237
9fbbc427 238 ret = __netlink_send(handler, request);
0ad19a3f 239 if (ret < 0)
19bfd55a 240 return ret;
0ad19a3f 241
9fbbc427 242 ret = __netlink_recv(handler, answer);
0ad19a3f 243 if (ret < 0)
19bfd55a 244 return ret;
0ad19a3f 245
9fbbc427
CB
246 if (answer->nlmsg_type == NLMSG_ERROR) {
247 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(answer);
bfcedc7e 248 if (err->error < 0)
19bfd55a 249 return ret_errno(-err->error);
0ad19a3f 250 }
e239ff31 251
19bfd55a 252 return 0;
0ad19a3f 253}
254
9fbbc427
CB
255extern int netlink_transaction(struct nl_handler *handler,
256 struct nlmsg *request, struct nlmsg *answer)
257{
258 return __netlink_transaction(handler, request->nlmsghdr,
259 answer->nlmsghdr);
260}
261
0ad19a3f 262extern int netlink_open(struct nl_handler *handler, int protocol)
263{
19bfd55a 264 __do_close int fd = -EBADF;
0ad19a3f 265 socklen_t socklen;
d028235d
SG
266 int sndbuf = 32768;
267 int rcvbuf = 32768;
0ad19a3f 268
d028235d 269 memset(handler, 0, sizeof(*handler));
19bfd55a 270 handler->fd = -EBADF;
0ad19a3f 271
19bfd55a
CB
272 fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
273 if (fd < 0)
274 return ret_errno(errno);
0ad19a3f 275
19bfd55a
CB
276 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0)
277 return ret_errno(errno);
0ad19a3f 278
19bfd55a
CB
279 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,sizeof(rcvbuf)) < 0)
280 return ret_errno(errno);
0ad19a3f 281
d028235d
SG
282 memset(&handler->local, 0, sizeof(handler->local));
283 handler->local.nl_family = AF_NETLINK;
284 handler->local.nl_groups = 0;
0ad19a3f 285
19bfd55a
CB
286 if (bind(fd, (struct sockaddr*)&handler->local, sizeof(handler->local)) < 0)
287 return ret_errno(errno);
0ad19a3f 288
d028235d 289 socklen = sizeof(handler->local);
19bfd55a
CB
290 if (getsockname(fd, (struct sockaddr*)&handler->local, &socklen) < 0)
291 return ret_errno(errno);
0ad19a3f 292
19bfd55a
CB
293 if (socklen != sizeof(handler->local))
294 return ret_errno(EINVAL);
0ad19a3f 295
19bfd55a
CB
296 if (handler->local.nl_family != AF_NETLINK)
297 return ret_errno(EINVAL);
0ad19a3f 298
299 handler->seq = time(NULL);
19bfd55a 300 handler->fd = move_fd(fd);
d028235d 301 return 0;
0ad19a3f 302}
303
d16bda44 304extern void netlink_close(struct nl_handler *handler)
0ad19a3f 305{
d16bda44 306 close_prot_errno_disarm(handler->fd);
0ad19a3f 307}
308
cc6119a0
CB
309int addattr(struct nlmsghdr *n, size_t maxlen, int type, const void *data,
310 size_t alen)
311{
312 int len = RTA_LENGTH(alen);
313 struct rtattr *rta;
314
cc6119a0 315 if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen)
19bfd55a 316 return ret_errno(EMSGSIZE);
cc6119a0
CB
317
318 rta = NLMSG_TAIL(n);
319 rta->rta_type = type;
320 rta->rta_len = len;
321 if (alen)
322 memcpy(RTA_DATA(rta), data, alen);
323 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
324
325 return 0;
326}