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