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