]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-rtnl/rtnl-message.c
rtnl: add support for receiving route messages
[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
50b3c42f 130int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, unsigned type, unsigned 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
50b3c42f
TG
225int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
226 struct ifinfomsg *ifi;
227
228 assert_return(m, -EINVAL);
229 assert_return(flags, -EINVAL);
230 assert_return(m->hdr->nlmsg_type == RTM_NEWLINK || m->hdr->nlmsg_type == RTM_DELLINK ||
231 m->hdr->nlmsg_type == RTM_GETLINK || m->hdr->nlmsg_type == RTM_SETLINK, -EINVAL);
232
233 ifi = NLMSG_DATA(m->hdr);
234
235 *flags = ifi->ifi_flags;
236
237 return 0;
238}
239
65f568bb
TG
240/* If successful the updated message will be correctly aligned, if unsuccessful the old message is
241 untouched */
242static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
dabfa9d1 243 uint32_t rta_length, message_length;
65f568bb
TG
244 struct nlmsghdr *new_hdr;
245 struct rtattr *rta;
8e337e64 246 char *padding;
65f568bb 247
33125ac5
TG
248 assert(m);
249 assert(m->hdr);
250 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
251 assert(!data || data_length > 0);
65f568bb 252
8e337e64 253 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 254 rta_length = RTA_LENGTH(data_length);
8e337e64 255 /* get the new message size (with padding at the end)
65f568bb
TG
256 */
257 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
258
259 /* realloc to fit the new attribute */
260 new_hdr = realloc(m->hdr, message_length);
261 if (!new_hdr)
262 return -ENOMEM;
263 m->hdr = new_hdr;
264
265 /* get pointer to the attribute we are about to add */
266 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
267 /* update message size */
268 m->hdr->nlmsg_len = message_length;
269
33125ac5
TG
270 /* we are inside a container, extend it */
271 if (m->current_container)
272 m->current_container->rta_len = (unsigned char *) m->hdr +
273 m->hdr->nlmsg_len -
274 (unsigned char *) m->current_container;
275
65f568bb
TG
276 /* fill in the attribute */
277 rta->rta_type = type;
278 rta->rta_len = rta_length;
33125ac5
TG
279 if (!data) {
280 /* this is a container, set pointer */
281 m->current_container = rta;
282 } else {
283 /* we don't deal with the case where the user lies about the type
284 * and gives us too little data (so don't do that)
285 */
286 padding = mempcpy(RTA_DATA(rta), data, data_length);
287 /* make sure also the padding at the end of the message is initialized */
288 memset(padding, '\0', (unsigned char *) m->hdr +
289 m->hdr->nlmsg_len -
290 (unsigned char *) padding);
291 }
65f568bb
TG
292
293 return 0;
294}
295
296int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
dabfa9d1 297 uint16_t rtm_type;
65f568bb 298 struct ifaddrmsg *ifa;
03d7e632 299 struct rtmsg *rtm;
65f568bb
TG
300
301 assert_return(m, -EINVAL);
302 assert_return(data, -EINVAL);
303
304 sd_rtnl_message_get_type(m, &rtm_type);
305
33125ac5
TG
306 if (m->current_container) {
307 switch (rtm_type) {
308 case RTM_NEWLINK:
309 case RTM_SETLINK:
310 case RTM_GETLINK:
311 case RTM_DELLINK:
312 switch (m->current_container->rta_type) {
313 case IFLA_LINKINFO:
314 switch (type) {
315 case IFLA_INFO_KIND:
316 return add_rtattr(m, type, data, strlen(data) + 1);
317 default:
318 return -ENOTSUP;
319 }
320 default:
321 return -ENOTSUP;
322 }
323 default:
324 return -ENOTSUP;
325 }
326 }
327
65f568bb
TG
328 switch (rtm_type) {
329 case RTM_NEWLINK:
d2df0d0e 330 case RTM_SETLINK:
65f568bb
TG
331 case RTM_DELLINK:
332 case RTM_GETLINK:
333 switch (type) {
334 case IFLA_IFNAME:
d2df0d0e 335 case IFLA_IFALIAS:
65f568bb
TG
336 case IFLA_QDISC:
337 return add_rtattr(m, type, data, strlen(data) + 1);
46fabae6 338 case IFLA_MASTER:
65f568bb 339 case IFLA_MTU:
65f568bb 340 case IFLA_LINK:
03d7e632 341 return add_rtattr(m, type, data, sizeof(uint32_t));
65f568bb
TG
342 case IFLA_STATS:
343 return add_rtattr(m, type, data, sizeof(struct rtnl_link_stats));
344 case IFLA_ADDRESS:
345 case IFLA_BROADCAST:
346 return add_rtattr(m, type, data, ETH_ALEN);
347 default:
348 return -ENOTSUP;
349 }
350 case RTM_NEWADDR:
351 case RTM_DELADDR:
352 case RTM_GETADDR:
353 switch (type) {
354 case IFA_LABEL:
355 return add_rtattr(m, type, data, strlen(data) + 1);
356 case IFA_ADDRESS:
357 case IFA_LOCAL:
358 case IFA_BROADCAST:
359 case IFA_ANYCAST:
360 ifa = NLMSG_DATA(m->hdr);
361 switch (ifa->ifa_family) {
362 case AF_INET:
363 return add_rtattr(m, type, data, sizeof(struct in_addr));
364 case AF_INET6:
365 return add_rtattr(m, type, data, sizeof(struct in6_addr));
366 default:
367 return -EINVAL;
368 }
369 default:
370 return -ENOTSUP;
371 }
03d7e632
TG
372 case RTM_NEWROUTE:
373 case RTM_DELROUTE:
374 case RTM_GETROUTE:
375 switch (type) {
376 case RTA_DST:
377 case RTA_SRC:
378 case RTA_GATEWAY:
379 rtm = NLMSG_DATA(m->hdr);
380 switch (rtm->rtm_family) {
381 case AF_INET:
382 return add_rtattr(m, type, data, sizeof(struct in_addr));
383 case AF_INET6:
384 return add_rtattr(m, type, data, sizeof(struct in6_addr));
385 default:
386 return -EINVAL;
387 }
388 case RTA_TABLE:
389 case RTA_PRIORITY:
390 case RTA_IIF:
391 case RTA_OIF:
392 return add_rtattr(m, type, data, sizeof(uint32_t));
393 default:
394 return -ENOTSUP;
395 }
65f568bb
TG
396 default:
397 return -ENOTSUP;
398 }
399}
400
33125ac5
TG
401int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
402 uint16_t rtm_type;
403
65f568bb 404 assert_return(m, -EINVAL);
33125ac5
TG
405 assert_return(!m->current_container, -EINVAL);
406
407 sd_rtnl_message_get_type(m, &rtm_type);
408
409 switch (rtm_type) {
410 case RTM_NEWLINK:
411 case RTM_SETLINK:
412 case RTM_GETLINK:
413 case RTM_DELLINK:
414 if (type == IFLA_LINKINFO)
415 return add_rtattr(m, type, NULL, 0);
416 else
417 return -ENOTSUP;
418 default:
419 return -ENOTSUP;
420 }
421
422 return 0;
423}
424
425int sd_rtnl_message_close_container(sd_rtnl_message *m) {
426 assert_return(m, -EINVAL);
427 assert_return(m->current_container, -EINVAL);
428
429 m->current_container = NULL;
430
431 return 0;
432}
433
434static int message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
435 uint16_t rtm_type;
436 int r;
437
438 assert(m);
439 assert(m->next_rta);
440 assert(type);
441 assert(data);
65f568bb
TG
442
443 if (!RTA_OK(m->next_rta, m->remaining_size))
444 return 0;
445
33125ac5
TG
446 /* make sure we don't try to read a container
447 * TODO: add support for entering containers for reading */
448 r = sd_rtnl_message_get_type(m, &rtm_type);
449 if (r < 0)
450 return r;
451
452 switch (rtm_type) {
453 case RTM_NEWLINK:
454 case RTM_GETLINK:
455 case RTM_SETLINK:
456 case RTM_DELLINK:
457 if (m->next_rta->rta_type == IFLA_LINKINFO) {
458 return -EINVAL;
459 }
460 }
461
65f568bb
TG
462 *data = RTA_DATA(m->next_rta);
463 *type = m->next_rta->rta_type;
464
465 m->next_rta = RTA_NEXT(m->next_rta, m->remaining_size);
466
467 return 1;
468}
469
470int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
dabfa9d1 471 uint16_t rtm_type;
33125ac5 472 int r;
65f568bb
TG
473
474 assert_return(m, -EINVAL);
475 assert_return(data, -EINVAL);
476
33125ac5
TG
477 r = sd_rtnl_message_get_type(m, &rtm_type);
478 if (r < 0)
479 return r;
65f568bb
TG
480
481 switch (rtm_type) {
482 case RTM_NEWLINK:
d2df0d0e 483 case RTM_SETLINK:
65f568bb
TG
484 case RTM_DELLINK:
485 case RTM_GETLINK:
486 if (!m->next_rta) {
dabfa9d1 487 struct ifinfomsg *ifi = NLMSG_DATA(m->hdr);
65f568bb
TG
488
489 m->next_rta = IFLA_RTA(ifi);
490 m->remaining_size = IFLA_PAYLOAD(m->hdr);
491 }
03d7e632 492 break;
65f568bb
TG
493 case RTM_NEWADDR:
494 case RTM_DELADDR:
495 case RTM_GETADDR:
496 if (!m->next_rta) {
dabfa9d1 497 struct ifaddrmsg *ifa = NLMSG_DATA(m->hdr);
65f568bb
TG
498
499 m->next_rta = IFA_RTA(ifa);
03d7e632
TG
500 m->remaining_size = IFA_PAYLOAD(m->hdr);
501 }
502 break;
503 case RTM_NEWROUTE:
504 case RTM_DELROUTE:
505 case RTM_GETROUTE:
506 if (!m->next_rta) {
507 struct rtmesg *rtm = NLMSG_DATA(m->hdr);
508
509 m->next_rta = RTM_RTA(rtm);
510 m->remaining_size = RTM_PAYLOAD(m->hdr);
65f568bb 511 }
03d7e632 512 break;
65f568bb
TG
513 default:
514 return -ENOTSUP;
515 }
516
517 return message_read(m, type, data);
518}
519
4555ec72 520uint32_t message_get_serial(sd_rtnl_message *m) {
65f568bb
TG
521 assert(m);
522
523 return m->hdr->nlmsg_seq;
524}
525
e16bcf98 526int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
527 struct nlmsgerr *err;
528
e16bcf98 529 assert_return(m, -EINVAL);
65f568bb
TG
530
531 if (m->hdr->nlmsg_type != NLMSG_ERROR)
532 return 0;
533
534 err = NLMSG_DATA(m->hdr);
535
536 return err->error;
537}
538
539int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
540 if (m->sealed)
541 return -EPERM;
542
543 m->hdr->nlmsg_seq = nl->serial++;
544 m->sealed = true;
545
546 return 0;
547}
548
549static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
550 assert_return(rtnl, -EINVAL);
551 assert_return(need, -EINVAL);
552
553 /* ioctl(rtnl->fd, FIONREAD, &need)
dabfa9d1
TG
554 Does not appear to work on netlink sockets. libnl uses
555 MSG_PEEK instead. I don't know if that is worth the
556 extra roundtrip.
557
558 For now we simply use the maximum message size the kernel
559 may use (NLMSG_GOODSIZE), and then realloc to the actual
560 size after reading the message (hence avoiding huge memory
561 usage in case many small messages are kept around) */
562 *need = page_size();
65f568bb
TG
563 if (*need > 8192UL)
564 *need = 8192UL;
565
566 return 0;
567}
568
569/* returns the number of bytes sent, or a negative error code */
570int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
571 union {
572 struct sockaddr sa;
573 struct sockaddr_nl nl;
574 } addr = {
575 .nl.nl_family = AF_NETLINK,
576 };
65f568bb
TG
577 ssize_t k;
578
579 assert_return(nl, -EINVAL);
580 assert_return(m, -EINVAL);
581
582 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 583 0, &addr.sa, sizeof(addr));
65f568bb
TG
584 if (k < 0)
585 return (errno == EAGAIN) ? 0 : -errno;
586
587 return k;
588}
589
590/* On success, the number of bytes received is returned and *ret points to the received message
591 * which has a valid header and the correct size.
592 * If nothing useful was received 0 is returned.
593 * On failure, a negative error code is returned.
dabfa9d1 594 */
65f568bb
TG
595int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
596 sd_rtnl_message *m;
d4bbdb77
TG
597 union {
598 struct sockaddr sa;
599 struct sockaddr_nl nl;
600 } addr;
601 socklen_t addr_len;
65f568bb
TG
602 int r;
603 ssize_t k;
604 size_t need;
605
606 assert_return(nl, -EINVAL);
607 assert_return(ret, -EINVAL);
608
609 r = message_receive_need(nl, &need);
610 if (r < 0)
611 return r;
612
613 r = message_new(&m, need);
614 if (r < 0)
615 return r;
616
d4bbdb77
TG
617 addr_len = sizeof(addr);
618
65f568bb 619 k = recvfrom(nl->fd, m->hdr, need,
d4bbdb77 620 0, &addr.sa, &addr_len);
65f568bb 621 if (k < 0)
276fc066 622 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
65f568bb
TG
623 else if (k == 0)
624 k = -ECONNRESET; /* connection was closed by the kernel */
d4bbdb77
TG
625 else if (addr_len != sizeof(addr.nl) ||
626 addr.nl.nl_family != AF_NETLINK)
65f568bb 627 k = -EIO; /* not a netlink message */
d4bbdb77 628 else if (addr.nl.nl_pid != 0)
65f568bb
TG
629 k = 0; /* not from the kernel */
630 else if ((size_t) k < sizeof(struct nlmsghdr) ||
dabfa9d1 631 (size_t) k < m->hdr->nlmsg_len)
65f568bb 632 k = -EIO; /* too small (we do accept too big though) */
a02113d2
TG
633 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
634 k = 0; /* not broadcast and not for us */
65f568bb
TG
635
636 if (k > 0)
637 switch (m->hdr->nlmsg_type) {
638 /* check that the size matches the message type */
639 case NLMSG_ERROR:
640 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
641 k = -EIO;
03d7e632 642 break;
65f568bb 643 case RTM_NEWLINK:
d2df0d0e 644 case RTM_SETLINK:
65f568bb
TG
645 case RTM_DELLINK:
646 case RTM_GETLINK:
647 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
648 k = -EIO;
03d7e632 649 break;
65f568bb
TG
650 case RTM_NEWADDR:
651 case RTM_DELADDR:
652 case RTM_GETADDR:
653 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
654 k = -EIO;
03d7e632 655 break;
3e10a9f4
TG
656 case RTM_NEWROUTE:
657 case RTM_DELROUTE:
658 case RTM_GETROUTE:
659 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
660 k = -EIO;
661 break;
65f568bb
TG
662 case NLMSG_NOOP:
663 k = 0;
03d7e632 664 break;
65f568bb
TG
665 default:
666 k = 0; /* ignoring message of unknown type */
667 }
668
669 if (k <= 0)
670 sd_rtnl_message_unref(m);
671 else {
672 /* we probably allocated way too much memory, give it back */
673 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
674 *ret = m;
675 }
676
677 return k;
678}