]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-netlink/netlink-message.c
sd-netlink: make NLTypeSystem internal
[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
817d1cd8 79 size = NLMSG_SPACE(type_get_size(nl_type));
1b89cf56
TG
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
817d1cd8 88 if (type_get_type(nl_type) == NETLINK_TYPE_NESTED)
c658008f 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
817d1cd8 226 if (type_get_type(type) != data_type)
d8e538ec
TG
227 return -EINVAL;
228
817d1cd8 229 return type_get_size(type);
d8e538ec
TG
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
817d1cd8 673int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
d8e538ec
TG
674 const NLType *nl_type;
675 const NLTypeSystem *type_system;
3dd215e0 676 void *container;
817d1cd8 677 uint16_t type;
d8e538ec
TG
678 size_t size;
679 int r;
3dd215e0
TG
680
681 assert_return(m, -EINVAL);
682 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
683
d8e538ec
TG
684 r = type_system_get_type(m->container_type_system[m->n_containers],
685 &nl_type,
817d1cd8 686 type_id);
3dd215e0
TG
687 if (r < 0)
688 return r;
3dd215e0 689
817d1cd8
DH
690 type = type_get_type(nl_type);
691
692 if (type == NETLINK_TYPE_NESTED) {
d8e538ec
TG
693 r = type_system_get_type_system(m->container_type_system[m->n_containers],
694 &type_system,
817d1cd8 695 type_id);
d8e538ec
TG
696 if (r < 0)
697 return r;
817d1cd8 698 } else if (type == NETLINK_TYPE_UNION) {
d8e538ec 699 const NLTypeSystemUnion *type_system_union;
d8e538ec
TG
700
701 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
702 &type_system_union,
817d1cd8 703 type_id);
d8e538ec
TG
704 if (r < 0)
705 return r;
706
4af7b60d
TG
707 switch (type_system_union->match_type) {
708 case NL_MATCH_SIBLING:
709 {
710 const char *key;
711
1c4baffc 712 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
4af7b60d
TG
713 if (r < 0)
714 return r;
715
716 r = type_system_union_get_type_system(type_system_union,
717 &type_system,
718 key);
719 if (r < 0)
720 return r;
721
722 break;
723 }
724 case NL_MATCH_PROTOCOL:
725 {
726 int family;
727
89489ef7 728 r = sd_rtnl_message_get_family(m, &family);
4af7b60d
TG
729 if (r < 0)
730 return r;
731
732 r = type_system_union_protocol_get_type_system(type_system_union,
733 &type_system,
734 family);
735 if (r < 0)
736 return r;
737
738 break;
739 }
740 default:
1c4baffc 741 assert_not_reached("sd-netlink: invalid type system union type");
4af7b60d 742 }
d8e538ec
TG
743 } else
744 return -EINVAL;
745
817d1cd8 746 r = rtnl_message_read_internal(m, type_id, &container);
3dd215e0
TG
747 if (r < 0)
748 return r;
d8e538ec
TG
749 else
750 size = (size_t)r;
3dd215e0 751
d8e538ec 752 m->n_containers ++;
3dd215e0
TG
753
754 r = rtnl_message_parse(m,
d8e538ec
TG
755 &m->rta_offset_tb[m->n_containers],
756 &m->rta_tb_size[m->n_containers],
435bbb02 757 type_system_get_max(type_system),
3dd215e0 758 container,
d8e538ec
TG
759 size);
760 if (r < 0) {
761 m->n_containers --;
3dd215e0 762 return r;
d8e538ec 763 }
3dd215e0 764
d8e538ec 765 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
766
767 return 0;
768}
769
1c4baffc 770int sd_netlink_message_exit_container(sd_netlink_message *m) {
e5c4350b
TG
771 assert_return(m, -EINVAL);
772 assert_return(m->sealed, -EINVAL);
773 assert_return(m->n_containers > 0, -EINVAL);
774
3dd215e0
TG
775 free(m->rta_offset_tb[m->n_containers]);
776 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 777 m->container_type_system[m->n_containers] = NULL;
3dd215e0 778
e5c4350b
TG
779 m->n_containers --;
780
781 return 0;
782}
783
1c4baffc 784uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
65f568bb 785 assert(m);
9d0db178 786 assert(m->hdr);
65f568bb
TG
787
788 return m->hdr->nlmsg_seq;
789}
790
1c4baffc 791int sd_netlink_message_is_error(sd_netlink_message *m) {
45af44d4
TG
792 assert_return(m, 0);
793 assert_return(m->hdr, 0);
794
795 return m->hdr->nlmsg_type == NLMSG_ERROR;
796}
797
1c4baffc 798int sd_netlink_message_get_errno(sd_netlink_message *m) {
65f568bb
TG
799 struct nlmsgerr *err;
800
e16bcf98 801 assert_return(m, -EINVAL);
9d0db178 802 assert_return(m->hdr, -EINVAL);
65f568bb 803
1c4baffc 804 if (!sd_netlink_message_is_error(m))
65f568bb
TG
805 return 0;
806
807 err = NLMSG_DATA(m->hdr);
808
809 return err->error;
810}
811
1c4baffc 812int rtnl_message_parse(sd_netlink_message *m,
44caa5e7
SS
813 size_t **rta_offset_tb,
814 unsigned short *rta_tb_size,
815 int max,
816 struct rtattr *rta,
817 unsigned int rt_len) {
e634cd40 818 unsigned short type;
44caa5e7
SS
819 size_t *tb;
820
c8a7165f 821 tb = new0(size_t, max + 1);
44caa5e7
SS
822 if(!tb)
823 return -ENOMEM;
824
c8a7165f 825 *rta_tb_size = max + 1;
44caa5e7
SS
826
827 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
0a2478a9 828 type = RTA_TYPE(rta);
44caa5e7 829
aef0768e
TG
830 /* if the kernel is newer than the headers we used
831 when building, we ignore out-of-range attributes
832 */
833 if (type > max)
e634cd40 834 continue;
e634cd40
TG
835
836 if (tb[type])
837 log_debug("rtnl: message parse - overwriting repeated attribute");
838
839 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
840 }
841
842 *rta_offset_tb = tb;
843
844 return 0;
845}
846
1c4baffc 847int sd_netlink_message_rewind(sd_netlink_message *m) {
817d1cd8
DH
848 const NLType *nl_type;
849 uint16_t type;
850 size_t size;
3dd215e0
TG
851 unsigned i;
852 int r;
0fc7531b
TG
853
854 assert_return(m, -EINVAL);
0fc7531b 855
3dd215e0
TG
856 /* don't allow appending to message once parsed */
857 if (!m->sealed)
858 rtnl_message_seal(m);
859
860 for (i = 1; i <= m->n_containers; i++) {
861 free(m->rta_offset_tb[i]);
862 m->rta_offset_tb[i] = NULL;
863 m->rta_tb_size[i] = 0;
d8e538ec 864 m->container_type_system[i] = NULL;
3dd215e0
TG
865 }
866
867 m->n_containers = 0;
868
869 if (m->rta_offset_tb[0]) {
870 /* top-level attributes have already been parsed */
871 return 0;
872 }
873
d8e538ec
TG
874 assert(m->hdr);
875
817d1cd8 876 r = type_system_get_type(NULL, &nl_type, m->hdr->nlmsg_type);
d8e538ec
TG
877 if (r < 0)
878 return r;
879
817d1cd8
DH
880 type = type_get_type(nl_type);
881 size = type_get_size(nl_type);
882
883 if (type == NETLINK_TYPE_NESTED) {
c658008f 884 const NLTypeSystem *type_system;
d8e538ec 885
817d1cd8 886 type_get_type_system(nl_type, &type_system);
d8e538ec
TG
887
888 m->container_type_system[0] = type_system;
889
890 r = rtnl_message_parse(m,
891 &m->rta_offset_tb[m->n_containers],
892 &m->rta_tb_size[m->n_containers],
435bbb02 893 type_system_get_max(type_system),
817d1cd8
DH
894 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
895 NLMSG_PAYLOAD(m->hdr, size));
d8e538ec
TG
896 if (r < 0)
897 return r;
0fc7531b
TG
898 }
899
900 return 0;
901}
3dd215e0 902
1c4baffc 903void rtnl_message_seal(sd_netlink_message *m) {
3dd215e0
TG
904 assert(m);
905 assert(!m->sealed);
906
907 m->sealed = true;
908}
1403f45a 909
1c4baffc 910sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
1403f45a
TG
911 assert_return(m, NULL);
912
913 return m->next;
914}