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