]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-netlink/netlink-message.c
sd-netlink: drop NETLINK_TYPE_META
[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
6c14ad61 218static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
d8e538ec
TG
219 const NLType *type;
220 int r;
221
6c14ad61
DH
222 assert(m);
223
d8e538ec
TG
224 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
225 if (r < 0)
226 return r;
227
817d1cd8 228 if (type_get_type(type) != data_type)
d8e538ec
TG
229 return -EINVAL;
230
6c14ad61
DH
231 if (out_size)
232 *out_size = type_get_size(type);
233 return 0;
d8e538ec
TG
234}
235
1c4baffc 236int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
d8e538ec 237 size_t length, size;
0a0dc69b 238 int r;
65f568bb
TG
239
240 assert_return(m, -EINVAL);
e5c4350b 241 assert_return(!m->sealed, -EPERM);
65f568bb
TG
242 assert_return(data, -EINVAL);
243
6c14ad61 244 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
0a0dc69b
TG
245 if (r < 0)
246 return r;
65f568bb 247
d8e538ec 248 if (size) {
3072eecf
LP
249 length = strnlen(data, size+1);
250 if (length > size)
d8e538ec
TG
251 return -EINVAL;
252 } else
253 length = strlen(data);
33125ac5 254
d8e538ec 255 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
256 if (r < 0)
257 return r;
258
259 return 0;
260}
261
1c4baffc 262int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
7b179640
SS
263 int r;
264
265 assert_return(m, -EINVAL);
266 assert_return(!m->sealed, -EPERM);
267
6c14ad61 268 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
7b179640
SS
269 if (r < 0)
270 return r;
271
7b179640
SS
272 r = add_rtattr(m, type, &data, sizeof(uint8_t));
273 if (r < 0)
274 return r;
275
276 return 0;
277}
278
279
1c4baffc 280int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
01b36069
TG
281 int r;
282
283 assert_return(m, -EINVAL);
e5c4350b 284 assert_return(!m->sealed, -EPERM);
01b36069 285
6c14ad61 286 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
01b36069
TG
287 if (r < 0)
288 return r;
289
01b36069
TG
290 r = add_rtattr(m, type, &data, sizeof(uint16_t));
291 if (r < 0)
292 return r;
293
294 return 0;
295}
296
1c4baffc 297int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
298 int r;
299
300 assert_return(m, -EINVAL);
e5c4350b 301 assert_return(!m->sealed, -EPERM);
0a0dc69b 302
6c14ad61 303 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
0a0dc69b
TG
304 if (r < 0)
305 return r;
306
4d47756b 307 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
308 if (r < 0)
309 return r;
310
311 return 0;
312}
313
1c4baffc 314int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
0a0dc69b
TG
315 int r;
316
317 assert_return(m, -EINVAL);
e5c4350b 318 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
319 assert_return(data, -EINVAL);
320
6c14ad61 321 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
0a0dc69b
TG
322 if (r < 0)
323 return r;
324
4d47756b 325 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
326 if (r < 0)
327 return r;
328
329 return 0;
330}
331
1c4baffc 332int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
0a0dc69b
TG
333 int r;
334
335 assert_return(m, -EINVAL);
e5c4350b 336 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
337 assert_return(data, -EINVAL);
338
6c14ad61 339 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
0a0dc69b
TG
340 if (r < 0)
341 return r;
342
4d47756b 343 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
344 if (r < 0)
345 return r;
346
347 return 0;
348}
349
1c4baffc 350int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
351 int r;
352
353 assert_return(m, -EINVAL);
e5c4350b 354 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
355 assert_return(data, -EINVAL);
356
6c14ad61 357 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
d8e538ec
TG
358 if (r < 0)
359 return r;
0a0dc69b 360
b9eaf3d1 361 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
362 if (r < 0)
363 return r;
364
365 return 0;
65f568bb
TG
366}
367
1c4baffc 368int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
aba496a5
UTL
369 int r;
370
371 assert_return(m, -EINVAL);
372 assert_return(!m->sealed, -EPERM);
373 assert_return(info, -EINVAL);
374
6c14ad61 375 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
aba496a5
UTL
376 if (r < 0)
377 return r;
378
379 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
380 if (r < 0)
381 return r;
382
383 return 0;
384}
385
1c4baffc 386int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
d8e538ec
TG
387 size_t size;
388 int r;
33125ac5 389
65f568bb 390 assert_return(m, -EINVAL);
e5c4350b 391 assert_return(!m->sealed, -EPERM);
7ca1d319 392 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
33125ac5 393
6c14ad61 394 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
4af7b60d
TG
395 if (r < 0) {
396 const NLTypeSystemUnion *type_system_union;
397 int family;
398
6c14ad61 399 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
4af7b60d
TG
400 if (r < 0)
401 return r;
4af7b60d 402
89489ef7 403 r = sd_rtnl_message_get_family(m, &family);
4af7b60d
TG
404 if (r < 0)
405 return r;
406
407 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
408 if (r < 0)
409 return r;
410
411 r = type_system_union_protocol_get_type_system(type_system_union,
412 &m->container_type_system[m->n_containers + 1],
413 family);
414 if (r < 0)
415 return r;
416 } else {
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
6c14ad61 502 r = message_attribute_has_type(m, NULL, 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
6c14ad61 524 r = message_attribute_has_type(m, NULL, 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
6c14ad61 546 r = message_attribute_has_type(m, NULL, 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
6c14ad61 568 r = message_attribute_has_type(m, NULL, 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
6c14ad61 590 r = message_attribute_has_type(m, NULL, 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
6c14ad61 612 r = message_attribute_has_type(m, NULL, 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
6c14ad61 634 r = message_attribute_has_type(m, NULL, 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
6c14ad61 656 r = message_attribute_has_type(m, NULL, 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
817d1cd8 672int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
d8e538ec
TG
673 const NLType *nl_type;
674 const NLTypeSystem *type_system;
3dd215e0 675 void *container;
817d1cd8 676 uint16_t type;
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,
817d1cd8 685 type_id);
3dd215e0
TG
686 if (r < 0)
687 return r;
3dd215e0 688
817d1cd8
DH
689 type = type_get_type(nl_type);
690
691 if (type == NETLINK_TYPE_NESTED) {
d8e538ec
TG
692 r = type_system_get_type_system(m->container_type_system[m->n_containers],
693 &type_system,
817d1cd8 694 type_id);
d8e538ec
TG
695 if (r < 0)
696 return r;
817d1cd8 697 } else if (type == NETLINK_TYPE_UNION) {
d8e538ec 698 const NLTypeSystemUnion *type_system_union;
d8e538ec
TG
699
700 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
701 &type_system_union,
817d1cd8 702 type_id);
d8e538ec
TG
703 if (r < 0)
704 return r;
705
4af7b60d
TG
706 switch (type_system_union->match_type) {
707 case NL_MATCH_SIBLING:
708 {
709 const char *key;
710
1c4baffc 711 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
4af7b60d
TG
712 if (r < 0)
713 return r;
714
715 r = type_system_union_get_type_system(type_system_union,
716 &type_system,
717 key);
718 if (r < 0)
719 return r;
720
721 break;
722 }
723 case NL_MATCH_PROTOCOL:
724 {
725 int family;
726
89489ef7 727 r = sd_rtnl_message_get_family(m, &family);
4af7b60d
TG
728 if (r < 0)
729 return r;
730
731 r = type_system_union_protocol_get_type_system(type_system_union,
732 &type_system,
733 family);
734 if (r < 0)
735 return r;
736
737 break;
738 }
739 default:
1c4baffc 740 assert_not_reached("sd-netlink: invalid type system union type");
4af7b60d 741 }
d8e538ec
TG
742 } else
743 return -EINVAL;
744
817d1cd8 745 r = rtnl_message_read_internal(m, type_id, &container);
3dd215e0
TG
746 if (r < 0)
747 return r;
d8e538ec
TG
748 else
749 size = (size_t)r;
3dd215e0 750
d8e538ec 751 m->n_containers ++;
3dd215e0
TG
752
753 r = rtnl_message_parse(m,
d8e538ec
TG
754 &m->rta_offset_tb[m->n_containers],
755 &m->rta_tb_size[m->n_containers],
c1df8dee 756 type_system_get_count(type_system),
3dd215e0 757 container,
d8e538ec
TG
758 size);
759 if (r < 0) {
760 m->n_containers --;
3dd215e0 761 return r;
d8e538ec 762 }
3dd215e0 763
d8e538ec 764 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
765
766 return 0;
767}
768
1c4baffc 769int sd_netlink_message_exit_container(sd_netlink_message *m) {
e5c4350b
TG
770 assert_return(m, -EINVAL);
771 assert_return(m->sealed, -EINVAL);
772 assert_return(m->n_containers > 0, -EINVAL);
773
3dd215e0
TG
774 free(m->rta_offset_tb[m->n_containers]);
775 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 776 m->container_type_system[m->n_containers] = NULL;
3dd215e0 777
e5c4350b
TG
778 m->n_containers --;
779
780 return 0;
781}
782
1c4baffc 783uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
65f568bb 784 assert(m);
9d0db178 785 assert(m->hdr);
65f568bb
TG
786
787 return m->hdr->nlmsg_seq;
788}
789
1c4baffc 790int sd_netlink_message_is_error(sd_netlink_message *m) {
45af44d4
TG
791 assert_return(m, 0);
792 assert_return(m->hdr, 0);
793
794 return m->hdr->nlmsg_type == NLMSG_ERROR;
795}
796
1c4baffc 797int sd_netlink_message_get_errno(sd_netlink_message *m) {
65f568bb
TG
798 struct nlmsgerr *err;
799
e16bcf98 800 assert_return(m, -EINVAL);
9d0db178 801 assert_return(m->hdr, -EINVAL);
65f568bb 802
1c4baffc 803 if (!sd_netlink_message_is_error(m))
65f568bb
TG
804 return 0;
805
806 err = NLMSG_DATA(m->hdr);
807
808 return err->error;
809}
810
1c4baffc 811int rtnl_message_parse(sd_netlink_message *m,
44caa5e7
SS
812 size_t **rta_offset_tb,
813 unsigned short *rta_tb_size,
c1df8dee 814 int count,
44caa5e7
SS
815 struct rtattr *rta,
816 unsigned int rt_len) {
e634cd40 817 unsigned short type;
44caa5e7
SS
818 size_t *tb;
819
c1df8dee 820 tb = new0(size_t, count);
44caa5e7
SS
821 if(!tb)
822 return -ENOMEM;
823
c1df8dee 824 *rta_tb_size = count;
44caa5e7
SS
825
826 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
0a2478a9 827 type = RTA_TYPE(rta);
44caa5e7 828
aef0768e
TG
829 /* if the kernel is newer than the headers we used
830 when building, we ignore out-of-range attributes
831 */
c1df8dee 832 if (type >= count)
e634cd40 833 continue;
e634cd40
TG
834
835 if (tb[type])
836 log_debug("rtnl: message parse - overwriting repeated attribute");
837
838 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
839 }
840
841 *rta_offset_tb = tb;
842
843 return 0;
844}
845
1c4baffc 846int sd_netlink_message_rewind(sd_netlink_message *m) {
817d1cd8
DH
847 const NLType *nl_type;
848 uint16_t type;
849 size_t size;
3dd215e0
TG
850 unsigned i;
851 int r;
0fc7531b
TG
852
853 assert_return(m, -EINVAL);
0fc7531b 854
3dd215e0
TG
855 /* don't allow appending to message once parsed */
856 if (!m->sealed)
857 rtnl_message_seal(m);
858
859 for (i = 1; i <= m->n_containers; i++) {
860 free(m->rta_offset_tb[i]);
861 m->rta_offset_tb[i] = NULL;
862 m->rta_tb_size[i] = 0;
d8e538ec 863 m->container_type_system[i] = NULL;
3dd215e0
TG
864 }
865
866 m->n_containers = 0;
867
868 if (m->rta_offset_tb[0]) {
869 /* top-level attributes have already been parsed */
870 return 0;
871 }
872
d8e538ec
TG
873 assert(m->hdr);
874
817d1cd8 875 r = type_system_get_type(NULL, &nl_type, m->hdr->nlmsg_type);
d8e538ec
TG
876 if (r < 0)
877 return r;
878
817d1cd8
DH
879 type = type_get_type(nl_type);
880 size = type_get_size(nl_type);
881
882 if (type == NETLINK_TYPE_NESTED) {
c658008f 883 const NLTypeSystem *type_system;
d8e538ec 884
817d1cd8 885 type_get_type_system(nl_type, &type_system);
d8e538ec
TG
886
887 m->container_type_system[0] = type_system;
888
889 r = rtnl_message_parse(m,
890 &m->rta_offset_tb[m->n_containers],
891 &m->rta_tb_size[m->n_containers],
c1df8dee 892 type_system_get_count(type_system),
817d1cd8
DH
893 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
894 NLMSG_PAYLOAD(m->hdr, size));
d8e538ec
TG
895 if (r < 0)
896 return r;
0fc7531b
TG
897 }
898
899 return 0;
900}
3dd215e0 901
1c4baffc 902void rtnl_message_seal(sd_netlink_message *m) {
3dd215e0
TG
903 assert(m);
904 assert(!m->sealed);
905
906 m->sealed = true;
907}
1403f45a 908
1c4baffc 909sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
1403f45a
TG
910 assert_return(m, NULL);
911
912 return m->next;
913}