]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-rtnl/rtnl-message.c
rtnl: support interleaved reading and writing, and rewind
[thirdparty/systemd.git] / src / libsystemd-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
a33dece5 22#include <linux/rtnetlink.h>
65f568bb
TG
23#include <netinet/in.h>
24#include <netinet/ether.h>
25#include <stdbool.h>
26#include <unistd.h>
27
28#include "util.h"
29#include "refcnt.h"
30
31#include "sd-rtnl.h"
32#include "rtnl-internal.h"
33
34struct sd_rtnl_message {
35 RefCount n_ref;
36
37 struct nlmsghdr *hdr;
38
33125ac5
TG
39 struct rtattr *current_container;
40
65f568bb 41 struct rtattr *next_rta;
65f568bb
TG
42
43 bool sealed:1;
44};
45
46static int message_new(sd_rtnl_message **ret, size_t initial_size) {
47 sd_rtnl_message *m;
48
49 assert_return(ret, -EINVAL);
dabfa9d1 50 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
65f568bb
TG
51
52 m = new0(sd_rtnl_message, 1);
53 if (!m)
54 return -ENOMEM;
55
dc7d8997 56 m->hdr = malloc0(initial_size);
65f568bb
TG
57 if (!m->hdr) {
58 free(m);
59 return -ENOMEM;
60 }
61
62 m->n_ref = REFCNT_INIT;
63
64 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
65 m->sealed = false;
66
67 *ret = m;
68
69 return 0;
70}
71
e16bcf98
TG
72int message_new_synthetic_error(int error, uint32_t serial, sd_rtnl_message **ret) {
73 struct nlmsgerr *err;
74 int r;
75
76 assert(error <= 0);
77
78 r = message_new(ret, NLMSG_SPACE(sizeof(struct nlmsgerr)));
79 if (r < 0)
80 return r;
81
82 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
83 (*ret)->hdr->nlmsg_type = NLMSG_ERROR;
84 (*ret)->hdr->nlmsg_seq = serial;
85
86 err = NLMSG_DATA((*ret)->hdr);
87
88 err->error = error;
89
90 return 0;
91}
92
9d0db178
TG
93bool message_type_is_route(uint16_t type) {
94 switch (type) {
95 case RTM_NEWROUTE:
96 case RTM_GETROUTE:
97 case RTM_DELROUTE:
98 return true;
99 default:
100 return false;
101 }
102}
103
104bool message_type_is_link(uint16_t type) {
105 switch (type) {
106 case RTM_NEWLINK:
107 case RTM_SETLINK:
108 case RTM_GETLINK:
109 case RTM_DELLINK:
110 return true;
111 default:
112 return false;
113 }
114}
115
116bool message_type_is_addr(uint16_t type) {
117 switch (type) {
118 case RTM_NEWADDR:
119 case RTM_GETADDR:
120 case RTM_DELADDR:
121 return true;
122 default:
123 return false;
124 }
125}
126
1f01fb4f
TG
127int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
128 struct rtmsg *rtm;
129
130 rtm = NLMSG_DATA(m->hdr);
131
132 rtm->rtm_dst_len = prefixlen;
133
134 return 0;
135}
136
03d7e632 137int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
1f01fb4f 138 sd_rtnl_message **ret) {
03d7e632
TG
139 struct rtmsg *rtm;
140 int r;
141
9d0db178 142 assert_return(message_type_is_route(nlmsg_type), -EINVAL);
1f01fb4f 143 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
03d7e632
TG
144 assert_return(ret, -EINVAL);
145
146 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
147 if (r < 0)
148 return r;
149
150 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
151 (*ret)->hdr->nlmsg_type = nlmsg_type;
152 if (nlmsg_type == RTM_NEWROUTE)
153 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
154
155 rtm = NLMSG_DATA((*ret)->hdr);
156
0fc7531b
TG
157 (*ret)->next_rta = RTM_RTA(rtm);
158
03d7e632 159 rtm->rtm_family = rtm_family;
1f01fb4f
TG
160 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
161 rtm->rtm_type = RTN_UNICAST;
162 rtm->rtm_table = RT_TABLE_MAIN;
163 rtm->rtm_protocol = RTPROT_BOOT;
03d7e632
TG
164
165 return 0;
166}
167
fc25d7f8
TG
168int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags) {
169 struct ifinfomsg *ifi;
170
171 ifi = NLMSG_DATA(m->hdr);
172
173 ifi->ifi_flags = flags;
174
175 return 0;
176}
177
178int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
179 struct ifinfomsg *ifi;
180
181 ifi = NLMSG_DATA(m->hdr);
182
183 ifi->ifi_type = type;
184
185 return 0;
186}
187
188int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
65f568bb
TG
189 struct ifinfomsg *ifi;
190 int r;
191
9d0db178 192 assert_return(message_type_is_link(nlmsg_type), -EINVAL);
33125ac5 193 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
65f568bb
TG
194 assert_return(ret, -EINVAL);
195
196 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
197 if (r < 0)
198 return r;
199
200 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
201 (*ret)->hdr->nlmsg_type = nlmsg_type;
33125ac5
TG
202 if (nlmsg_type == RTM_NEWLINK)
203 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
65f568bb 204
dabfa9d1 205 ifi = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
206
207 ifi->ifi_family = AF_UNSPEC;
208 ifi->ifi_index = index;
65f568bb
TG
209 ifi->ifi_change = 0xffffffff;
210
0fc7531b
TG
211 (*ret)->next_rta = IFLA_RTA(ifi);
212
65f568bb
TG
213 return 0;
214}
215
dabfa9d1 216int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family, unsigned char prefixlen, unsigned char flags, unsigned char scope, sd_rtnl_message **ret) {
65f568bb
TG
217 struct ifaddrmsg *ifa;
218 int r;
219
9d0db178 220 assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
65f568bb
TG
221 assert_return(index > 0, -EINVAL);
222 assert_return(ret, -EINVAL);
223
224 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
225 if (r < 0)
226 return r;
227
228 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
229 (*ret)->hdr->nlmsg_type = nlmsg_type;
230
dabfa9d1 231 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
232
233 ifa->ifa_family = family;
234 ifa->ifa_prefixlen = prefixlen;
235 ifa->ifa_flags = flags;
236 ifa->ifa_scope = scope;
237 ifa->ifa_index = index;
238
0fc7531b
TG
239 (*ret)->next_rta = IFA_RTA(ifa);
240
65f568bb
TG
241 return 0;
242}
243
244sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
245 if (m)
246 assert_se(REFCNT_INC(m->n_ref) >= 2);
247
248 return m;
249}
250
251sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
252 if (m && REFCNT_DEC(m->n_ref) <= 0) {
253 free(m->hdr);
254 free(m);
255 }
256
257 return NULL;
258}
259
dabfa9d1 260int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
65f568bb
TG
261 assert_return(m, -EINVAL);
262 assert_return(type, -EINVAL);
263
264 *type = m->hdr->nlmsg_type;
265
266 return 0;
267}
268
33125ac5
TG
269int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
270 struct ifinfomsg *ifi;
271
272 assert_return(m, -EINVAL);
9d0db178
TG
273 assert_return(m->hdr, -EINVAL);
274 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 275 assert_return(ifindex, -EINVAL);
33125ac5
TG
276
277 ifi = NLMSG_DATA(m->hdr);
278
279 *ifindex = ifi->ifi_index;
280
281 return 0;
282}
283
50b3c42f
TG
284int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
285 struct ifinfomsg *ifi;
286
287 assert_return(m, -EINVAL);
9d0db178
TG
288 assert_return(m->hdr, -EINVAL);
289 assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 290 assert_return(flags, -EINVAL);
50b3c42f
TG
291
292 ifi = NLMSG_DATA(m->hdr);
293
294 *flags = ifi->ifi_flags;
295
296 return 0;
297}
298
65f568bb
TG
299/* If successful the updated message will be correctly aligned, if unsuccessful the old message is
300 untouched */
301static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
dabfa9d1 302 uint32_t rta_length, message_length;
65f568bb
TG
303 struct nlmsghdr *new_hdr;
304 struct rtattr *rta;
8e337e64 305 char *padding;
65f568bb 306
33125ac5
TG
307 assert(m);
308 assert(m->hdr);
309 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
310 assert(!data || data_length > 0);
65f568bb 311
8e337e64 312 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 313 rta_length = RTA_LENGTH(data_length);
8e337e64 314 /* get the new message size (with padding at the end)
65f568bb
TG
315 */
316 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
317
318 /* realloc to fit the new attribute */
319 new_hdr = realloc(m->hdr, message_length);
320 if (!new_hdr)
321 return -ENOMEM;
0fc7531b
TG
322 /* update the location of the next rta for reading */
323 m->next_rta = (struct rtattr *) ((uint8_t *) m->next_rta +
324 ((uint8_t *) new_hdr -
325 (uint8_t *) m->hdr));
65f568bb
TG
326 m->hdr = new_hdr;
327
328 /* get pointer to the attribute we are about to add */
329 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
330 /* update message size */
331 m->hdr->nlmsg_len = message_length;
332
33125ac5
TG
333 /* we are inside a container, extend it */
334 if (m->current_container)
0fc7531b 335 m->current_container->rta_len = (uint8_t *) m->hdr +
33125ac5 336 m->hdr->nlmsg_len -
0fc7531b 337 (uint8_t *) m->current_container;
33125ac5 338
65f568bb
TG
339 /* fill in the attribute */
340 rta->rta_type = type;
341 rta->rta_len = rta_length;
33125ac5
TG
342 if (!data) {
343 /* this is a container, set pointer */
344 m->current_container = rta;
345 } else {
346 /* we don't deal with the case where the user lies about the type
347 * and gives us too little data (so don't do that)
348 */
349 padding = mempcpy(RTA_DATA(rta), data, data_length);
350 /* make sure also the padding at the end of the message is initialized */
0fc7531b 351 memset(padding, '\0', (uint8_t *) m->hdr +
33125ac5 352 m->hdr->nlmsg_len -
0fc7531b 353 (uint8_t *) padding);
33125ac5 354 }
65f568bb
TG
355
356 return 0;
357}
358
359int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
dabfa9d1 360 uint16_t rtm_type;
65f568bb 361 struct ifaddrmsg *ifa;
03d7e632 362 struct rtmsg *rtm;
65f568bb
TG
363
364 assert_return(m, -EINVAL);
365 assert_return(data, -EINVAL);
366
367 sd_rtnl_message_get_type(m, &rtm_type);
368
33125ac5
TG
369 if (m->current_container) {
370 switch (rtm_type) {
371 case RTM_NEWLINK:
372 case RTM_SETLINK:
373 case RTM_GETLINK:
374 case RTM_DELLINK:
375 switch (m->current_container->rta_type) {
376 case IFLA_LINKINFO:
377 switch (type) {
378 case IFLA_INFO_KIND:
379 return add_rtattr(m, type, data, strlen(data) + 1);
380 default:
381 return -ENOTSUP;
382 }
383 default:
384 return -ENOTSUP;
385 }
386 default:
387 return -ENOTSUP;
388 }
389 }
390
65f568bb
TG
391 switch (rtm_type) {
392 case RTM_NEWLINK:
d2df0d0e 393 case RTM_SETLINK:
65f568bb
TG
394 case RTM_DELLINK:
395 case RTM_GETLINK:
396 switch (type) {
397 case IFLA_IFNAME:
d2df0d0e 398 case IFLA_IFALIAS:
65f568bb
TG
399 case IFLA_QDISC:
400 return add_rtattr(m, type, data, strlen(data) + 1);
46fabae6 401 case IFLA_MASTER:
65f568bb 402 case IFLA_MTU:
65f568bb 403 case IFLA_LINK:
03d7e632 404 return add_rtattr(m, type, data, sizeof(uint32_t));
65f568bb
TG
405 case IFLA_STATS:
406 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
407 case IFLA_ADDRESS:
408 case IFLA_BROADCAST:
409 return add_rtattr(m, type, data, ETH_ALEN);
410 default:
411 return -ENOTSUP;
412 }
413 case RTM_NEWADDR:
414 case RTM_DELADDR:
415 case RTM_GETADDR:
416 switch (type) {
417 case IFA_LABEL:
418 return add_rtattr(m, type, data, strlen(data) + 1);
419 case IFA_ADDRESS:
420 case IFA_LOCAL:
421 case IFA_BROADCAST:
422 case IFA_ANYCAST:
423 ifa = NLMSG_DATA(m->hdr);
424 switch (ifa->ifa_family) {
425 case AF_INET:
426 return add_rtattr(m, type, data, sizeof(struct in_addr));
427 case AF_INET6:
428 return add_rtattr(m, type, data, sizeof(struct in6_addr));
429 default:
430 return -EINVAL;
431 }
432 default:
433 return -ENOTSUP;
434 }
03d7e632
TG
435 case RTM_NEWROUTE:
436 case RTM_DELROUTE:
437 case RTM_GETROUTE:
438 switch (type) {
439 case RTA_DST:
440 case RTA_SRC:
441 case RTA_GATEWAY:
442 rtm = NLMSG_DATA(m->hdr);
443 switch (rtm->rtm_family) {
444 case AF_INET:
445 return add_rtattr(m, type, data, sizeof(struct in_addr));
446 case AF_INET6:
447 return add_rtattr(m, type, data, sizeof(struct in6_addr));
448 default:
449 return -EINVAL;
450 }
451 case RTA_TABLE:
452 case RTA_PRIORITY:
453 case RTA_IIF:
454 case RTA_OIF:
455 return add_rtattr(m, type, data, sizeof(uint32_t));
456 default:
457 return -ENOTSUP;
458 }
65f568bb
TG
459 default:
460 return -ENOTSUP;
461 }
462}
463
33125ac5
TG
464int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
465 uint16_t rtm_type;
466
65f568bb 467 assert_return(m, -EINVAL);
33125ac5
TG
468 assert_return(!m->current_container, -EINVAL);
469
470 sd_rtnl_message_get_type(m, &rtm_type);
471
9d0db178
TG
472 if (message_type_is_link(rtm_type)) {
473 if (type == IFLA_LINKINFO)
474 return add_rtattr(m, type, NULL, 0);
475 else
33125ac5 476 return -ENOTSUP;
9d0db178
TG
477 } else
478 return -ENOTSUP;
33125ac5
TG
479
480 return 0;
481}
482
483int sd_rtnl_message_close_container(sd_rtnl_message *m) {
484 assert_return(m, -EINVAL);
485 assert_return(m->current_container, -EINVAL);
486
487 m->current_container = NULL;
488
489 return 0;
490}
491
0fc7531b
TG
492int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
493 size_t remaining_size;
33125ac5
TG
494 uint16_t rtm_type;
495 int r;
496
497 assert(m);
498 assert(m->next_rta);
499 assert(type);
500 assert(data);
65f568bb 501
0fc7531b
TG
502 remaining_size = (uint8_t *) m->hdr + m->hdr->nlmsg_len - (uint8_t *) m->next_rta;
503
504 if (!RTA_OK(m->next_rta, remaining_size))
65f568bb
TG
505 return 0;
506
33125ac5
TG
507 /* make sure we don't try to read a container
508 * TODO: add support for entering containers for reading */
509 r = sd_rtnl_message_get_type(m, &rtm_type);
510 if (r < 0)
511 return r;
512
0fc7531b
TG
513 if (message_type_is_link(rtm_type) &&
514 m->next_rta->rta_type == IFLA_LINKINFO)
515 return -EINVAL;
33125ac5 516
65f568bb
TG
517 *data = RTA_DATA(m->next_rta);
518 *type = m->next_rta->rta_type;
519
0fc7531b 520 m->next_rta = RTA_NEXT(m->next_rta, remaining_size);
65f568bb
TG
521
522 return 1;
523}
524
4555ec72 525uint32_t message_get_serial(sd_rtnl_message *m) {
65f568bb 526 assert(m);
9d0db178 527 assert(m->hdr);
65f568bb
TG
528
529 return m->hdr->nlmsg_seq;
530}
531
e16bcf98 532int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
533 struct nlmsgerr *err;
534
e16bcf98 535 assert_return(m, -EINVAL);
9d0db178 536 assert_return(m->hdr, -EINVAL);
65f568bb
TG
537
538 if (m->hdr->nlmsg_type != NLMSG_ERROR)
539 return 0;
540
541 err = NLMSG_DATA(m->hdr);
542
543 return err->error;
544}
545
546int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
9d0db178
TG
547 assert(nl);
548 assert(m);
549 assert(m->hdr);
550
65f568bb
TG
551 if (m->sealed)
552 return -EPERM;
553
554 m->hdr->nlmsg_seq = nl->serial++;
555 m->sealed = true;
556
557 return 0;
558}
559
560static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
9d0db178
TG
561 assert(rtnl);
562 assert(need);
65f568bb
TG
563
564 /* ioctl(rtnl->fd, FIONREAD, &need)
dabfa9d1
TG
565 Does not appear to work on netlink sockets. libnl uses
566 MSG_PEEK instead. I don't know if that is worth the
567 extra roundtrip.
568
569 For now we simply use the maximum message size the kernel
570 may use (NLMSG_GOODSIZE), and then realloc to the actual
571 size after reading the message (hence avoiding huge memory
572 usage in case many small messages are kept around) */
573 *need = page_size();
65f568bb
TG
574 if (*need > 8192UL)
575 *need = 8192UL;
576
577 return 0;
578}
579
580/* returns the number of bytes sent, or a negative error code */
581int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
582 union {
583 struct sockaddr sa;
584 struct sockaddr_nl nl;
585 } addr = {
586 .nl.nl_family = AF_NETLINK,
587 };
65f568bb
TG
588 ssize_t k;
589
9d0db178
TG
590 assert(nl);
591 assert(m);
592 assert(m->hdr);
65f568bb
TG
593
594 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 595 0, &addr.sa, sizeof(addr));
65f568bb
TG
596 if (k < 0)
597 return (errno == EAGAIN) ? 0 : -errno;
598
599 return k;
600}
601
602/* On success, the number of bytes received is returned and *ret points to the received message
603 * which has a valid header and the correct size.
604 * If nothing useful was received 0 is returned.
605 * On failure, a negative error code is returned.
dabfa9d1 606 */
65f568bb
TG
607int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
608 sd_rtnl_message *m;
d4bbdb77
TG
609 union {
610 struct sockaddr sa;
611 struct sockaddr_nl nl;
612 } addr;
613 socklen_t addr_len;
65f568bb
TG
614 int r;
615 ssize_t k;
616 size_t need;
617
9d0db178
TG
618 assert(nl);
619 assert(ret);
65f568bb
TG
620
621 r = message_receive_need(nl, &need);
622 if (r < 0)
623 return r;
624
625 r = message_new(&m, need);
626 if (r < 0)
627 return r;
628
d4bbdb77
TG
629 addr_len = sizeof(addr);
630
65f568bb 631 k = recvfrom(nl->fd, m->hdr, need,
d4bbdb77 632 0, &addr.sa, &addr_len);
65f568bb 633 if (k < 0)
276fc066 634 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
65f568bb
TG
635 else if (k == 0)
636 k = -ECONNRESET; /* connection was closed by the kernel */
d4bbdb77
TG
637 else if (addr_len != sizeof(addr.nl) ||
638 addr.nl.nl_family != AF_NETLINK)
65f568bb 639 k = -EIO; /* not a netlink message */
d4bbdb77 640 else if (addr.nl.nl_pid != 0)
65f568bb
TG
641 k = 0; /* not from the kernel */
642 else if ((size_t) k < sizeof(struct nlmsghdr) ||
dabfa9d1 643 (size_t) k < m->hdr->nlmsg_len)
65f568bb 644 k = -EIO; /* too small (we do accept too big though) */
a02113d2
TG
645 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
646 k = 0; /* not broadcast and not for us */
65f568bb
TG
647
648 if (k > 0)
649 switch (m->hdr->nlmsg_type) {
0fc7531b
TG
650 struct ifinfomsg *ifi;
651 struct ifaddrmsg *ifa;
652 struct rtmsg *rtm;
653
65f568bb
TG
654 /* check that the size matches the message type */
655 case NLMSG_ERROR:
656 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
657 k = -EIO;
03d7e632 658 break;
65f568bb 659 case RTM_NEWLINK:
d2df0d0e 660 case RTM_SETLINK:
65f568bb
TG
661 case RTM_DELLINK:
662 case RTM_GETLINK:
663 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
664 k = -EIO;
0fc7531b
TG
665 else {
666 ifi = NLMSG_DATA(m->hdr);
667 m->next_rta = IFLA_RTA(ifi);
668 }
03d7e632 669 break;
65f568bb
TG
670 case RTM_NEWADDR:
671 case RTM_DELADDR:
672 case RTM_GETADDR:
673 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
674 k = -EIO;
0fc7531b
TG
675 else {
676 ifa = NLMSG_DATA(m->hdr);
677 m->next_rta = IFA_RTA(ifa);
678 }
03d7e632 679 break;
3e10a9f4
TG
680 case RTM_NEWROUTE:
681 case RTM_DELROUTE:
682 case RTM_GETROUTE:
683 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
684 k = -EIO;
0fc7531b
TG
685 else {
686 rtm = NLMSG_DATA(m->hdr);
687 m->next_rta = RTM_RTA(rtm);
688 }
3e10a9f4 689 break;
65f568bb
TG
690 case NLMSG_NOOP:
691 k = 0;
03d7e632 692 break;
65f568bb
TG
693 default:
694 k = 0; /* ignoring message of unknown type */
695 }
696
697 if (k <= 0)
698 sd_rtnl_message_unref(m);
699 else {
700 /* we probably allocated way too much memory, give it back */
701 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
702 *ret = m;
703 }
704
705 return k;
706}
0fc7531b
TG
707
708int sd_rtnl_message_rewind(sd_rtnl_message *m) {
709 struct ifinfomsg *ifi;
710 struct ifaddrmsg *ifa;
711 struct rtmsg *rtm;
712
713 assert_return(m, -EINVAL);
714 assert_return(m->hdr, -EINVAL);
715
716 switch(m->hdr->nlmsg_type) {
717 case RTM_NEWLINK:
718 case RTM_SETLINK:
719 case RTM_GETLINK:
720 case RTM_DELLINK:
721 ifi = NLMSG_DATA(m->hdr);
722
723 m->next_rta = IFLA_RTA(ifi);
724 break;
725 case RTM_NEWADDR:
726 case RTM_GETADDR:
727 case RTM_DELADDR:
728 ifa = NLMSG_DATA(m->hdr);
729
730 m->next_rta = IFA_RTA(ifa);
731 break;
732 case RTM_NEWROUTE:
733 case RTM_GETROUTE:
734 case RTM_DELROUTE:
735 rtm = NLMSG_DATA(m->hdr);
736
737 m->next_rta = RTM_RTA(rtm);
738 break;
739 default:
740 return -ENOTSUP;
741 }
742
743 return 0;
744}