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