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