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