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