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