]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-rtnl/rtnl-message.c
Added attribute support for sd-rtnl
[thirdparty/systemd.git] / src / libsystemd / sd-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-util.h"
33 #include "rtnl-internal.h"
34
35 #define GET_CONTAINER(m, i) (i < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
36 #define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
37 #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
38 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
39
40 int message_new(sd_rtnl_message **ret, size_t initial_size) {
41 sd_rtnl_message *m;
42
43 assert_return(ret, -EINVAL);
44 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
45
46 m = new0(sd_rtnl_message, 1);
47 if (!m)
48 return -ENOMEM;
49
50 m->hdr = malloc0(initial_size);
51 if (!m->hdr) {
52 free(m);
53 return -ENOMEM;
54 }
55
56 m->n_ref = REFCNT_INIT;
57
58 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
59 m->sealed = false;
60
61 *ret = m;
62
63 return 0;
64 }
65
66 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
67 struct rtmsg *rtm;
68
69 assert_return(m, -EINVAL);
70 assert_return(m->hdr, -EINVAL);
71 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
72
73 rtm = NLMSG_DATA(m->hdr);
74
75 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
76 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
77 return -ERANGE;
78
79 rtm->rtm_dst_len = prefixlen;
80
81 return 0;
82 }
83
84 int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
85 sd_rtnl_message **ret) {
86 struct rtmsg *rtm;
87 int r;
88
89 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
90 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
91 assert_return(ret, -EINVAL);
92
93 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
94 if (r < 0)
95 return r;
96
97 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
98 (*ret)->hdr->nlmsg_type = nlmsg_type;
99 if (nlmsg_type == RTM_NEWROUTE)
100 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
101
102 rtm = NLMSG_DATA((*ret)->hdr);
103
104 UPDATE_RTA(*ret, RTM_RTA(rtm));
105
106 rtm->rtm_family = rtm_family;
107 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
108 rtm->rtm_type = RTN_UNICAST;
109 rtm->rtm_table = RT_TABLE_MAIN;
110 rtm->rtm_protocol = RTPROT_BOOT;
111
112 return 0;
113 }
114
115 int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
116 struct ifinfomsg *ifi;
117
118 assert_return(m, -EINVAL);
119 assert_return(m->hdr, -EINVAL);
120 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
121
122 ifi = NLMSG_DATA(m->hdr);
123
124 ifi->ifi_flags = flags;
125 if (change)
126 ifi->ifi_change = change;
127 else
128 ifi->ifi_change = 0xffffffff;
129
130 return 0;
131 }
132
133 int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
134 struct ifinfomsg *ifi;
135
136 assert_return(m, -EINVAL);
137 assert_return(m->hdr, -EINVAL);
138 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
139
140 ifi = NLMSG_DATA(m->hdr);
141
142 ifi->ifi_type = type;
143
144 return 0;
145 }
146
147 int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
148 struct ifinfomsg *ifi;
149 int r;
150
151 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
152 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
153 assert_return(ret, -EINVAL);
154
155 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
156 if (r < 0)
157 return r;
158
159 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
160 (*ret)->hdr->nlmsg_type = nlmsg_type;
161 if (nlmsg_type == RTM_NEWLINK)
162 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
163
164 ifi = NLMSG_DATA((*ret)->hdr);
165
166 ifi->ifi_family = AF_UNSPEC;
167 ifi->ifi_index = index;
168
169 UPDATE_RTA(*ret, IFLA_RTA(ifi));
170
171 return 0;
172 }
173
174 int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
175 struct ifaddrmsg *ifa;
176
177 assert_return(m, -EINVAL);
178 assert_return(m->hdr, -EINVAL);
179 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
180
181 ifa = NLMSG_DATA(m->hdr);
182
183 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
184 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
185 return -ERANGE;
186
187 ifa->ifa_prefixlen = prefixlen;
188
189 return 0;
190 }
191
192 int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
193 struct ifaddrmsg *ifa;
194
195 assert_return(m, -EINVAL);
196 assert_return(m->hdr, -EINVAL);
197 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
198
199 ifa = NLMSG_DATA(m->hdr);
200
201 ifa->ifa_flags = flags;
202
203 return 0;
204 }
205
206 int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
207 struct ifaddrmsg *ifa;
208
209 assert_return(m, -EINVAL);
210 assert_return(m->hdr, -EINVAL);
211 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
212
213 ifa = NLMSG_DATA(m->hdr);
214
215 ifa->ifa_scope = scope;
216
217 return 0;
218 }
219
220 int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family,
221 sd_rtnl_message **ret) {
222 struct ifaddrmsg *ifa;
223 int r;
224
225 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
226 assert_return(index > 0, -EINVAL);
227 assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
228 assert_return(ret, -EINVAL);
229
230 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
231 if (r < 0)
232 return r;
233
234 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
235 (*ret)->hdr->nlmsg_type = nlmsg_type;
236
237 ifa = NLMSG_DATA((*ret)->hdr);
238
239 ifa->ifa_index = index;
240 ifa->ifa_family = family;
241 if (family == AF_INET)
242 ifa->ifa_prefixlen = 32;
243 else if (family == AF_INET6)
244 ifa->ifa_prefixlen = 128;
245
246 UPDATE_RTA(*ret, IFA_RTA(ifa));
247
248 return 0;
249 }
250
251 sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
252 if (m)
253 assert_se(REFCNT_INC(m->n_ref) >= 2);
254
255 return m;
256 }
257
258 sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
259 if (m && REFCNT_DEC(m->n_ref) <= 0) {
260 free(m->hdr);
261 free(m);
262 }
263
264 return NULL;
265 }
266
267 int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
268 assert_return(m, -EINVAL);
269 assert_return(type, -EINVAL);
270
271 *type = m->hdr->nlmsg_type;
272
273 return 0;
274 }
275
276 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
277 struct ifinfomsg *ifi;
278
279 assert_return(m, -EINVAL);
280 assert_return(m->hdr, -EINVAL);
281 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
282 assert_return(ifindex, -EINVAL);
283
284 ifi = NLMSG_DATA(m->hdr);
285
286 *ifindex = ifi->ifi_index;
287
288 return 0;
289 }
290
291 int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
292 struct ifinfomsg *ifi;
293
294 assert_return(m, -EINVAL);
295 assert_return(m->hdr, -EINVAL);
296 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
297 assert_return(flags, -EINVAL);
298
299 ifi = NLMSG_DATA(m->hdr);
300
301 *flags = ifi->ifi_flags;
302
303 return 0;
304 }
305
306 /* If successful the updated message will be correctly aligned, if
307 unsuccessful the old message is untouched. */
308 static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
309 uint32_t rta_length, message_length;
310 struct nlmsghdr *new_hdr;
311 struct rtattr *rta;
312 char *padding;
313 unsigned i;
314
315 assert(m);
316 assert(m->hdr);
317 assert(!m->sealed);
318 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
319 assert(!data || data_length > 0);
320 assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
321
322 /* get the size of the new rta attribute (with padding at the end) */
323 rta_length = RTA_LENGTH(data_length);
324
325 /* get the new message size (with padding at the end) */
326 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
327
328 /* realloc to fit the new attribute */
329 new_hdr = realloc(m->hdr, message_length);
330 if (!new_hdr)
331 return -ENOMEM;
332 m->hdr = new_hdr;
333
334 /* get pointer to the attribute we are about to add */
335 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
336
337 /* if we are inside containers, extend them */
338 for (i = 0; i < m->n_containers; i++)
339 GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len;
340
341 /* fill in the attribute */
342 rta->rta_type = type;
343 rta->rta_len = rta_length;
344 if (!data) {
345 /* this is the start of a new container */
346 m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len;
347 } else {
348 /* we don't deal with the case where the user lies about the type
349 * and gives us too little data (so don't do that)
350 */
351 padding = mempcpy(RTA_DATA(rta), data, data_length);
352 /* make sure also the padding at the end of the message is initialized */
353 memzero(padding,
354 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
355 }
356
357 /* update message size */
358 m->hdr->nlmsg_len = message_length;
359
360 return 0;
361 }
362
363 int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
364 uint16_t rtm_type;
365 int r;
366
367 assert_return(m, -EINVAL);
368 assert_return(!m->sealed, -EPERM);
369 assert_return(data, -EINVAL);
370
371 r = sd_rtnl_message_get_type(m, &rtm_type);
372 if (r < 0)
373 return r;
374
375 /* check that the type is correct */
376 switch (rtm_type) {
377 case RTM_NEWLINK:
378 case RTM_SETLINK:
379 case RTM_GETLINK:
380 case RTM_DELLINK:
381 if (m->n_containers == 1) {
382 if (GET_CONTAINER(m, 0)->rta_type != IFLA_LINKINFO ||
383 type != IFLA_INFO_KIND)
384 return -ENOTSUP;
385 } else {
386 switch (type) {
387 case IFLA_IFNAME:
388 case IFLA_IFALIAS:
389 case IFLA_QDISC:
390 break;
391 default:
392 return -ENOTSUP;
393 }
394 }
395 break;
396 case RTM_NEWADDR:
397 case RTM_GETADDR:
398 case RTM_DELADDR:
399 if (type != IFA_LABEL)
400 return -ENOTSUP;
401 break;
402 default:
403 return -ENOTSUP;
404 }
405
406 r = add_rtattr(m, type, data, strlen(data) + 1);
407 if (r < 0)
408 return r;
409
410 return 0;
411 }
412
413 int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
414 uint16_t rtm_type;
415 int r;
416
417 assert_return(m, -EINVAL);
418 assert_return(!m->sealed, -EPERM);
419
420 r = sd_rtnl_message_get_type(m, &rtm_type);
421 if (r < 0)
422 return r;
423
424 switch (rtm_type) {
425 case RTM_NEWLINK:
426 case RTM_SETLINK:
427 case RTM_GETLINK:
428 case RTM_DELLINK:
429 switch (type) {
430 case IFLA_CARRIER:
431 case IFLA_OPERSTATE:
432 case IFLA_LINKMODE:
433 break;
434 default:
435 return -ENOTSUP;
436 }
437
438 break;
439 default:
440 return -ENOTSUP;
441 }
442
443 r = add_rtattr(m, type, &data, sizeof(uint8_t));
444 if (r < 0)
445 return r;
446
447 return 0;
448 }
449
450
451 int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
452 uint16_t rtm_type;
453 int r;
454
455 assert_return(m, -EINVAL);
456 assert_return(!m->sealed, -EPERM);
457
458 r = sd_rtnl_message_get_type(m, &rtm_type);
459 if (r < 0)
460 return r;
461
462 /* check that the type is correct */
463 switch (rtm_type) {
464 case RTM_NEWLINK:
465 case RTM_SETLINK:
466 case RTM_GETLINK:
467 case RTM_DELLINK:
468 if (m->n_containers == 2 &&
469 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
470 GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA &&
471 type == IFLA_VLAN_ID)
472 break;
473 else
474 return -ENOTSUP;
475 break;
476 default:
477 return -ENOTSUP;
478 }
479
480 r = add_rtattr(m, type, &data, sizeof(uint16_t));
481 if (r < 0)
482 return r;
483
484 return 0;
485 }
486
487 int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
488 uint16_t rtm_type;
489 int r;
490
491 assert_return(m, -EINVAL);
492 assert_return(!m->sealed, -EPERM);
493
494 r = sd_rtnl_message_get_type(m, &rtm_type);
495 if (r < 0)
496 return r;
497
498 /* check that the type is correct */
499 switch (rtm_type) {
500 case RTM_NEWLINK:
501 case RTM_SETLINK:
502 case RTM_GETLINK:
503 case RTM_DELLINK:
504 switch (type) {
505 case IFLA_MASTER:
506 case IFLA_MTU:
507 case IFLA_LINK:
508 case IFLA_GROUP:
509 case IFLA_TXQLEN:
510 case IFLA_NUM_TX_QUEUES:
511 case IFLA_NUM_RX_QUEUES:
512 break;
513 default:
514 return -ENOTSUP;
515 }
516 break;
517 case RTM_NEWROUTE:
518 case RTM_GETROUTE:
519 case RTM_DELROUTE:
520 switch (type) {
521 case RTA_TABLE:
522 case RTA_PRIORITY:
523 case RTA_IIF:
524 case RTA_OIF:
525 break;
526 default:
527 return -ENOTSUP;
528 }
529 break;
530 default:
531 return -ENOTSUP;
532 }
533
534 r = add_rtattr(m, type, &data, sizeof(uint32_t));
535 if (r < 0)
536 return r;
537
538 return 0;
539 }
540
541 int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
542 struct ifaddrmsg *ifa;
543 struct rtmsg *rtm;
544 uint16_t rtm_type;
545 int r;
546
547 assert_return(m, -EINVAL);
548 assert_return(!m->sealed, -EPERM);
549 assert_return(data, -EINVAL);
550
551 r = sd_rtnl_message_get_type(m, &rtm_type);
552 if (r < 0)
553 return r;
554
555 /* check that the type is correct */
556 switch (rtm_type) {
557 case RTM_NEWADDR:
558 case RTM_GETADDR:
559 case RTM_DELADDR:
560 switch (type) {
561 case IFA_ADDRESS:
562 case IFA_LOCAL:
563 case IFA_BROADCAST:
564 case IFA_ANYCAST:
565 ifa = NLMSG_DATA(m->hdr);
566
567 if (ifa->ifa_family != AF_INET)
568 return -EINVAL;
569
570 break;
571 default:
572 return -ENOTSUP;
573 }
574 break;
575 case RTM_NEWROUTE:
576 case RTM_GETROUTE:
577 case RTM_DELROUTE:
578 switch (type) {
579 case RTA_DST:
580 case RTA_SRC:
581 case RTA_GATEWAY:
582 rtm = NLMSG_DATA(m->hdr);
583
584 if (rtm->rtm_family != AF_INET)
585 return -EINVAL;
586
587 break;
588 default:
589 return -ENOTSUP;
590 }
591 break;
592 default:
593 return -ENOTSUP;
594 }
595
596 r = add_rtattr(m, type, data, sizeof(struct in_addr));
597 if (r < 0)
598 return r;
599
600 return 0;
601 }
602
603 int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
604 struct ifaddrmsg *ifa;
605 struct rtmsg *rtm;
606 uint16_t rtm_type;
607 int r;
608
609 assert_return(m, -EINVAL);
610 assert_return(!m->sealed, -EPERM);
611 assert_return(data, -EINVAL);
612
613 r = sd_rtnl_message_get_type(m, &rtm_type);
614 if (r < 0)
615 return r;
616
617 /* check that the type is correct */
618 switch (rtm_type) {
619 case RTM_NEWADDR:
620 case RTM_GETADDR:
621 case RTM_DELADDR:
622 switch (type) {
623 case IFA_ADDRESS:
624 case IFA_LOCAL:
625 case IFA_BROADCAST:
626 case IFA_ANYCAST:
627 ifa = NLMSG_DATA(m->hdr);
628
629 if (ifa->ifa_family != AF_INET6)
630 return -EINVAL;
631
632 break;
633 default:
634 return -ENOTSUP;
635 }
636 break;
637 case RTM_NEWROUTE:
638 case RTM_GETROUTE:
639 case RTM_DELROUTE:
640 switch (type) {
641 case RTA_DST:
642 case RTA_SRC:
643 case RTA_GATEWAY:
644 rtm = NLMSG_DATA(m->hdr);
645
646 if (rtm->rtm_family != AF_INET6)
647 return -EINVAL;
648
649 break;
650 default:
651 return -ENOTSUP;
652 }
653 default:
654 return -ENOTSUP;
655 }
656
657 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
658 if (r < 0)
659 return r;
660
661 return 0;
662 }
663
664 int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
665 uint16_t rtm_type;
666 int r;
667
668 assert_return(m, -EINVAL);
669 assert_return(!m->sealed, -EPERM);
670 assert_return(data, -EINVAL);
671
672 sd_rtnl_message_get_type(m, &rtm_type);
673
674 switch (rtm_type) {
675 case RTM_NEWLINK:
676 case RTM_SETLINK:
677 case RTM_DELLINK:
678 case RTM_GETLINK:
679 switch (type) {
680 case IFLA_ADDRESS:
681 case IFLA_BROADCAST:
682 break;
683 default:
684 return -ENOTSUP;
685 }
686 break;
687 default:
688 return -ENOTSUP;
689 }
690
691 r = add_rtattr(m, type, data, ETH_ALEN);
692 if (r < 0)
693 return r;
694
695 return 0;
696 }
697
698 int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
699 uint16_t rtm_type;
700
701 assert_return(m, -EINVAL);
702 assert_return(!m->sealed, -EPERM);
703
704 sd_rtnl_message_get_type(m, &rtm_type);
705
706 if (rtnl_message_type_is_link(rtm_type)) {
707 if ((type == IFLA_LINKINFO && m->n_containers == 0) ||
708 (type == IFLA_INFO_DATA && m->n_containers == 1 &&
709 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO))
710 return add_rtattr(m, type, NULL, 0);
711 else
712 return -ENOTSUP;
713 } else
714 return -ENOTSUP;
715
716 return 0;
717 }
718
719 int sd_rtnl_message_close_container(sd_rtnl_message *m) {
720 assert_return(m, -EINVAL);
721 assert_return(!m->sealed, -EPERM);
722 assert_return(m->n_containers > 0, -EINVAL);
723
724 m->n_containers --;
725
726 return 0;
727 }
728
729 int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
730 size_t remaining_size;
731 uint16_t rtm_type;
732 int r;
733
734 assert_return(m, -EINVAL);
735 assert_return(m->sealed, -EPERM);
736 assert_return(m->next_rta_offset, -EINVAL);
737 assert_return(type, -EINVAL);
738 assert_return(data, -EINVAL);
739
740 /* only read until the end of the current container */
741 if (m->n_containers)
742 remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len -
743 (m->next_rta_offset -
744 m->container_offsets[m->n_containers - 1]);
745 else
746 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
747
748 if (!RTA_OK(NEXT_RTA(m), remaining_size))
749 return 0;
750
751 /* if we read a container, enter it and return its type */
752 r = sd_rtnl_message_get_type(m, &rtm_type);
753 if (r < 0)
754 return r;
755
756 *type = NEXT_RTA(m)->rta_type;
757
758 if (rtnl_message_type_is_link(rtm_type) &&
759 ((m->n_containers == 0 &&
760 NEXT_RTA(m)->rta_type == IFLA_LINKINFO) ||
761 (m->n_containers == 1 &&
762 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
763 NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) {
764 *data = NULL;
765 PUSH_CONTAINER(m, NEXT_RTA(m));
766 UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m)));
767 } else {
768 *data = RTA_DATA(NEXT_RTA(m));
769 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
770 }
771
772 return 1;
773 }
774
775 int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
776 assert_return(m, -EINVAL);
777 assert_return(m->sealed, -EINVAL);
778 assert_return(m->n_containers > 0, -EINVAL);
779
780 m->n_containers --;
781
782 return 0;
783 }
784
785 uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
786 assert(m);
787 assert(m->hdr);
788
789 return m->hdr->nlmsg_seq;
790 }
791
792 int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
793 struct nlmsgerr *err;
794
795 assert_return(m, -EINVAL);
796 assert_return(m->hdr, -EINVAL);
797
798 if (m->hdr->nlmsg_type != NLMSG_ERROR)
799 return 0;
800
801 err = NLMSG_DATA(m->hdr);
802
803 return err->error;
804 }
805
806 int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
807 int r;
808
809 assert(m);
810 assert(m->hdr);
811
812 if (m->sealed)
813 return -EPERM;
814
815 if (nl)
816 m->hdr->nlmsg_seq = nl->serial++;
817
818 m->sealed = true;
819
820 r = sd_rtnl_message_rewind(m);
821 if (r < 0)
822 return r;
823
824 return 0;
825 }
826
827 static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
828 assert(rtnl);
829 assert(need);
830
831 /* ioctl(rtnl->fd, FIONREAD, &need)
832 Does not appear to work on netlink sockets. libnl uses
833 MSG_PEEK instead. I don't know if that is worth the
834 extra roundtrip.
835
836 For now we simply use the maximum message size the kernel
837 may use (NLMSG_GOODSIZE), and then realloc to the actual
838 size after reading the message (hence avoiding huge memory
839 usage in case many small messages are kept around) */
840 *need = page_size();
841 if (*need > 8192UL)
842 *need = 8192UL;
843
844 return 0;
845 }
846
847 /* returns the number of bytes sent, or a negative error code */
848 int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
849 union {
850 struct sockaddr sa;
851 struct sockaddr_nl nl;
852 } addr = {
853 .nl.nl_family = AF_NETLINK,
854 };
855 ssize_t k;
856
857 assert(nl);
858 assert(m);
859 assert(m->hdr);
860
861 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
862 0, &addr.sa, sizeof(addr));
863 if (k < 0)
864 return (errno == EAGAIN) ? 0 : -errno;
865
866 return k;
867 }
868
869 /* On success, the number of bytes received is returned and *ret points to the received message
870 * which has a valid header and the correct size.
871 * If nothing useful was received 0 is returned.
872 * On failure, a negative error code is returned.
873 */
874 int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
875 sd_rtnl_message *m;
876 union {
877 struct sockaddr sa;
878 struct sockaddr_nl nl;
879 } addr;
880 socklen_t addr_len;
881 int r;
882 ssize_t k;
883 size_t need;
884
885 assert(nl);
886 assert(ret);
887
888 r = message_receive_need(nl, &need);
889 if (r < 0)
890 return r;
891
892 r = message_new(&m, need);
893 if (r < 0)
894 return r;
895
896 /* don't allow sealing/appending to received messages */
897 m->sealed = true;
898
899 addr_len = sizeof(addr);
900
901 k = recvfrom(nl->fd, m->hdr, need,
902 0, &addr.sa, &addr_len);
903 if (k < 0)
904 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
905 else if (k == 0)
906 k = -ECONNRESET; /* connection was closed by the kernel */
907 else if (addr_len != sizeof(addr.nl) ||
908 addr.nl.nl_family != AF_NETLINK)
909 k = -EIO; /* not a netlink message */
910 else if (addr.nl.nl_pid != 0)
911 k = 0; /* not from the kernel */
912 else if ((size_t) k < sizeof(struct nlmsghdr) ||
913 (size_t) k < m->hdr->nlmsg_len)
914 k = -EIO; /* too small (we do accept too big though) */
915 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
916 k = 0; /* not broadcast and not for us */
917
918 if (k > 0)
919 switch (m->hdr->nlmsg_type) {
920 struct ifinfomsg *ifi;
921 struct ifaddrmsg *ifa;
922 struct rtmsg *rtm;
923
924 /* check that the size matches the message type */
925 case NLMSG_ERROR:
926 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
927 k = -EIO;
928 break;
929 case RTM_NEWLINK:
930 case RTM_SETLINK:
931 case RTM_DELLINK:
932 case RTM_GETLINK:
933 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
934 k = -EIO;
935 else {
936 ifi = NLMSG_DATA(m->hdr);
937 UPDATE_RTA(m, IFLA_RTA(ifi));
938 }
939 break;
940 case RTM_NEWADDR:
941 case RTM_DELADDR:
942 case RTM_GETADDR:
943 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
944 k = -EIO;
945 else {
946 ifa = NLMSG_DATA(m->hdr);
947 UPDATE_RTA(m, IFA_RTA(ifa));
948 }
949 break;
950 case RTM_NEWROUTE:
951 case RTM_DELROUTE:
952 case RTM_GETROUTE:
953 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
954 k = -EIO;
955 else {
956 rtm = NLMSG_DATA(m->hdr);
957 UPDATE_RTA(m, RTM_RTA(rtm));
958 }
959 break;
960 case NLMSG_NOOP:
961 k = 0;
962 break;
963 default:
964 k = 0; /* ignoring message of unknown type */
965 }
966
967 if (k <= 0)
968 sd_rtnl_message_unref(m);
969 else {
970 /* we probably allocated way too much memory, give it back */
971 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
972 *ret = m;
973 }
974
975 return k;
976 }
977
978 int sd_rtnl_message_rewind(sd_rtnl_message *m) {
979 struct ifinfomsg *ifi;
980 struct ifaddrmsg *ifa;
981 struct rtmsg *rtm;
982
983 assert_return(m, -EINVAL);
984 assert_return(m->sealed, -EPERM);
985 assert_return(m->hdr, -EINVAL);
986
987 switch(m->hdr->nlmsg_type) {
988 case RTM_NEWLINK:
989 case RTM_SETLINK:
990 case RTM_GETLINK:
991 case RTM_DELLINK:
992 ifi = NLMSG_DATA(m->hdr);
993 UPDATE_RTA(m, IFLA_RTA(ifi));
994
995 break;
996 case RTM_NEWADDR:
997 case RTM_GETADDR:
998 case RTM_DELADDR:
999 ifa = NLMSG_DATA(m->hdr);
1000 UPDATE_RTA(m, IFA_RTA(ifa));
1001
1002 break;
1003 case RTM_NEWROUTE:
1004 case RTM_GETROUTE:
1005 case RTM_DELROUTE:
1006 rtm = NLMSG_DATA(m->hdr);
1007 UPDATE_RTA(m, RTM_RTA(rtm));
1008
1009 break;
1010 default:
1011 return -ENOTSUP;
1012 }
1013
1014 m->n_containers = 0;
1015
1016 return 0;
1017 }