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