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