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