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