]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
networkd: add Patch of MTU discovery for IPIP and GRE
[thirdparty/systemd.git] / src / libsystemd / sd-rtnl / rtnl-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>
23#include <netinet/ether.h>
24#include <stdbool.h>
25#include <unistd.h>
26
27#include "util.h"
28#include "refcnt.h"
d5eff740 29#include "missing.h"
65f568bb
TG
30
31#include "sd-rtnl.h"
3815f36f 32#include "rtnl-util.h"
65f568bb 33#include "rtnl-internal.h"
d8e538ec 34#include "rtnl-types.h"
65f568bb 35
31a4e153 36#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
e5c4350b 37#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4ebe732c 38
1b89cf56 39static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) {
65f568bb
TG
40 sd_rtnl_message *m;
41
42 assert_return(ret, -EINVAL);
65f568bb 43
8c578303
TG
44 /* Note that 'rtnl' is curretly unused, if we start using it internally
45 we must take care to avoid problems due to mutual references between
46 busses and their queued messages. See sd-bus.
47 */
48
65f568bb
TG
49 m = new0(sd_rtnl_message, 1);
50 if (!m)
51 return -ENOMEM;
52
65f568bb
TG
53 m->n_ref = REFCNT_INIT;
54
65f568bb
TG
55 m->sealed = false;
56
57 *ret = m;
58
59 return 0;
60}
61
d8e538ec 62int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type) {
1b89cf56 63 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
d8e538ec
TG
64 const NLType *nl_type;
65 size_t size;
66 int r;
67
68 r = type_system_get_type(NULL, &nl_type, type);
69 if (r < 0)
70 return r;
71
72 assert(nl_type->type == NLA_NESTED);
73
1b89cf56 74 r = message_new_empty(rtnl, &m);
d8e538ec
TG
75 if (r < 0)
76 return r;
77
1b89cf56
TG
78 size = NLMSG_SPACE(nl_type->size);
79
80 assert(size >= sizeof(struct nlmsghdr));
81 m->hdr = malloc0(size);
82 if (!m->hdr)
83 return -ENOMEM;
84
85 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
86
87 m->container_type_system[0] = nl_type->type_system;
88 m->hdr->nlmsg_len = size;
89 m->hdr->nlmsg_type = type;
90
91 *ret = m;
92 m = NULL;
d8e538ec
TG
93
94 return 0;
95}
96
1f01fb4f
TG
97int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
98 struct rtmsg *rtm;
99
5a723174
TG
100 assert_return(m, -EINVAL);
101 assert_return(m->hdr, -EINVAL);
3815f36f 102 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
5a723174 103
1f01fb4f
TG
104 rtm = NLMSG_DATA(m->hdr);
105
5a723174
TG
106 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
107 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
108 return -ERANGE;
109
1f01fb4f
TG
110 rtm->rtm_dst_len = prefixlen;
111
5c1d3fc9
UTL
112 return 0;
113}
114
115int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
116 struct rtmsg *rtm;
117
118 assert_return(m, -EINVAL);
119 assert_return(m->hdr, -EINVAL);
120 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
121
122 rtm = NLMSG_DATA(m->hdr);
123
124 rtm->rtm_scope = scope;
125
1f01fb4f
TG
126 return 0;
127}
128
151b9b96 129int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
28cc555d
DW
130 uint16_t nlmsg_type, int rtm_family,
131 unsigned char rtm_protocol) {
03d7e632
TG
132 struct rtmsg *rtm;
133 int r;
134
3815f36f 135 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
1f01fb4f 136 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
03d7e632
TG
137 assert_return(ret, -EINVAL);
138
d8e538ec 139 r = message_new(rtnl, ret, nlmsg_type);
03d7e632
TG
140 if (r < 0)
141 return r;
142
03d7e632 143 if (nlmsg_type == RTM_NEWROUTE)
3f781aa8 144 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
03d7e632
TG
145
146 rtm = NLMSG_DATA((*ret)->hdr);
147
148 rtm->rtm_family = rtm_family;
1f01fb4f
TG
149 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
150 rtm->rtm_type = RTN_UNICAST;
151 rtm->rtm_table = RT_TABLE_MAIN;
28cc555d 152 rtm->rtm_protocol = rtm_protocol;
03d7e632
TG
153
154 return 0;
155}
156
5d4795f3 157int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
fc25d7f8
TG
158 struct ifinfomsg *ifi;
159
5a723174
TG
160 assert_return(m, -EINVAL);
161 assert_return(m->hdr, -EINVAL);
3815f36f 162 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
a7b74db6 163 assert_return(change, -EINVAL);
5a723174 164
fc25d7f8
TG
165 ifi = NLMSG_DATA(m->hdr);
166
167 ifi->ifi_flags = flags;
a7b74db6 168 ifi->ifi_change = change;
fc25d7f8
TG
169
170 return 0;
171}
172
173int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
174 struct ifinfomsg *ifi;
175
5a723174
TG
176 assert_return(m, -EINVAL);
177 assert_return(m->hdr, -EINVAL);
3815f36f 178 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
5a723174 179
fc25d7f8
TG
180 ifi = NLMSG_DATA(m->hdr);
181
182 ifi->ifi_type = type;
183
184 return 0;
185}
186
151b9b96
LP
187int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
188 uint16_t nlmsg_type, int index) {
65f568bb
TG
189 struct ifinfomsg *ifi;
190 int r;
191
3815f36f 192 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
6a8402d9 193 assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
65f568bb
TG
194 assert_return(ret, -EINVAL);
195
d8e538ec 196 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
197 if (r < 0)
198 return r;
199
33125ac5 200 if (nlmsg_type == RTM_NEWLINK)
6a8402d9 201 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
65f568bb 202
dabfa9d1 203 ifi = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
204
205 ifi->ifi_family = AF_UNSPEC;
206 ifi->ifi_index = index;
65f568bb
TG
207
208 return 0;
209}
210
6e20c8f8
TG
211int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) {
212 assert_return(m, -EINVAL);
213 assert_return(m->hdr, -EINVAL);
214 assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
215 m->hdr->nlmsg_type == RTM_GETADDR ||
216 m->hdr->nlmsg_type == RTM_GETROUTE,
217 -EINVAL);
218
219 if (dump)
220 m->hdr->nlmsg_flags |= NLM_F_DUMP;
221 else
222 m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
223
224 return 0;
225}
226
5a723174
TG
227int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
228 struct ifaddrmsg *ifa;
229
230 assert_return(m, -EINVAL);
231 assert_return(m->hdr, -EINVAL);
3815f36f 232 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
233
234 ifa = NLMSG_DATA(m->hdr);
235
236 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
237 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
238 return -ERANGE;
239
240 ifa->ifa_prefixlen = prefixlen;
241
242 return 0;
243}
244
245int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
246 struct ifaddrmsg *ifa;
247
248 assert_return(m, -EINVAL);
249 assert_return(m->hdr, -EINVAL);
3815f36f 250 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
251
252 ifa = NLMSG_DATA(m->hdr);
253
254 ifa->ifa_flags = flags;
255
256 return 0;
257}
258
259int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
260 struct ifaddrmsg *ifa;
261
262 assert_return(m, -EINVAL);
263 assert_return(m->hdr, -EINVAL);
3815f36f 264 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
265
266 ifa = NLMSG_DATA(m->hdr);
267
268 ifa->ifa_scope = scope;
269
270 return 0;
271}
272
0dd25fb9 273int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, int *family) {
e00d77dd
TG
274 struct ifaddrmsg *ifa;
275
276 assert_return(m, -EINVAL);
277 assert_return(m->hdr, -EINVAL);
278 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
279 assert_return(family, -EINVAL);
280
281 ifa = NLMSG_DATA(m->hdr);
282
283 *family = ifa->ifa_family;
284
285 return 0;
286}
287
f4e884dd
TG
288int sd_rtnl_message_addr_get_prefixlen(sd_rtnl_message *m, unsigned char *prefixlen) {
289 struct ifaddrmsg *ifa;
290
291 assert_return(m, -EINVAL);
292 assert_return(m->hdr, -EINVAL);
293 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
294 assert_return(prefixlen, -EINVAL);
295
296 ifa = NLMSG_DATA(m->hdr);
297
298 *prefixlen = ifa->ifa_prefixlen;
299
300 return 0;
301}
302
e00d77dd
TG
303int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) {
304 struct ifaddrmsg *ifa;
305
306 assert_return(m, -EINVAL);
307 assert_return(m->hdr, -EINVAL);
308 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
309 assert_return(scope, -EINVAL);
310
311 ifa = NLMSG_DATA(m->hdr);
312
313 *scope = ifa->ifa_scope;
314
315 return 0;
316}
317
318int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags) {
319 struct ifaddrmsg *ifa;
320
321 assert_return(m, -EINVAL);
322 assert_return(m->hdr, -EINVAL);
323 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
324 assert_return(flags, -EINVAL);
325
326 ifa = NLMSG_DATA(m->hdr);
327
328 *flags = ifa->ifa_flags;
329
330 return 0;
331}
332
333int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex) {
334 struct ifaddrmsg *ifa;
335
336 assert_return(m, -EINVAL);
337 assert_return(m->hdr, -EINVAL);
338 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
339 assert_return(ifindex, -EINVAL);
340
341 ifa = NLMSG_DATA(m->hdr);
342
343 *ifindex = ifa->ifa_index;
344
345 return 0;
346}
347
151b9b96
LP
348int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
349 uint16_t nlmsg_type, int index,
0dd25fb9 350 int family) {
65f568bb
TG
351 struct ifaddrmsg *ifa;
352 int r;
353
3815f36f 354 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
b9ef681b
TG
355 assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
356 index > 0, -EINVAL);
357 assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
358 family == AF_INET || family == AF_INET6, -EINVAL);
65f568bb
TG
359 assert_return(ret, -EINVAL);
360
d8e538ec 361 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
362 if (r < 0)
363 return r;
364
b9ef681b 365 if (nlmsg_type == RTM_GETADDR)
818dc5e7 366 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
65f568bb 367
dabfa9d1 368 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb 369
65f568bb 370 ifa->ifa_index = index;
5a723174
TG
371 ifa->ifa_family = family;
372 if (family == AF_INET)
373 ifa->ifa_prefixlen = 32;
374 else if (family == AF_INET6)
375 ifa->ifa_prefixlen = 128;
65f568bb
TG
376
377 return 0;
378}
379
aba496a5 380int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
0dd25fb9 381 int index, int family) {
aba496a5
UTL
382 int r;
383
384 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
385 if (r < 0)
386 return r;
387
388 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
389
390 return 0;
391}
392
65f568bb
TG
393sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
394 if (m)
395 assert_se(REFCNT_INC(m->n_ref) >= 2);
396
397 return m;
398}
399
400sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
401 if (m && REFCNT_DEC(m->n_ref) <= 0) {
3dd215e0
TG
402 unsigned i;
403
65f568bb 404 free(m->hdr);
3dd215e0 405
9f5bbfe3 406 for (i = 0; i <= m->n_containers; i++)
3dd215e0
TG
407 free(m->rta_offset_tb[i]);
408
1403f45a
TG
409 sd_rtnl_message_unref(m->next);
410
65f568bb
TG
411 free(m);
412 }
413
414 return NULL;
415}
416
dabfa9d1 417int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
65f568bb
TG
418 assert_return(m, -EINVAL);
419 assert_return(type, -EINVAL);
420
421 *type = m->hdr->nlmsg_type;
422
423 return 0;
424}
425
1f0db3ed
TG
426int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
427 assert_return(m, -EINVAL);
428
429 return !m->hdr->nlmsg_pid;
430}
431
33125ac5
TG
432int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
433 struct ifinfomsg *ifi;
434
435 assert_return(m, -EINVAL);
9d0db178 436 assert_return(m->hdr, -EINVAL);
3815f36f 437 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 438 assert_return(ifindex, -EINVAL);
33125ac5
TG
439
440 ifi = NLMSG_DATA(m->hdr);
441
442 *ifindex = ifi->ifi_index;
443
444 return 0;
445}
446
50b3c42f
TG
447int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
448 struct ifinfomsg *ifi;
449
450 assert_return(m, -EINVAL);
9d0db178 451 assert_return(m->hdr, -EINVAL);
3815f36f 452 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 453 assert_return(flags, -EINVAL);
50b3c42f
TG
454
455 ifi = NLMSG_DATA(m->hdr);
456
457 *flags = ifi->ifi_flags;
458
459 return 0;
460}
461
ee8c4568
LP
462int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type) {
463 struct ifinfomsg *ifi;
464
465 assert_return(m, -EINVAL);
466 assert_return(m->hdr, -EINVAL);
467 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
468 assert_return(type, -EINVAL);
469
470 ifi = NLMSG_DATA(m->hdr);
471
472 *type = ifi->ifi_type;
473
474 return 0;
475}
476
4ebe732c
ZJS
477/* If successful the updated message will be correctly aligned, if
478 unsuccessful the old message is untouched. */
65f568bb 479static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
7ca1d319
TG
480 uint32_t rta_length;
481 size_t message_length, padding_length;
65f568bb
TG
482 struct nlmsghdr *new_hdr;
483 struct rtattr *rta;
8e337e64 484 char *padding;
5a081409 485 unsigned i;
7ca1d319 486 int offset;
65f568bb 487
33125ac5
TG
488 assert(m);
489 assert(m->hdr);
e5c4350b 490 assert(!m->sealed);
33125ac5 491 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
7ca1d319
TG
492 assert(!data || data_length);
493
494 /* get offset of the new attribute */
495 offset = m->hdr->nlmsg_len;
65f568bb 496
8e337e64 497 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 498 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
499
500 /* get the new message size (with padding at the end) */
7ca1d319 501 message_length = offset + RTA_ALIGN(rta_length);
65f568bb
TG
502
503 /* realloc to fit the new attribute */
504 new_hdr = realloc(m->hdr, message_length);
505 if (!new_hdr)
506 return -ENOMEM;
507 m->hdr = new_hdr;
508
509 /* get pointer to the attribute we are about to add */
7ca1d319 510 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
65f568bb 511
5a081409
TG
512 /* if we are inside containers, extend them */
513 for (i = 0; i < m->n_containers; i++)
7ca1d319 514 GET_CONTAINER(m, i)->rta_len += message_length - offset;
33125ac5 515
65f568bb
TG
516 /* fill in the attribute */
517 rta->rta_type = type;
518 rta->rta_len = rta_length;
7ca1d319 519 if (data)
33125ac5
TG
520 /* we don't deal with the case where the user lies about the type
521 * and gives us too little data (so don't do that)
7ca1d319 522 */
33125ac5 523 padding = mempcpy(RTA_DATA(rta), data, data_length);
7ca1d319
TG
524 else {
525 /* if no data was passed, make sure we still initialize the padding
526 note that we can have data_length > 0 (used by some containers) */
527 padding = RTA_DATA(rta);
33125ac5 528 }
65f568bb 529
7ca1d319
TG
530 /* make sure also the padding at the end of the message is initialized */
531 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
532 memzero(padding, padding_length);
533
4ebe732c
ZJS
534 /* update message size */
535 m->hdr->nlmsg_len = message_length;
536
7ca1d319 537 return offset;
65f568bb
TG
538}
539
d8e538ec
TG
540static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
541 const NLType *type;
542 int r;
543
544 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
545 if (r < 0)
546 return r;
547
548 if (type->type != data_type)
549 return -EINVAL;
550
551 return type->size;
552}
553
0a0dc69b 554int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
d8e538ec 555 size_t length, size;
0a0dc69b 556 int r;
65f568bb
TG
557
558 assert_return(m, -EINVAL);
e5c4350b 559 assert_return(!m->sealed, -EPERM);
65f568bb
TG
560 assert_return(data, -EINVAL);
561
d8e538ec 562 r = message_attribute_has_type(m, type, NLA_STRING);
0a0dc69b
TG
563 if (r < 0)
564 return r;
d8e538ec
TG
565 else
566 size = (size_t)r;
65f568bb 567
d8e538ec
TG
568 if (size) {
569 length = strnlen(data, size);
570 if (length >= size)
571 return -EINVAL;
572 } else
573 length = strlen(data);
33125ac5 574
d8e538ec 575 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
576 if (r < 0)
577 return r;
578
579 return 0;
580}
581
7b179640 582int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
7b179640
SS
583 int r;
584
585 assert_return(m, -EINVAL);
586 assert_return(!m->sealed, -EPERM);
587
d8e538ec 588 r = message_attribute_has_type(m, type, NLA_U8);
7b179640
SS
589 if (r < 0)
590 return r;
591
7b179640
SS
592 r = add_rtattr(m, type, &data, sizeof(uint8_t));
593 if (r < 0)
594 return r;
595
596 return 0;
597}
598
599
01b36069 600int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
01b36069
TG
601 int r;
602
603 assert_return(m, -EINVAL);
e5c4350b 604 assert_return(!m->sealed, -EPERM);
01b36069 605
d8e538ec 606 r = message_attribute_has_type(m, type, NLA_U16);
01b36069
TG
607 if (r < 0)
608 return r;
609
01b36069
TG
610 r = add_rtattr(m, type, &data, sizeof(uint16_t));
611 if (r < 0)
612 return r;
613
614 return 0;
615}
616
0a0dc69b 617int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
618 int r;
619
620 assert_return(m, -EINVAL);
e5c4350b 621 assert_return(!m->sealed, -EPERM);
0a0dc69b 622
d8e538ec 623 r = message_attribute_has_type(m, type, NLA_U32);
0a0dc69b
TG
624 if (r < 0)
625 return r;
626
4d47756b 627 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
628 if (r < 0)
629 return r;
630
631 return 0;
632}
633
634int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
0a0dc69b
TG
635 int r;
636
637 assert_return(m, -EINVAL);
e5c4350b 638 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
639 assert_return(data, -EINVAL);
640
d8e538ec 641 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
642 if (r < 0)
643 return r;
644
4d47756b 645 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
646 if (r < 0)
647 return r;
648
649 return 0;
650}
651
652int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
0a0dc69b
TG
653 int r;
654
655 assert_return(m, -EINVAL);
e5c4350b 656 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
657 assert_return(data, -EINVAL);
658
d8e538ec 659 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
660 if (r < 0)
661 return r;
662
4d47756b 663 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
664 if (r < 0)
665 return r;
666
667 return 0;
668}
669
670int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
671 int r;
672
673 assert_return(m, -EINVAL);
e5c4350b 674 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
675 assert_return(data, -EINVAL);
676
d8e538ec
TG
677 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
678 if (r < 0)
679 return r;
0a0dc69b 680
b9eaf3d1 681 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
682 if (r < 0)
683 return r;
684
685 return 0;
65f568bb
TG
686}
687
aba496a5
UTL
688int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
689 int r;
690
691 assert_return(m, -EINVAL);
692 assert_return(!m->sealed, -EPERM);
693 assert_return(info, -EINVAL);
694
695 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
696 if (r < 0)
697 return r;
698
699 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
700 if (r < 0)
701 return r;
702
703 return 0;
704}
705
ee3a6a51 706int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
707 size_t size;
708 int r;
33125ac5 709
65f568bb 710 assert_return(m, -EINVAL);
e5c4350b 711 assert_return(!m->sealed, -EPERM);
7ca1d319 712 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
33125ac5 713
d8e538ec
TG
714 r = message_attribute_has_type(m, type, NLA_NESTED);
715 if (r < 0)
716 return r;
717 else
718 size = (size_t)r;
33125ac5 719
d8e538ec
TG
720 r = type_system_get_type_system(m->container_type_system[m->n_containers],
721 &m->container_type_system[m->n_containers + 1],
722 type);
723 if (r < 0)
724 return r;
31a4e153 725
d8e538ec
TG
726 r = add_rtattr(m, type, NULL, size);
727 if (r < 0)
728 return r;
729
7ca1d319
TG
730 m->container_offsets[m->n_containers ++] = r;
731
d8e538ec
TG
732 return 0;
733}
734
735int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
736 const NLTypeSystemUnion *type_system_union;
737 int r;
738
739 assert_return(m, -EINVAL);
740 assert_return(!m->sealed, -EPERM);
741
742 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
743 if (r < 0)
744 return r;
745
746 r = type_system_union_get_type_system(type_system_union,
747 &m->container_type_system[m->n_containers + 1],
748 key);
749 if (r < 0)
750 return r;
33125ac5 751
d8e538ec
TG
752 r = sd_rtnl_message_append_string(m, type_system_union->match, key);
753 if (r < 0)
754 return r;
755
756 /* do we evere need non-null size */
757 r = add_rtattr(m, type, NULL, 0);
758 if (r < 0)
759 return r;
760
7ca1d319
TG
761 m->container_offsets[m->n_containers ++] = r;
762
d8e538ec 763 return 0;
33125ac5
TG
764}
765
d8e538ec 766
33125ac5
TG
767int sd_rtnl_message_close_container(sd_rtnl_message *m) {
768 assert_return(m, -EINVAL);
e5c4350b 769 assert_return(!m->sealed, -EPERM);
5a081409 770 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 771
d8e538ec 772 m->container_type_system[m->n_containers] = NULL;
5a081409 773 m->n_containers --;
33125ac5
TG
774
775 return 0;
776}
777
44caa5e7 778int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
f66eeb6b
TG
779 struct rtattr *rta;
780
44caa5e7
SS
781 assert_return(m, -EINVAL);
782 assert_return(m->sealed, -EPERM);
783 assert_return(data, -EINVAL);
d8e538ec
TG
784 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
785 assert(m->rta_offset_tb[m->n_containers]);
786 assert(type < m->rta_tb_size[m->n_containers]);
44caa5e7 787
3dd215e0 788 if(!m->rta_offset_tb[m->n_containers][type])
44caa5e7
SS
789 return -ENODATA;
790
3dd215e0 791 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
44caa5e7 792
f66eeb6b
TG
793 *data = RTA_DATA(rta);
794
795 return RTA_PAYLOAD(rta);
44caa5e7
SS
796}
797
ca4e095a 798int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const char **data) {
44caa5e7
SS
799 int r;
800 void *attr_data;
801
d8e538ec
TG
802 r = message_attribute_has_type(m, type, NLA_STRING);
803 if (r < 0)
804 return r;
44caa5e7
SS
805
806 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 807 if (r < 0)
44caa5e7 808 return r;
f66eeb6b
TG
809 else if (strnlen(attr_data, r) >= (size_t) r)
810 return -EIO;
44caa5e7 811
ca4e095a 812 *data = (const char *) attr_data;
44caa5e7
SS
813
814 return 0;
815}
816
817int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
818 int r;
819 void *attr_data;
820
d8e538ec
TG
821 r = message_attribute_has_type(m, type, NLA_U8);
822 if (r < 0)
823 return r;
44caa5e7
SS
824
825 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 826 if (r < 0)
44caa5e7 827 return r;
f66eeb6b
TG
828 else if ((size_t) r < sizeof(uint8_t))
829 return -EIO;
44caa5e7
SS
830
831 *data = *(uint8_t *) attr_data;
832
833 return 0;
834}
835
836int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
837 int r;
838 void *attr_data;
839
d8e538ec
TG
840 r = message_attribute_has_type(m, type, NLA_U16);
841 if (r < 0)
842 return r;
44caa5e7
SS
843
844 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 845 if (r < 0)
44caa5e7 846 return r;
f66eeb6b
TG
847 else if ((size_t) r < sizeof(uint16_t))
848 return -EIO;
44caa5e7
SS
849
850 *data = *(uint16_t *) attr_data;
851
852 return 0;
853}
854
855int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
856 int r;
857 void *attr_data;
858
d8e538ec
TG
859 r = message_attribute_has_type(m, type, NLA_U32);
860 if (r < 0)
861 return r;
44caa5e7
SS
862
863 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 864 if (r < 0)
44caa5e7 865 return r;
f66eeb6b
TG
866 else if ((size_t)r < sizeof(uint32_t))
867 return -EIO;
44caa5e7
SS
868
869 *data = *(uint32_t *) attr_data;
870
871 return 0;
872}
873
4e9e7f18
SS
874int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
875 int r;
876 void *attr_data;
877
d8e538ec
TG
878 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
879 if (r < 0)
880 return r;
4e9e7f18
SS
881
882 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 883 if (r < 0)
4e9e7f18 884 return r;
f66eeb6b
TG
885 else if ((size_t)r < sizeof(struct ether_addr))
886 return -EIO;
4e9e7f18
SS
887
888 memcpy(data, attr_data, sizeof(struct ether_addr));
889
890 return 0;
891}
892
aba496a5
UTL
893int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
894 int r;
895 void *attr_data;
896
897 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
898 if (r < 0)
899 return r;
900
901 r = rtnl_message_read_internal(m, type, &attr_data);
902 if (r < 0)
903 return r;
904 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
905 return -EIO;
906
907 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
908
909 return 0;
910}
911
4e9e7f18
SS
912int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
913 int r;
914 void *attr_data;
915
d8e538ec
TG
916 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
917 if (r < 0)
918 return r;
4e9e7f18
SS
919
920 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 921 if (r < 0)
4e9e7f18 922 return r;
f66eeb6b
TG
923 else if ((size_t)r < sizeof(struct in_addr))
924 return -EIO;
4e9e7f18
SS
925
926 memcpy(data, attr_data, sizeof(struct in_addr));
927
928 return 0;
929}
930
931int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
932 int r;
933 void *attr_data;
934
d8e538ec
TG
935 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
936 if (r < 0)
937 return r;
4e9e7f18
SS
938
939 r = rtnl_message_read_internal(m, type, &attr_data);
3dd215e0 940 if (r < 0)
4e9e7f18 941 return r;
3dd215e0
TG
942 else if ((size_t)r < sizeof(struct in6_addr))
943 return -EIO;
4e9e7f18
SS
944
945 memcpy(data, attr_data, sizeof(struct in6_addr));
946
947 return 0;
948}
949
3dd215e0 950int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
951 const NLType *nl_type;
952 const NLTypeSystem *type_system;
3dd215e0 953 void *container;
d8e538ec
TG
954 size_t size;
955 int r;
3dd215e0
TG
956
957 assert_return(m, -EINVAL);
958 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
959
d8e538ec
TG
960 r = type_system_get_type(m->container_type_system[m->n_containers],
961 &nl_type,
962 type);
3dd215e0
TG
963 if (r < 0)
964 return r;
3dd215e0 965
d8e538ec
TG
966 if (nl_type->type == NLA_NESTED) {
967 r = type_system_get_type_system(m->container_type_system[m->n_containers],
968 &type_system,
969 type);
970 if (r < 0)
971 return r;
972 } else if (nl_type->type == NLA_UNION) {
973 const NLTypeSystemUnion *type_system_union;
ca4e095a 974 const char *key;
d8e538ec
TG
975
976 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
977 &type_system_union,
978 type);
979 if (r < 0)
980 return r;
981
982 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
983 if (r < 0)
984 return r;
985
986 r = type_system_union_get_type_system(type_system_union,
987 &type_system,
988 key);
989 if (r < 0)
990 return r;
991 } else
992 return -EINVAL;
993
994 r = rtnl_message_read_internal(m, type, &container);
3dd215e0
TG
995 if (r < 0)
996 return r;
d8e538ec
TG
997 else
998 size = (size_t)r;
3dd215e0 999
d8e538ec 1000 m->n_containers ++;
3dd215e0
TG
1001
1002 r = rtnl_message_parse(m,
d8e538ec
TG
1003 &m->rta_offset_tb[m->n_containers],
1004 &m->rta_tb_size[m->n_containers],
1005 type_system->max,
3dd215e0 1006 container,
d8e538ec
TG
1007 size);
1008 if (r < 0) {
1009 m->n_containers --;
3dd215e0 1010 return r;
d8e538ec 1011 }
3dd215e0 1012
d8e538ec 1013 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
1014
1015 return 0;
1016}
1017
e5c4350b
TG
1018int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
1019 assert_return(m, -EINVAL);
1020 assert_return(m->sealed, -EINVAL);
1021 assert_return(m->n_containers > 0, -EINVAL);
1022
3dd215e0
TG
1023 free(m->rta_offset_tb[m->n_containers]);
1024 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 1025 m->container_type_system[m->n_containers] = NULL;
3dd215e0 1026
e5c4350b
TG
1027 m->n_containers --;
1028
1029 return 0;
1030}
1031
3815f36f 1032uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 1033 assert(m);
9d0db178 1034 assert(m->hdr);
65f568bb
TG
1035
1036 return m->hdr->nlmsg_seq;
1037}
1038
e16bcf98 1039int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
1040 struct nlmsgerr *err;
1041
e16bcf98 1042 assert_return(m, -EINVAL);
9d0db178 1043 assert_return(m->hdr, -EINVAL);
65f568bb
TG
1044
1045 if (m->hdr->nlmsg_type != NLMSG_ERROR)
1046 return 0;
1047
1048 err = NLMSG_DATA(m->hdr);
1049
1050 return err->error;
1051}
1052
44caa5e7
SS
1053int rtnl_message_parse(sd_rtnl_message *m,
1054 size_t **rta_offset_tb,
1055 unsigned short *rta_tb_size,
1056 int max,
1057 struct rtattr *rta,
1058 unsigned int rt_len) {
e634cd40 1059 unsigned short type;
44caa5e7
SS
1060 size_t *tb;
1061
c8a7165f 1062 tb = new0(size_t, max + 1);
44caa5e7
SS
1063 if(!tb)
1064 return -ENOMEM;
1065
c8a7165f 1066 *rta_tb_size = max + 1;
44caa5e7
SS
1067
1068 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
1069 type = rta->rta_type;
1070
aef0768e
TG
1071 /* if the kernel is newer than the headers we used
1072 when building, we ignore out-of-range attributes
1073 */
1074 if (type > max)
e634cd40 1075 continue;
e634cd40
TG
1076
1077 if (tb[type])
1078 log_debug("rtnl: message parse - overwriting repeated attribute");
1079
1080 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
1081 }
1082
1083 *rta_offset_tb = tb;
1084
1085 return 0;
1086}
1087
65f568bb
TG
1088/* returns the number of bytes sent, or a negative error code */
1089int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
1090 union {
1091 struct sockaddr sa;
1092 struct sockaddr_nl nl;
1093 } addr = {
1094 .nl.nl_family = AF_NETLINK,
1095 };
65f568bb
TG
1096 ssize_t k;
1097
9d0db178
TG
1098 assert(nl);
1099 assert(m);
1100 assert(m->hdr);
65f568bb
TG
1101
1102 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1103 0, &addr.sa, sizeof(addr));
65f568bb
TG
1104 if (k < 0)
1105 return (errno == EAGAIN) ? 0 : -errno;
1106
1107 return k;
1108}
1109
66269b05
TG
1110static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
1111 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred)) +
1112 CMSG_SPACE(sizeof(struct nl_pktinfo))];
bc078e71 1113 struct msghdr msg = {
26349add 1114 .msg_iov = iov,
bc078e71
TG
1115 .msg_iovlen = 1,
1116 .msg_control = cred_buffer,
1117 .msg_controllen = sizeof(cred_buffer),
1118 };
1119 struct cmsghdr *cmsg;
66269b05 1120 uint32_t group = 0;
26349add 1121 bool auth = false;
4e996881 1122 int r;
d4bbdb77 1123
26349add
TG
1124 assert(fd >= 0);
1125 assert(iov);
bc078e71 1126
26349add 1127 r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
5968b1c3 1128 if (r < 0) {
bc078e71 1129 /* no data */
5968b1c3
TG
1130 if (errno == ENOBUFS)
1131 log_debug("rtnl: kernel receive buffer overrun");
1132
bc078e71 1133 return (errno == EAGAIN) ? 0 : -errno;
5968b1c3 1134 } else if (r == 0)
bc078e71
TG
1135 /* connection was closed by the kernel */
1136 return -ECONNRESET;
3dd215e0 1137
bc078e71
TG
1138 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1139 if (cmsg->cmsg_level == SOL_SOCKET &&
1140 cmsg->cmsg_type == SCM_CREDENTIALS &&
1141 cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
1142 struct ucred *ucred = (void *)CMSG_DATA(cmsg);
1143
1144 /* from the kernel */
66269b05 1145 if (ucred->uid == 0 && ucred->pid == 0)
bc078e71 1146 auth = true;
66269b05
TG
1147 } else if (cmsg->cmsg_level == SOL_NETLINK &&
1148 cmsg->cmsg_type == NETLINK_PKTINFO &&
1149 cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
1150 struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
1151
1152 /* multi-cast group */
1153 group = pktinfo->group;
bc078e71
TG
1154 }
1155 }
1156
1157 if (!auth)
1158 /* not from the kernel, ignore */
1159 return 0;
1160
66269b05
TG
1161 if (group)
1162 *_group = group;
1163
26349add
TG
1164 return r;
1165}
1166
1167/* On success, the number of bytes received is returned and *ret points to the received message
1168 * which has a valid header and the correct size.
1169 * If nothing useful was received 0 is returned.
1170 * On failure, a negative error code is returned.
1171 */
1172int socket_read_message(sd_rtnl *rtnl) {
1173 _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
1174 struct iovec iov = {};
66269b05 1175 uint32_t group = 0;
26349add
TG
1176 bool multi_part = false, done = false;
1177 struct nlmsghdr *new_msg;
1178 size_t len;
1179 int r;
1180 unsigned i = 0;
1181
1182 assert(rtnl);
1183 assert(rtnl->rbuffer);
1184 assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
1185
1186 /* read nothing, just get the pending message size */
66269b05 1187 r = socket_recv_message(rtnl->fd, &iov, &group, true);
26349add
TG
1188 if (r <= 0)
1189 return r;
1190 else
1191 len = (size_t)r;
1192
1193 /* make room for the pending message */
1194 if (!greedy_realloc((void **)&rtnl->rbuffer,
1195 &rtnl->rbuffer_allocated,
1196 len, sizeof(uint8_t)))
1197 return -ENOMEM;
1198
1199 iov.iov_base = rtnl->rbuffer;
1200 iov.iov_len = rtnl->rbuffer_allocated;
1201
1202 /* read the pending message */
66269b05 1203 r = socket_recv_message(rtnl->fd, &iov, &group, false);
26349add
TG
1204 if (r <= 0)
1205 return r;
1206 else
1207 len = (size_t)r;
1208
127dc4ea
TG
1209 if (len > rtnl->rbuffer_allocated)
1210 /* message did not fit in read buffer */
1211 return -EIO;
1212
4e996881
TG
1213 if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
1214 multi_part = true;
1215
1216 for (i = 0; i < rtnl->rqueue_partial_size; i++) {
1217 if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
1218 rtnl->rbuffer->nlmsg_seq) {
1219 first = rtnl->rqueue_partial[i];
1220 break;
1221 }
1222 }
1223 }
1224
a88f77c4 1225 for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
1b89cf56
TG
1226 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1227 const NLType *nl_type;
3dd215e0 1228
8fe65c03 1229 if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
1b89cf56
TG
1230 /* not broadcast and not for us */
1231 continue;
3dd215e0 1232
1b89cf56 1233 if (new_msg->nlmsg_type == NLMSG_NOOP)
4e996881 1234 /* silently drop noop messages */
1b89cf56 1235 continue;
bdd13f6b 1236
4e996881
TG
1237 if (new_msg->nlmsg_type == NLMSG_DONE) {
1238 /* finished reading multi-part message */
1239 done = true;
1403f45a 1240 break;
4e996881 1241 }
1403f45a 1242
1b89cf56
TG
1243 /* check that we support this message type */
1244 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
1245 if (r < 0) {
1246 if (r == -ENOTSUP)
1247 log_debug("sd-rtnl: ignored message with unknown type: %u",
1248 new_msg->nlmsg_type);
d8e538ec 1249
1b89cf56
TG
1250 continue;
1251 }
bdd13f6b 1252
1b89cf56
TG
1253 /* check that the size matches the message type */
1254 if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size))
1255 continue;
65f568bb 1256
1b89cf56
TG
1257 r = message_new_empty(rtnl, &m);
1258 if (r < 0)
1259 return r;
1260
1261 m->hdr = memdup(new_msg, new_msg->nlmsg_len);
1262 if (!m->hdr)
1263 return -ENOMEM;
1264
1265 /* seal and parse the top-level message */
1266 r = sd_rtnl_message_rewind(m);
1267 if (r < 0)
1268 return r;
1269
4e996881
TG
1270 /* push the message onto the multi-part message stack */
1271 if (first)
1272 m->next = first;
1273 first = m;
1b89cf56 1274 m = NULL;
4e996881 1275 }
1403f45a 1276
4e996881
TG
1277 if (len)
1278 log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
1b89cf56 1279
4e996881
TG
1280 if (!first)
1281 return 0;
65f568bb 1282
4e996881
TG
1283 if (!multi_part || done) {
1284 /* we got a complete message, push it on the read queue */
24a02673
TG
1285 r = rtnl_rqueue_make_room(rtnl);
1286 if (r < 0)
1287 return r;
1288
d4ef4f46
TG
1289 rtnl->rqueue[rtnl->rqueue_size ++] = first;
1290 first = NULL;
1291
1292 if (multi_part && (i < rtnl->rqueue_partial_size)) {
4e996881
TG
1293 /* remove the message form the partial read queue */
1294 memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
1295 sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
1296 rtnl->rqueue_partial_size --;
1297 }
1298
4e996881
TG
1299 return 1;
1300 } else {
1301 /* we only got a partial multi-part message, push it on the
1302 partial read queue */
1303 if (i < rtnl->rqueue_partial_size) {
1304 rtnl->rqueue_partial[i] = first;
1305 } else {
1306 r = rtnl_rqueue_partial_make_room(rtnl);
1307 if (r < 0)
1308 return r;
1309
1310 rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
1311 }
1312 first = NULL;
1403f45a 1313
4e996881
TG
1314 return 0;
1315 }
65f568bb 1316}
0fc7531b
TG
1317
1318int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1319 const NLType *type;
3dd215e0
TG
1320 unsigned i;
1321 int r;
0fc7531b
TG
1322
1323 assert_return(m, -EINVAL);
0fc7531b 1324
3dd215e0
TG
1325 /* don't allow appending to message once parsed */
1326 if (!m->sealed)
1327 rtnl_message_seal(m);
1328
1329 for (i = 1; i <= m->n_containers; i++) {
1330 free(m->rta_offset_tb[i]);
1331 m->rta_offset_tb[i] = NULL;
1332 m->rta_tb_size[i] = 0;
d8e538ec 1333 m->container_type_system[i] = NULL;
3dd215e0
TG
1334 }
1335
1336 m->n_containers = 0;
1337
1338 if (m->rta_offset_tb[0]) {
1339 /* top-level attributes have already been parsed */
1340 return 0;
1341 }
1342
d8e538ec
TG
1343 assert(m->hdr);
1344
1345 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1346 if (r < 0)
1347 return r;
1348
1349 if (type->type == NLA_NESTED) {
1350 const NLTypeSystem *type_system = type->type_system;
1351
1352 assert(type_system);
1353
1354 m->container_type_system[0] = type_system;
1355
1356 r = rtnl_message_parse(m,
1357 &m->rta_offset_tb[m->n_containers],
1358 &m->rta_tb_size[m->n_containers],
1359 type_system->max,
0834ff93
TG
1360 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1361 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1362 NLMSG_PAYLOAD(m->hdr, type->size));
1363 if (r < 0)
1364 return r;
0fc7531b
TG
1365 }
1366
1367 return 0;
1368}
3dd215e0
TG
1369
1370void rtnl_message_seal(sd_rtnl_message *m) {
1371 assert(m);
1372 assert(!m->sealed);
1373
1374 m->sealed = true;
1375}
1403f45a
TG
1376
1377sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
1378 assert_return(m, NULL);
1379
1380 return m->next;
1381}