]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-netlink/netlink-message.c
sd-hwdb: some minor logging and style updates
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / netlink-message.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
65f568bb
TG
2
3#include <netinet/in.h>
65f568bb
TG
4#include <stdbool.h>
5#include <unistd.h>
6
07630cea
LP
7#include "sd-netlink.h"
8
b5efdb8a 9#include "alloc-util.h"
f97b34a6 10#include "format-util.h"
d5eff740 11#include "missing.h"
1c4baffc
TG
12#include "netlink-internal.h"
13#include "netlink-types.h"
07630cea
LP
14#include "netlink-util.h"
15#include "refcnt.h"
16#include "socket-util.h"
17#include "util.h"
65f568bb 18
f663aeb8 19#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
313cefa1 20#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4ebe732c 21
0a2478a9 22#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
4c641e99 23#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
0a2478a9 24
89489ef7 25int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
1c4baffc 26 sd_netlink_message *m;
65f568bb
TG
27
28 assert_return(ret, -EINVAL);
65f568bb 29
f131770b 30 /* Note that 'rtnl' is currently unused, if we start using it internally
8c578303 31 we must take care to avoid problems due to mutual references between
ff9b60f3 32 buses and their queued messages. See sd-bus.
8c578303
TG
33 */
34
1c4baffc 35 m = new0(sd_netlink_message, 1);
65f568bb
TG
36 if (!m)
37 return -ENOMEM;
38
65f568bb 39 m->n_ref = REFCNT_INIT;
05d0c2e3 40 m->protocol = rtnl->protocol;
65f568bb
TG
41 m->sealed = false;
42
43 *ret = m;
44
45 return 0;
46}
47
1c4baffc 48int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
4afd3348 49 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
d8e538ec 50 const NLType *nl_type;
05d0c2e3 51 const NLTypeSystem *type_system_root;
d8e538ec
TG
52 size_t size;
53 int r;
54
05d0c2e3
JT
55 assert_return(rtnl, -EINVAL);
56
57 type_system_root = type_system_get_root(rtnl->protocol);
58
59 r = type_system_get_type(type_system_root, &nl_type, type);
d8e538ec
TG
60 if (r < 0)
61 return r;
62
12b7dff4
DH
63 if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
64 return -EINVAL;
65
1b89cf56 66 r = message_new_empty(rtnl, &m);
d8e538ec
TG
67 if (r < 0)
68 return r;
69
817d1cd8 70 size = NLMSG_SPACE(type_get_size(nl_type));
1b89cf56
TG
71
72 assert(size >= sizeof(struct nlmsghdr));
73 m->hdr = malloc0(size);
74 if (!m->hdr)
75 return -ENOMEM;
76
77 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
78
f663aeb8 79 type_get_type_system(nl_type, &m->containers[0].type_system);
1b89cf56
TG
80 m->hdr->nlmsg_len = size;
81 m->hdr->nlmsg_type = type;
82
1cc6c93a 83 *ret = TAKE_PTR(m);
d8e538ec
TG
84
85 return 0;
86}
87
1c4baffc 88int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
6e20c8f8
TG
89 assert_return(m, -EINVAL);
90 assert_return(m->hdr, -EINVAL);
bce67bbe
SS
91
92 assert_return(IN_SET(m->hdr->nlmsg_type, RTM_GETLINK, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH, RTM_GETRULE, RTM_GETADDRLABEL), -EINVAL);
6e20c8f8 93
5883ff60 94 SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
6e20c8f8
TG
95
96 return 0;
97}
98
1c71f7f3 99DEFINE_ATOMIC_REF_FUNC(sd_netlink_message, sd_netlink_message);
65f568bb 100
1c4baffc 101sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
82e4eda6
DH
102 sd_netlink_message *t;
103
104 while (m && REFCNT_DEC(m->n_ref) == 0) {
3dd215e0
TG
105 unsigned i;
106
65f568bb 107 free(m->hdr);
3dd215e0 108
9f5bbfe3 109 for (i = 0; i <= m->n_containers; i++)
f663aeb8 110 free(m->containers[i].attributes);
3dd215e0 111
82e4eda6
DH
112 t = m;
113 m = m->next;
114 free(t);
65f568bb
TG
115 }
116
117 return NULL;
118}
119
1c4baffc 120int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
65f568bb
TG
121 assert_return(m, -EINVAL);
122 assert_return(type, -EINVAL);
123
124 *type = m->hdr->nlmsg_type;
125
126 return 0;
127}
128
c06cb593
SS
129int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
130 assert_return(m, -EINVAL);
131 assert_return(flags, -EINVAL);
132
133 m->hdr->nlmsg_flags = flags;
134
135 return 0;
136}
137
1c4baffc 138int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
1f0db3ed
TG
139 assert_return(m, -EINVAL);
140
3f42446d 141 return m->broadcast;
1f0db3ed
TG
142}
143
4ebe732c
ZJS
144/* If successful the updated message will be correctly aligned, if
145 unsuccessful the old message is untouched. */
1c4baffc 146static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
7ca1d319
TG
147 uint32_t rta_length;
148 size_t message_length, padding_length;
65f568bb
TG
149 struct nlmsghdr *new_hdr;
150 struct rtattr *rta;
8e337e64 151 char *padding;
5a081409 152 unsigned i;
7ca1d319 153 int offset;
65f568bb 154
33125ac5
TG
155 assert(m);
156 assert(m->hdr);
e5c4350b 157 assert(!m->sealed);
33125ac5 158 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
7ca1d319
TG
159 assert(!data || data_length);
160
161 /* get offset of the new attribute */
162 offset = m->hdr->nlmsg_len;
65f568bb 163
8e337e64 164 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 165 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
166
167 /* get the new message size (with padding at the end) */
7ca1d319 168 message_length = offset + RTA_ALIGN(rta_length);
65f568bb 169
05d0c2e3
JT
170 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
171 if (message_length > MIN(page_size(), 8192UL))
172 return -ENOBUFS;
173
65f568bb
TG
174 /* realloc to fit the new attribute */
175 new_hdr = realloc(m->hdr, message_length);
176 if (!new_hdr)
177 return -ENOMEM;
178 m->hdr = new_hdr;
179
180 /* get pointer to the attribute we are about to add */
7ca1d319 181 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
65f568bb 182
5a081409
TG
183 /* if we are inside containers, extend them */
184 for (i = 0; i < m->n_containers; i++)
7ca1d319 185 GET_CONTAINER(m, i)->rta_len += message_length - offset;
33125ac5 186
65f568bb
TG
187 /* fill in the attribute */
188 rta->rta_type = type;
189 rta->rta_len = rta_length;
7ca1d319 190 if (data)
33125ac5
TG
191 /* we don't deal with the case where the user lies about the type
192 * and gives us too little data (so don't do that)
7ca1d319 193 */
33125ac5 194 padding = mempcpy(RTA_DATA(rta), data, data_length);
b8cc01a2
SS
195
196 else
7ca1d319
TG
197 /* if no data was passed, make sure we still initialize the padding
198 note that we can have data_length > 0 (used by some containers) */
199 padding = RTA_DATA(rta);
65f568bb 200
7ca1d319
TG
201 /* make sure also the padding at the end of the message is initialized */
202 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
203 memzero(padding, padding_length);
204
4ebe732c
ZJS
205 /* update message size */
206 m->hdr->nlmsg_len = message_length;
207
7ca1d319 208 return offset;
65f568bb
TG
209}
210
6c14ad61 211static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
d8e538ec
TG
212 const NLType *type;
213 int r;
214
6c14ad61
DH
215 assert(m);
216
f663aeb8 217 r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type);
d8e538ec
TG
218 if (r < 0)
219 return r;
220
817d1cd8 221 if (type_get_type(type) != data_type)
d8e538ec
TG
222 return -EINVAL;
223
6c14ad61
DH
224 if (out_size)
225 *out_size = type_get_size(type);
226 return 0;
d8e538ec
TG
227}
228
1c4baffc 229int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
d8e538ec 230 size_t length, size;
0a0dc69b 231 int r;
65f568bb
TG
232
233 assert_return(m, -EINVAL);
e5c4350b 234 assert_return(!m->sealed, -EPERM);
65f568bb
TG
235 assert_return(data, -EINVAL);
236
6c14ad61 237 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
0a0dc69b
TG
238 if (r < 0)
239 return r;
65f568bb 240
d8e538ec 241 if (size) {
3072eecf
LP
242 length = strnlen(data, size+1);
243 if (length > size)
d8e538ec
TG
244 return -EINVAL;
245 } else
246 length = strlen(data);
33125ac5 247
d8e538ec 248 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
249 if (r < 0)
250 return r;
251
252 return 0;
253}
254
c06aead0
SS
255int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
256 size_t size;
257 int r;
258
259 assert_return(m, -EINVAL);
260 assert_return(!m->sealed, -EPERM);
261
262 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
263 if (r < 0)
264 return r;
265
266 r = add_rtattr(m, type, NULL, 0);
267 if (r < 0)
268 return r;
269
270 return 0;
271}
272
1c4baffc 273int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
7b179640
SS
274 int r;
275
276 assert_return(m, -EINVAL);
277 assert_return(!m->sealed, -EPERM);
278
6c14ad61 279 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
7b179640
SS
280 if (r < 0)
281 return r;
282
7b179640
SS
283 r = add_rtattr(m, type, &data, sizeof(uint8_t));
284 if (r < 0)
285 return r;
286
287 return 0;
288}
289
1c4baffc 290int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
01b36069
TG
291 int r;
292
293 assert_return(m, -EINVAL);
e5c4350b 294 assert_return(!m->sealed, -EPERM);
01b36069 295
6c14ad61 296 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
01b36069
TG
297 if (r < 0)
298 return r;
299
01b36069
TG
300 r = add_rtattr(m, type, &data, sizeof(uint16_t));
301 if (r < 0)
302 return r;
303
304 return 0;
305}
306
1c4baffc 307int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
308 int r;
309
310 assert_return(m, -EINVAL);
e5c4350b 311 assert_return(!m->sealed, -EPERM);
0a0dc69b 312
6c14ad61 313 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
0a0dc69b
TG
314 if (r < 0)
315 return r;
316
4d47756b 317 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
318 if (r < 0)
319 return r;
320
321 return 0;
322}
323
17af840b
SS
324int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
325 int r;
326
327 assert_return(m, -EINVAL);
328 assert_return(!m->sealed, -EPERM);
329
b8cc01a2 330 r = add_rtattr(m, type, data, len);
17af840b
SS
331 if (r < 0)
332 return r;
333
334 return 0;
335}
336
67b19a49 337int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data) {
0a0dc69b
TG
338 int r;
339
340 assert_return(m, -EINVAL);
e5c4350b 341 assert_return(!m->sealed, -EPERM);
0a0dc69b 342 assert_return(data, -EINVAL);
67b19a49 343 assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
0a0dc69b 344
6c14ad61 345 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
0a0dc69b
TG
346 if (r < 0)
347 return r;
348
67b19a49 349 r = add_rtattr(m, type, data, FAMILY_ADDRESS_SIZE(family));
0a0dc69b
TG
350 if (r < 0)
351 return r;
352
353 return 0;
354}
355
67b19a49
YW
356int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
357 return netlink_message_append_in_addr_union(m, type, AF_INET, (const union in_addr_union *) data);
358}
abd48ec8 359
67b19a49
YW
360int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
361 return netlink_message_append_in_addr_union(m, type, AF_INET6, (const union in_addr_union *) data);
abd48ec8
YW
362}
363
67b19a49 364int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data) {
abd48ec8
YW
365 int r;
366
367 assert_return(m, -EINVAL);
368 assert_return(!m->sealed, -EPERM);
369 assert_return(data, -EINVAL);
67b19a49 370 assert_return(IN_SET(data->sa.sa_family, AF_INET, AF_INET6), -EINVAL);
abd48ec8
YW
371
372 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR);
373 if (r < 0)
374 return r;
375
67b19a49 376 r = add_rtattr(m, type, data, data->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
abd48ec8
YW
377 if (r < 0)
378 return r;
379
380 return 0;
381}
382
67b19a49
YW
383int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) {
384 return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
385}
0a0dc69b 386
67b19a49
YW
387int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) {
388 return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
0a0dc69b
TG
389}
390
67b19a49 391
1c4baffc 392int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
393 int r;
394
395 assert_return(m, -EINVAL);
e5c4350b 396 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
397 assert_return(data, -EINVAL);
398
6c14ad61 399 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
d8e538ec
TG
400 if (r < 0)
401 return r;
0a0dc69b 402
b9eaf3d1 403 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
404 if (r < 0)
405 return r;
406
407 return 0;
65f568bb
TG
408}
409
1c4baffc 410int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
aba496a5
UTL
411 int r;
412
413 assert_return(m, -EINVAL);
414 assert_return(!m->sealed, -EPERM);
415 assert_return(info, -EINVAL);
416
6c14ad61 417 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
aba496a5
UTL
418 if (r < 0)
419 return r;
420
421 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
422 if (r < 0)
423 return r;
424
425 return 0;
426}
427
1c4baffc 428int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
d8e538ec
TG
429 size_t size;
430 int r;
33125ac5 431
65f568bb 432 assert_return(m, -EINVAL);
e5c4350b 433 assert_return(!m->sealed, -EPERM);
7ca1d319 434 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
33125ac5 435
6c14ad61 436 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
4af7b60d
TG
437 if (r < 0) {
438 const NLTypeSystemUnion *type_system_union;
439 int family;
440
6c14ad61 441 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
4af7b60d
TG
442 if (r < 0)
443 return r;
4af7b60d 444
89489ef7 445 r = sd_rtnl_message_get_family(m, &family);
4af7b60d
TG
446 if (r < 0)
447 return r;
448
f663aeb8 449 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
4af7b60d
TG
450 if (r < 0)
451 return r;
452
453 r = type_system_union_protocol_get_type_system(type_system_union,
f663aeb8 454 &m->containers[m->n_containers + 1].type_system,
4af7b60d
TG
455 family);
456 if (r < 0)
457 return r;
458 } else {
f663aeb8
TG
459 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
460 &m->containers[m->n_containers + 1].type_system,
4af7b60d
TG
461 type);
462 if (r < 0)
463 return r;
464 }
31a4e153 465
fcf81a54 466 r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
d8e538ec
TG
467 if (r < 0)
468 return r;
469
313cefa1 470 m->containers[m->n_containers++].offset = r;
7ca1d319 471
d8e538ec
TG
472 return 0;
473}
474
1c4baffc 475int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
d8e538ec
TG
476 const NLTypeSystemUnion *type_system_union;
477 int r;
478
479 assert_return(m, -EINVAL);
480 assert_return(!m->sealed, -EPERM);
481
f663aeb8 482 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
d8e538ec
TG
483 if (r < 0)
484 return r;
485
486 r = type_system_union_get_type_system(type_system_union,
f663aeb8 487 &m->containers[m->n_containers + 1].type_system,
d8e538ec
TG
488 key);
489 if (r < 0)
490 return r;
33125ac5 491
1c4baffc 492 r = sd_netlink_message_append_string(m, type_system_union->match, key);
d8e538ec
TG
493 if (r < 0)
494 return r;
495
05d0c2e3 496 /* do we ever need non-null size */
da041d69 497 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
d8e538ec
TG
498 if (r < 0)
499 return r;
500
313cefa1 501 m->containers[m->n_containers++].offset = r;
7ca1d319 502
d8e538ec 503 return 0;
33125ac5
TG
504}
505
1c4baffc 506int sd_netlink_message_close_container(sd_netlink_message *m) {
33125ac5 507 assert_return(m, -EINVAL);
e5c4350b 508 assert_return(!m->sealed, -EPERM);
5a081409 509 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 510
f663aeb8 511 m->containers[m->n_containers].type_system = NULL;
05d0c2e3
JT
512 m->containers[m->n_containers].offset = 0;
513 m->n_containers--;
514
515 return 0;
516}
517
518int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
519 int r;
520
521 assert_return(m, -EINVAL);
522 assert_return(!m->sealed, -EPERM);
523 assert_return(m->n_containers > 0, -EINVAL);
524
525 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
526 if (r < 0)
527 return r;
528
529 m->containers[m->n_containers].offset = r;
530 m->n_containers++;
531 m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
532
533 return 0;
534}
535
536int sd_netlink_message_cancel_array(sd_netlink_message *m) {
537 unsigned i;
538 uint32_t rta_len;
539
540 assert_return(m, -EINVAL);
541 assert_return(!m->sealed, -EPERM);
542 assert_return(m->n_containers > 1, -EINVAL);
543
544 rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
545
546 for (i = 0; i < m->n_containers; i++)
547 GET_CONTAINER(m, i)->rta_len -= rta_len;
548
549 m->hdr->nlmsg_len -= rta_len;
550
313cefa1 551 m->n_containers--;
05d0c2e3 552 m->containers[m->n_containers].type_system = NULL;
33125ac5
TG
553
554 return 0;
555}
556
4c641e99 557static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) {
f663aeb8 558 struct netlink_attribute *attribute;
f66eeb6b
TG
559 struct rtattr *rta;
560
44caa5e7
SS
561 assert_return(m, -EINVAL);
562 assert_return(m->sealed, -EPERM);
563 assert_return(data, -EINVAL);
f1dd72c2 564
0610939d 565 assert(m->n_containers < RTNL_CONTAINER_DEPTH);
f663aeb8
TG
566 assert(m->containers[m->n_containers].attributes);
567 assert(type < m->containers[m->n_containers].n_attributes);
44caa5e7 568
f663aeb8
TG
569 attribute = &m->containers[m->n_containers].attributes[type];
570
f1dd72c2 571 if (attribute->offset == 0)
44caa5e7
SS
572 return -ENODATA;
573
f663aeb8 574 rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
44caa5e7 575
f66eeb6b
TG
576 *data = RTA_DATA(rta);
577
4c641e99
TG
578 if (net_byteorder)
579 *net_byteorder = attribute->net_byteorder;
580
f66eeb6b 581 return RTA_PAYLOAD(rta);
44caa5e7
SS
582}
583
926062f0
SS
584int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data) {
585 void *attr_data;
586 int r;
587
588 assert_return(m, -EINVAL);
589
590 r = netlink_message_read_internal(m, type, &attr_data, NULL);
591 if (r < 0)
592 return r;
593
594 if ((size_t) r < size)
595 return -EIO;
596
597 if (data)
598 memcpy(data, attr_data, size);
599
600 return 0;
601}
602
1c4baffc 603int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
44caa5e7
SS
604 int r;
605 void *attr_data;
606
73ae2b7d
TG
607 assert_return(m, -EINVAL);
608
6c14ad61 609 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
d8e538ec
TG
610 if (r < 0)
611 return r;
44caa5e7 612
4c641e99 613 r = netlink_message_read_internal(m, type, &attr_data, NULL);
f66eeb6b 614 if (r < 0)
44caa5e7 615 return r;
f66eeb6b
TG
616 else if (strnlen(attr_data, r) >= (size_t) r)
617 return -EIO;
44caa5e7 618
73ae2b7d
TG
619 if (data)
620 *data = (const char *) attr_data;
44caa5e7
SS
621
622 return 0;
623}
624
1c4baffc 625int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
44caa5e7
SS
626 int r;
627 void *attr_data;
628
73ae2b7d
TG
629 assert_return(m, -EINVAL);
630
6c14ad61 631 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
d8e538ec
TG
632 if (r < 0)
633 return r;
44caa5e7 634
4c641e99 635 r = netlink_message_read_internal(m, type, &attr_data, NULL);
f66eeb6b 636 if (r < 0)
44caa5e7 637 return r;
f66eeb6b
TG
638 else if ((size_t) r < sizeof(uint8_t))
639 return -EIO;
44caa5e7 640
73ae2b7d
TG
641 if (data)
642 *data = *(uint8_t *) attr_data;
44caa5e7
SS
643
644 return 0;
645}
646
1c4baffc 647int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
44caa5e7 648 void *attr_data;
4c641e99
TG
649 bool net_byteorder;
650 int r;
44caa5e7 651
73ae2b7d
TG
652 assert_return(m, -EINVAL);
653
6c14ad61 654 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
d8e538ec
TG
655 if (r < 0)
656 return r;
44caa5e7 657
4c641e99 658 r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
f66eeb6b 659 if (r < 0)
44caa5e7 660 return r;
f66eeb6b
TG
661 else if ((size_t) r < sizeof(uint16_t))
662 return -EIO;
44caa5e7 663
4c641e99
TG
664 if (data) {
665 if (net_byteorder)
666 *data = be16toh(*(uint16_t *) attr_data);
667 else
668 *data = *(uint16_t *) attr_data;
669 }
44caa5e7
SS
670
671 return 0;
672}
673
1c4baffc 674int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
44caa5e7 675 void *attr_data;
4c641e99
TG
676 bool net_byteorder;
677 int r;
44caa5e7 678
73ae2b7d
TG
679 assert_return(m, -EINVAL);
680
6c14ad61 681 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
d8e538ec
TG
682 if (r < 0)
683 return r;
44caa5e7 684
4c641e99 685 r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
f66eeb6b 686 if (r < 0)
44caa5e7 687 return r;
f66eeb6b
TG
688 else if ((size_t)r < sizeof(uint32_t))
689 return -EIO;
44caa5e7 690
4c641e99
TG
691 if (data) {
692 if (net_byteorder)
693 *data = be32toh(*(uint32_t *) attr_data);
694 else
695 *data = *(uint32_t *) attr_data;
696 }
44caa5e7
SS
697
698 return 0;
699}
700
1c4baffc 701int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
4e9e7f18
SS
702 int r;
703 void *attr_data;
704
73ae2b7d
TG
705 assert_return(m, -EINVAL);
706
6c14ad61 707 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
d8e538ec
TG
708 if (r < 0)
709 return r;
4e9e7f18 710
4c641e99 711 r = netlink_message_read_internal(m, type, &attr_data, NULL);
f66eeb6b 712 if (r < 0)
4e9e7f18 713 return r;
f66eeb6b
TG
714 else if ((size_t)r < sizeof(struct ether_addr))
715 return -EIO;
4e9e7f18 716
73ae2b7d
TG
717 if (data)
718 memcpy(data, attr_data, sizeof(struct ether_addr));
4e9e7f18
SS
719
720 return 0;
721}
722
1c4baffc 723int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
aba496a5
UTL
724 int r;
725 void *attr_data;
726
73ae2b7d
TG
727 assert_return(m, -EINVAL);
728
6c14ad61 729 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
aba496a5
UTL
730 if (r < 0)
731 return r;
732
4c641e99 733 r = netlink_message_read_internal(m, type, &attr_data, NULL);
aba496a5
UTL
734 if (r < 0)
735 return r;
736 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
737 return -EIO;
738
73ae2b7d
TG
739 if (info)
740 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
aba496a5
UTL
741
742 return 0;
743}
744
1c4baffc 745int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
4e9e7f18
SS
746 int r;
747 void *attr_data;
748
73ae2b7d
TG
749 assert_return(m, -EINVAL);
750
6c14ad61 751 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
d8e538ec
TG
752 if (r < 0)
753 return r;
4e9e7f18 754
4c641e99 755 r = netlink_message_read_internal(m, type, &attr_data, NULL);
f66eeb6b 756 if (r < 0)
4e9e7f18 757 return r;
f66eeb6b
TG
758 else if ((size_t)r < sizeof(struct in_addr))
759 return -EIO;
4e9e7f18 760
73ae2b7d
TG
761 if (data)
762 memcpy(data, attr_data, sizeof(struct in_addr));
4e9e7f18
SS
763
764 return 0;
765}
766
1c4baffc 767int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
4e9e7f18
SS
768 int r;
769 void *attr_data;
770
73ae2b7d
TG
771 assert_return(m, -EINVAL);
772
6c14ad61 773 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
d8e538ec
TG
774 if (r < 0)
775 return r;
4e9e7f18 776
4c641e99 777 r = netlink_message_read_internal(m, type, &attr_data, NULL);
3dd215e0 778 if (r < 0)
4e9e7f18 779 return r;
3dd215e0
TG
780 else if ((size_t)r < sizeof(struct in6_addr))
781 return -EIO;
4e9e7f18 782
73ae2b7d
TG
783 if (data)
784 memcpy(data, attr_data, sizeof(struct in6_addr));
4e9e7f18
SS
785
786 return 0;
787}
788
f663aeb8
TG
789static int netlink_container_parse(sd_netlink_message *m,
790 struct netlink_container *container,
791 int count,
792 struct rtattr *rta,
14cb109d 793 unsigned rt_len) {
f663aeb8 794 _cleanup_free_ struct netlink_attribute *attributes = NULL;
4203fc8b 795
f663aeb8 796 attributes = new0(struct netlink_attribute, count);
9ed794a3 797 if (!attributes)
4203fc8b
TG
798 return -ENOMEM;
799
4203fc8b 800 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
f663aeb8
TG
801 unsigned short type;
802
4203fc8b
TG
803 type = RTA_TYPE(rta);
804
805 /* if the kernel is newer than the headers we used
f663aeb8 806 when building, we ignore out-of-range attributes */
4203fc8b
TG
807 if (type >= count)
808 continue;
809
f1dd72c2 810 if (attributes[type].offset != 0)
4203fc8b
TG
811 log_debug("rtnl: message parse - overwriting repeated attribute");
812
f663aeb8 813 attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
4c641e99
TG
814 attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
815 attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
4203fc8b
TG
816 }
817
ae2a15bc 818 container->attributes = TAKE_PTR(attributes);
f663aeb8 819 container->n_attributes = count;
4203fc8b
TG
820
821 return 0;
822}
823
817d1cd8 824int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
d8e538ec
TG
825 const NLType *nl_type;
826 const NLTypeSystem *type_system;
3dd215e0 827 void *container;
817d1cd8 828 uint16_t type;
d8e538ec
TG
829 size_t size;
830 int r;
3dd215e0
TG
831
832 assert_return(m, -EINVAL);
833 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
834
f663aeb8 835 r = type_system_get_type(m->containers[m->n_containers].type_system,
d8e538ec 836 &nl_type,
817d1cd8 837 type_id);
3dd215e0
TG
838 if (r < 0)
839 return r;
3dd215e0 840
817d1cd8
DH
841 type = type_get_type(nl_type);
842
843 if (type == NETLINK_TYPE_NESTED) {
f663aeb8 844 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
d8e538ec 845 &type_system,
817d1cd8 846 type_id);
d8e538ec
TG
847 if (r < 0)
848 return r;
817d1cd8 849 } else if (type == NETLINK_TYPE_UNION) {
d8e538ec 850 const NLTypeSystemUnion *type_system_union;
d8e538ec 851
f663aeb8 852 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system,
d8e538ec 853 &type_system_union,
817d1cd8 854 type_id);
d8e538ec
TG
855 if (r < 0)
856 return r;
857
4af7b60d
TG
858 switch (type_system_union->match_type) {
859 case NL_MATCH_SIBLING:
860 {
861 const char *key;
862
1c4baffc 863 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
4af7b60d
TG
864 if (r < 0)
865 return r;
866
867 r = type_system_union_get_type_system(type_system_union,
868 &type_system,
869 key);
870 if (r < 0)
871 return r;
872
873 break;
874 }
875 case NL_MATCH_PROTOCOL:
876 {
877 int family;
878
89489ef7 879 r = sd_rtnl_message_get_family(m, &family);
4af7b60d
TG
880 if (r < 0)
881 return r;
882
883 r = type_system_union_protocol_get_type_system(type_system_union,
884 &type_system,
885 family);
886 if (r < 0)
887 return r;
888
889 break;
890 }
891 default:
1c4baffc 892 assert_not_reached("sd-netlink: invalid type system union type");
4af7b60d 893 }
d8e538ec
TG
894 } else
895 return -EINVAL;
896
4c641e99 897 r = netlink_message_read_internal(m, type_id, &container, NULL);
3dd215e0
TG
898 if (r < 0)
899 return r;
d8e538ec
TG
900 else
901 size = (size_t)r;
3dd215e0 902
313cefa1 903 m->n_containers++;
3dd215e0 904
f663aeb8
TG
905 r = netlink_container_parse(m,
906 &m->containers[m->n_containers],
907 type_system_get_count(type_system),
908 container,
909 size);
d8e538ec 910 if (r < 0) {
313cefa1 911 m->n_containers--;
3dd215e0 912 return r;
d8e538ec 913 }
3dd215e0 914
f663aeb8 915 m->containers[m->n_containers].type_system = type_system;
3dd215e0
TG
916
917 return 0;
918}
919
1c4baffc 920int sd_netlink_message_exit_container(sd_netlink_message *m) {
e5c4350b
TG
921 assert_return(m, -EINVAL);
922 assert_return(m->sealed, -EINVAL);
923 assert_return(m->n_containers > 0, -EINVAL);
924
a1e58e8e 925 m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
f663aeb8 926 m->containers[m->n_containers].type_system = NULL;
3dd215e0 927
313cefa1 928 m->n_containers--;
e5c4350b
TG
929
930 return 0;
931}
932
1c4baffc 933uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
65f568bb 934 assert(m);
9d0db178 935 assert(m->hdr);
65f568bb
TG
936
937 return m->hdr->nlmsg_seq;
938}
939
1c4baffc 940int sd_netlink_message_is_error(sd_netlink_message *m) {
45af44d4
TG
941 assert_return(m, 0);
942 assert_return(m->hdr, 0);
943
944 return m->hdr->nlmsg_type == NLMSG_ERROR;
945}
946
1c4baffc 947int sd_netlink_message_get_errno(sd_netlink_message *m) {
65f568bb
TG
948 struct nlmsgerr *err;
949
e16bcf98 950 assert_return(m, -EINVAL);
9d0db178 951 assert_return(m->hdr, -EINVAL);
65f568bb 952
1c4baffc 953 if (!sd_netlink_message_is_error(m))
65f568bb
TG
954 return 0;
955
956 err = NLMSG_DATA(m->hdr);
957
958 return err->error;
959}
960
1c4baffc 961int sd_netlink_message_rewind(sd_netlink_message *m) {
817d1cd8 962 const NLType *nl_type;
05d0c2e3 963 const NLTypeSystem *type_system_root;
817d1cd8
DH
964 uint16_t type;
965 size_t size;
3dd215e0
TG
966 unsigned i;
967 int r;
0fc7531b
TG
968
969 assert_return(m, -EINVAL);
0fc7531b 970
3dd215e0
TG
971 /* don't allow appending to message once parsed */
972 if (!m->sealed)
973 rtnl_message_seal(m);
974
05d0c2e3
JT
975 type_system_root = type_system_get_root(m->protocol);
976
1f6b4113 977 for (i = 1; i <= m->n_containers; i++)
a1e58e8e 978 m->containers[i].attributes = mfree(m->containers[i].attributes);
3dd215e0
TG
979
980 m->n_containers = 0;
981
ece174c5 982 if (m->containers[0].attributes)
3dd215e0
TG
983 /* top-level attributes have already been parsed */
984 return 0;
3dd215e0 985
d8e538ec
TG
986 assert(m->hdr);
987
05d0c2e3 988 r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
d8e538ec
TG
989 if (r < 0)
990 return r;
991
817d1cd8
DH
992 type = type_get_type(nl_type);
993 size = type_get_size(nl_type);
994
995 if (type == NETLINK_TYPE_NESTED) {
c658008f 996 const NLTypeSystem *type_system;
d8e538ec 997
817d1cd8 998 type_get_type_system(nl_type, &type_system);
d8e538ec 999
f663aeb8 1000 m->containers[0].type_system = type_system;
d8e538ec 1001
f663aeb8
TG
1002 r = netlink_container_parse(m,
1003 &m->containers[m->n_containers],
1004 type_system_get_count(type_system),
1005 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
1006 NLMSG_PAYLOAD(m->hdr, size));
d8e538ec
TG
1007 if (r < 0)
1008 return r;
0fc7531b
TG
1009 }
1010
1011 return 0;
1012}
3dd215e0 1013
1c4baffc 1014void rtnl_message_seal(sd_netlink_message *m) {
3dd215e0
TG
1015 assert(m);
1016 assert(!m->sealed);
1017
1018 m->sealed = true;
1019}
1403f45a 1020
1c4baffc 1021sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
1403f45a
TG
1022 assert_return(m, NULL);
1023
1024 return m->next;
1025}