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