chiark / gitweb /
rtnl: support interleaved reading and writing, and rewind
[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
43         bool sealed:1;
44 };
45
46 static int message_new(sd_rtnl_message **ret, size_t initial_size) {
47         sd_rtnl_message *m;
48
49         assert_return(ret, -EINVAL);
50         assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
51
52         m = new0(sd_rtnl_message, 1);
53         if (!m)
54                 return -ENOMEM;
55
56         m->hdr = malloc0(initial_size);
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
72 int 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
93 bool 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
104 bool 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
116 bool 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
127 int 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
137 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
138                               sd_rtnl_message **ret) {
139         struct rtmsg *rtm;
140         int r;
141
142         assert_return(message_type_is_route(nlmsg_type), -EINVAL);
143         assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
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
157         (*ret)->next_rta = RTM_RTA(rtm);
158
159         rtm->rtm_family = rtm_family;
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;
164
165         return 0;
166 }
167
168 int 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
178 int 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
188 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
189         struct ifinfomsg *ifi;
190         int r;
191
192         assert_return(message_type_is_link(nlmsg_type), -EINVAL);
193         assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
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;
202         if (nlmsg_type == RTM_NEWLINK)
203                 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
204
205         ifi = NLMSG_DATA((*ret)->hdr);
206
207         ifi->ifi_family = AF_UNSPEC;
208         ifi->ifi_index = index;
209         ifi->ifi_change = 0xffffffff;
210
211         (*ret)->next_rta = IFLA_RTA(ifi);
212
213         return 0;
214 }
215
216 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) {
217         struct ifaddrmsg *ifa;
218         int r;
219
220         assert_return(message_type_is_addr(nlmsg_type), -EINVAL);
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
231         ifa = NLMSG_DATA((*ret)->hdr);
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
239         (*ret)->next_rta = IFA_RTA(ifa);
240
241         return 0;
242 }
243
244 sd_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
251 sd_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
260 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
261         assert_return(m, -EINVAL);
262         assert_return(type, -EINVAL);
263
264         *type = m->hdr->nlmsg_type;
265
266         return 0;
267 }
268
269 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
270         struct ifinfomsg *ifi;
271
272         assert_return(m, -EINVAL);
273         assert_return(m->hdr, -EINVAL);
274         assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
275         assert_return(ifindex, -EINVAL);
276
277         ifi = NLMSG_DATA(m->hdr);
278
279         *ifindex = ifi->ifi_index;
280
281         return 0;
282 }
283
284 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
285         struct ifinfomsg *ifi;
286
287         assert_return(m, -EINVAL);
288         assert_return(m->hdr, -EINVAL);
289         assert_return(message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
290         assert_return(flags, -EINVAL);
291
292         ifi = NLMSG_DATA(m->hdr);
293
294         *flags = ifi->ifi_flags;
295
296         return 0;
297 }
298
299 /* If successful the updated message will be correctly aligned, if unsuccessful the old message is
300    untouched */
301 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
302         uint32_t rta_length, message_length;
303         struct nlmsghdr *new_hdr;
304         struct rtattr *rta;
305         char *padding;
306
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);
311
312         /* get the size of the new rta attribute (with padding at the end) */
313         rta_length = RTA_LENGTH(data_length);
314         /* get the new message size (with padding at the end)
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;
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));
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
333         /* we are inside a container, extend it */
334         if (m->current_container)
335                 m->current_container->rta_len = (uint8_t *) m->hdr +
336                                                 m->hdr->nlmsg_len -
337                                                 (uint8_t *) m->current_container;
338
339         /* fill in the attribute */
340         rta->rta_type = type;
341         rta->rta_len = rta_length;
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 */
351                 memset(padding, '\0', (uint8_t *) m->hdr +
352                                       m->hdr->nlmsg_len -
353                                       (uint8_t *) padding);
354         }
355
356         return 0;
357 }
358
359 int sd_rtnl_message_append(sd_rtnl_message *m, unsigned short type, const void *data) {
360         uint16_t rtm_type;
361         struct ifaddrmsg *ifa;
362         struct rtmsg *rtm;
363
364         assert_return(m, -EINVAL);
365         assert_return(data, -EINVAL);
366
367         sd_rtnl_message_get_type(m, &rtm_type);
368
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
391         switch (rtm_type) {
392                 case RTM_NEWLINK:
393                 case RTM_SETLINK:
394                 case RTM_DELLINK:
395                 case RTM_GETLINK:
396                         switch (type) {
397                                 case IFLA_IFNAME:
398                                 case IFLA_IFALIAS:
399                                 case IFLA_QDISC:
400                                         return add_rtattr(m, type, data, strlen(data) + 1);
401                                 case IFLA_MASTER:
402                                 case IFLA_MTU:
403                                 case IFLA_LINK:
404                                         return add_rtattr(m, type, data, sizeof(uint32_t));
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                         }
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                         }
459                 default:
460                         return -ENOTSUP;
461         }
462 }
463
464 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
465         uint16_t rtm_type;
466
467         assert_return(m, -EINVAL);
468         assert_return(!m->current_container, -EINVAL);
469
470         sd_rtnl_message_get_type(m, &rtm_type);
471
472         if (message_type_is_link(rtm_type)) {
473                 if (type == IFLA_LINKINFO)
474                         return add_rtattr(m, type, NULL, 0);
475                 else
476                         return -ENOTSUP;
477         } else
478                 return -ENOTSUP;
479
480         return 0;
481 }
482
483 int 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
492 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
493         size_t remaining_size;
494         uint16_t rtm_type;
495         int r;
496
497         assert(m);
498         assert(m->next_rta);
499         assert(type);
500         assert(data);
501
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))
505                 return 0;
506
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
513         if (message_type_is_link(rtm_type) &&
514             m->next_rta->rta_type == IFLA_LINKINFO)
515                return -EINVAL;
516
517         *data = RTA_DATA(m->next_rta);
518         *type = m->next_rta->rta_type;
519
520         m->next_rta = RTA_NEXT(m->next_rta, remaining_size);
521
522         return 1;
523 }
524
525 uint32_t message_get_serial(sd_rtnl_message *m) {
526         assert(m);
527         assert(m->hdr);
528
529         return m->hdr->nlmsg_seq;
530 }
531
532 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
533         struct nlmsgerr *err;
534
535         assert_return(m, -EINVAL);
536         assert_return(m->hdr, -EINVAL);
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
546 int message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
547         assert(nl);
548         assert(m);
549         assert(m->hdr);
550
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
560 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
561         assert(rtnl);
562         assert(need);
563
564         /* ioctl(rtnl->fd, FIONREAD, &need)
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();
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 */
581 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
582         union {
583                 struct sockaddr sa;
584                 struct sockaddr_nl nl;
585         } addr = {
586                 .nl.nl_family = AF_NETLINK,
587         };
588         ssize_t k;
589
590         assert(nl);
591         assert(m);
592         assert(m->hdr);
593
594         k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
595                         0, &addr.sa, sizeof(addr));
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.
606  */
607 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
608         sd_rtnl_message *m;
609         union {
610                 struct sockaddr sa;
611                 struct sockaddr_nl nl;
612         } addr;
613         socklen_t addr_len;
614         int r;
615         ssize_t k;
616         size_t need;
617
618         assert(nl);
619         assert(ret);
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
629         addr_len = sizeof(addr);
630
631         k = recvfrom(nl->fd, m->hdr, need,
632                         0, &addr.sa, &addr_len);
633         if (k < 0)
634                 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
635         else if (k == 0)
636                 k = -ECONNRESET; /* connection was closed by the kernel */
637         else if (addr_len != sizeof(addr.nl) ||
638                         addr.nl.nl_family != AF_NETLINK)
639                 k = -EIO; /* not a netlink message */
640         else if (addr.nl.nl_pid != 0)
641                 k = 0; /* not from the kernel */
642         else if ((size_t) k < sizeof(struct nlmsghdr) ||
643                         (size_t) k < m->hdr->nlmsg_len)
644                 k = -EIO; /* too small (we do accept too big though) */
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 */
647
648         if (k > 0)
649                 switch (m->hdr->nlmsg_type) {
650                         struct ifinfomsg *ifi;
651                         struct ifaddrmsg *ifa;
652                         struct rtmsg *rtm;
653
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;
658                                 break;
659                         case RTM_NEWLINK:
660                         case RTM_SETLINK:
661                         case RTM_DELLINK:
662                         case RTM_GETLINK:
663                                 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
664                                         k = -EIO;
665                                 else {
666                                         ifi = NLMSG_DATA(m->hdr);
667                                         m->next_rta = IFLA_RTA(ifi);
668                                 }
669                                 break;
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;
675                                 else {
676                                         ifa = NLMSG_DATA(m->hdr);
677                                         m->next_rta = IFA_RTA(ifa);
678                                 }
679                                 break;
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;
685                                 else {
686                                         rtm = NLMSG_DATA(m->hdr);
687                                         m->next_rta = RTM_RTA(rtm);
688                                 }
689                                 break;
690                         case NLMSG_NOOP:
691                                 k = 0;
692                                 break;
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 }
707
708 int 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 }