]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-rtnl/rtnl-message.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <netinet/in.h>
23 #include <netinet/ether.h>
26 #include <linux/veth.h>
33 #include "rtnl-util.h"
34 #include "rtnl-internal.h"
36 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
37 #define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
38 #define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
39 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
41 int message_new(sd_rtnl
*rtnl
, sd_rtnl_message
**ret
, size_t initial_size
) {
44 assert_return(ret
, -EINVAL
);
45 assert_return(initial_size
>= sizeof(struct nlmsghdr
), -EINVAL
);
47 m
= new0(sd_rtnl_message
, 1);
51 m
->hdr
= malloc0(initial_size
);
57 m
->n_ref
= REFCNT_INIT
;
59 m
->hdr
->nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
63 m
->rtnl
= sd_rtnl_ref(rtnl
);
70 int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message
*m
, unsigned char prefixlen
) {
73 assert_return(m
, -EINVAL
);
74 assert_return(m
->hdr
, -EINVAL
);
75 assert_return(rtnl_message_type_is_route(m
->hdr
->nlmsg_type
), -EINVAL
);
77 rtm
= NLMSG_DATA(m
->hdr
);
79 if ((rtm
->rtm_family
== AF_INET
&& prefixlen
> 32) ||
80 (rtm
->rtm_family
== AF_INET6
&& prefixlen
> 128))
83 rtm
->rtm_dst_len
= prefixlen
;
88 int sd_rtnl_message_route_set_scope(sd_rtnl_message
*m
, unsigned char scope
) {
91 assert_return(m
, -EINVAL
);
92 assert_return(m
->hdr
, -EINVAL
);
93 assert_return(rtnl_message_type_is_route(m
->hdr
->nlmsg_type
), -EINVAL
);
95 rtm
= NLMSG_DATA(m
->hdr
);
97 rtm
->rtm_scope
= scope
;
102 int sd_rtnl_message_new_route(sd_rtnl
*rtnl
, sd_rtnl_message
**ret
,
103 uint16_t nlmsg_type
, unsigned char rtm_family
) {
107 assert_return(rtnl_message_type_is_route(nlmsg_type
), -EINVAL
);
108 assert_return(rtm_family
== AF_INET
|| rtm_family
== AF_INET6
, -EINVAL
);
109 assert_return(ret
, -EINVAL
);
111 r
= message_new(rtnl
, ret
, NLMSG_SPACE(sizeof(struct rtmsg
)));
115 (*ret
)->hdr
->nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
116 (*ret
)->hdr
->nlmsg_type
= nlmsg_type
;
117 if (nlmsg_type
== RTM_NEWROUTE
)
118 (*ret
)->hdr
->nlmsg_flags
|= NLM_F_CREATE
| NLM_F_EXCL
;
120 rtm
= NLMSG_DATA((*ret
)->hdr
);
122 UPDATE_RTA(*ret
, RTM_RTA(rtm
));
124 rtm
->rtm_family
= rtm_family
;
125 rtm
->rtm_scope
= RT_SCOPE_UNIVERSE
;
126 rtm
->rtm_type
= RTN_UNICAST
;
127 rtm
->rtm_table
= RT_TABLE_MAIN
;
128 rtm
->rtm_protocol
= RTPROT_BOOT
;
133 int sd_rtnl_message_link_set_flags(sd_rtnl_message
*m
, unsigned flags
, unsigned change
) {
134 struct ifinfomsg
*ifi
;
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 assert_return(change
, -EINVAL
);
141 ifi
= NLMSG_DATA(m
->hdr
);
143 ifi
->ifi_flags
= flags
;
144 ifi
->ifi_change
= change
;
149 int sd_rtnl_message_link_set_type(sd_rtnl_message
*m
, unsigned type
) {
150 struct ifinfomsg
*ifi
;
152 assert_return(m
, -EINVAL
);
153 assert_return(m
->hdr
, -EINVAL
);
154 assert_return(rtnl_message_type_is_link(m
->hdr
->nlmsg_type
), -EINVAL
);
156 ifi
= NLMSG_DATA(m
->hdr
);
158 ifi
->ifi_type
= type
;
163 int sd_rtnl_message_new_link(sd_rtnl
*rtnl
, sd_rtnl_message
**ret
,
164 uint16_t nlmsg_type
, int index
) {
165 struct ifinfomsg
*ifi
;
168 assert_return(rtnl_message_type_is_link(nlmsg_type
), -EINVAL
);
169 assert_return(nlmsg_type
!= RTM_DELLINK
|| index
> 0, -EINVAL
);
170 assert_return(ret
, -EINVAL
);
172 r
= message_new(rtnl
, ret
, NLMSG_SPACE(sizeof(struct ifinfomsg
)));
176 (*ret
)->hdr
->nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
177 (*ret
)->hdr
->nlmsg_type
= nlmsg_type
;
178 if (nlmsg_type
== RTM_NEWLINK
)
179 (*ret
)->hdr
->nlmsg_flags
|= NLM_F_CREATE
| NLM_F_EXCL
;
181 ifi
= NLMSG_DATA((*ret
)->hdr
);
183 ifi
->ifi_family
= AF_UNSPEC
;
184 ifi
->ifi_index
= index
;
186 UPDATE_RTA(*ret
, IFLA_RTA(ifi
));
191 int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message
*m
, unsigned char prefixlen
) {
192 struct ifaddrmsg
*ifa
;
194 assert_return(m
, -EINVAL
);
195 assert_return(m
->hdr
, -EINVAL
);
196 assert_return(rtnl_message_type_is_addr(m
->hdr
->nlmsg_type
), -EINVAL
);
198 ifa
= NLMSG_DATA(m
->hdr
);
200 if ((ifa
->ifa_family
== AF_INET
&& prefixlen
> 32) ||
201 (ifa
->ifa_family
== AF_INET6
&& prefixlen
> 128))
204 ifa
->ifa_prefixlen
= prefixlen
;
209 int sd_rtnl_message_addr_set_flags(sd_rtnl_message
*m
, unsigned char flags
) {
210 struct ifaddrmsg
*ifa
;
212 assert_return(m
, -EINVAL
);
213 assert_return(m
->hdr
, -EINVAL
);
214 assert_return(rtnl_message_type_is_addr(m
->hdr
->nlmsg_type
), -EINVAL
);
216 ifa
= NLMSG_DATA(m
->hdr
);
218 ifa
->ifa_flags
= flags
;
223 int sd_rtnl_message_addr_set_scope(sd_rtnl_message
*m
, unsigned char scope
) {
224 struct ifaddrmsg
*ifa
;
226 assert_return(m
, -EINVAL
);
227 assert_return(m
->hdr
, -EINVAL
);
228 assert_return(rtnl_message_type_is_addr(m
->hdr
->nlmsg_type
), -EINVAL
);
230 ifa
= NLMSG_DATA(m
->hdr
);
232 ifa
->ifa_scope
= scope
;
237 int sd_rtnl_message_new_addr(sd_rtnl
*rtnl
, sd_rtnl_message
**ret
,
238 uint16_t nlmsg_type
, int index
,
239 unsigned char family
) {
240 struct ifaddrmsg
*ifa
;
243 assert_return(rtnl_message_type_is_addr(nlmsg_type
), -EINVAL
);
244 assert_return(index
> 0, -EINVAL
);
245 assert_return(family
== AF_INET
|| family
== AF_INET6
, -EINVAL
);
246 assert_return(ret
, -EINVAL
);
248 r
= message_new(rtnl
, ret
, NLMSG_SPACE(sizeof(struct ifaddrmsg
)));
252 (*ret
)->hdr
->nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
253 (*ret
)->hdr
->nlmsg_type
= nlmsg_type
;
254 if (nlmsg_type
== RTM_GETADDR
&& family
== AF_INET
)
255 (*ret
)->hdr
->nlmsg_flags
|= NLM_F_DUMP
;
257 ifa
= NLMSG_DATA((*ret
)->hdr
);
259 ifa
->ifa_index
= index
;
260 ifa
->ifa_family
= family
;
261 if (family
== AF_INET
)
262 ifa
->ifa_prefixlen
= 32;
263 else if (family
== AF_INET6
)
264 ifa
->ifa_prefixlen
= 128;
266 UPDATE_RTA(*ret
, IFA_RTA(ifa
));
271 sd_rtnl_message
*sd_rtnl_message_ref(sd_rtnl_message
*m
) {
273 assert_se(REFCNT_INC(m
->n_ref
) >= 2);
278 sd_rtnl_message
*sd_rtnl_message_unref(sd_rtnl_message
*m
) {
279 if (m
&& REFCNT_DEC(m
->n_ref
) <= 0) {
280 sd_rtnl_unref(m
->rtnl
);
282 free(m
->rta_offset_tb
);
289 int sd_rtnl_message_get_type(sd_rtnl_message
*m
, uint16_t *type
) {
290 assert_return(m
, -EINVAL
);
291 assert_return(type
, -EINVAL
);
293 *type
= m
->hdr
->nlmsg_type
;
298 int sd_rtnl_message_is_broadcast(sd_rtnl_message
*m
) {
299 assert_return(m
, -EINVAL
);
301 return !m
->hdr
->nlmsg_pid
;
304 int sd_rtnl_message_link_get_ifindex(sd_rtnl_message
*m
, int *ifindex
) {
305 struct ifinfomsg
*ifi
;
307 assert_return(m
, -EINVAL
);
308 assert_return(m
->hdr
, -EINVAL
);
309 assert_return(rtnl_message_type_is_link(m
->hdr
->nlmsg_type
), -EINVAL
);
310 assert_return(ifindex
, -EINVAL
);
312 ifi
= NLMSG_DATA(m
->hdr
);
314 *ifindex
= ifi
->ifi_index
;
319 int sd_rtnl_message_link_get_flags(sd_rtnl_message
*m
, unsigned *flags
) {
320 struct ifinfomsg
*ifi
;
322 assert_return(m
, -EINVAL
);
323 assert_return(m
->hdr
, -EINVAL
);
324 assert_return(rtnl_message_type_is_link(m
->hdr
->nlmsg_type
), -EINVAL
);
325 assert_return(flags
, -EINVAL
);
327 ifi
= NLMSG_DATA(m
->hdr
);
329 *flags
= ifi
->ifi_flags
;
334 /* If successful the updated message will be correctly aligned, if
335 unsuccessful the old message is untouched. */
336 static int add_rtattr(sd_rtnl_message
*m
, unsigned short type
, const void *data
, size_t data_length
) {
337 uint32_t rta_length
, message_length
;
338 struct nlmsghdr
*new_hdr
;
346 assert(NLMSG_ALIGN(m
->hdr
->nlmsg_len
) == m
->hdr
->nlmsg_len
);
347 assert(!data
|| data_length
> 0);
348 assert(data
|| m
->n_containers
< RTNL_CONTAINER_DEPTH
);
350 /* get the size of the new rta attribute (with padding at the end) */
351 rta_length
= RTA_LENGTH(data_length
);
353 /* get the new message size (with padding at the end) */
354 message_length
= m
->hdr
->nlmsg_len
+ RTA_ALIGN(rta_length
);
356 /* realloc to fit the new attribute */
357 new_hdr
= realloc(m
->hdr
, message_length
);
362 /* get pointer to the attribute we are about to add */
363 rta
= (struct rtattr
*) ((uint8_t *) m
->hdr
+ m
->hdr
->nlmsg_len
);
365 /* if we are inside containers, extend them */
366 for (i
= 0; i
< m
->n_containers
; i
++)
367 GET_CONTAINER(m
, i
)->rta_len
+= message_length
- m
->hdr
->nlmsg_len
;
369 /* fill in the attribute */
370 rta
->rta_type
= type
;
371 rta
->rta_len
= rta_length
;
373 /* this is the start of a new container */
374 m
->container_offsets
[m
->n_containers
++] = m
->hdr
->nlmsg_len
;
376 /* we don't deal with the case where the user lies about the type
377 * and gives us too little data (so don't do that)
379 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
380 /* make sure also the padding at the end of the message is initialized */
382 (uint8_t *) m
->hdr
+ message_length
- (uint8_t *) padding
);
385 /* update message size */
386 m
->hdr
->nlmsg_len
= message_length
;
391 int sd_rtnl_message_append_string(sd_rtnl_message
*m
, unsigned short type
, const char *data
) {
395 assert_return(m
, -EINVAL
);
396 assert_return(!m
->sealed
, -EPERM
);
397 assert_return(data
, -EINVAL
);
399 r
= sd_rtnl_message_get_type(m
, &rtm_type
);
403 /* check that the type is correct */
409 if (m
->n_containers
== 1) {
410 if (GET_CONTAINER(m
, 0)->rta_type
!= IFLA_LINKINFO
||
411 type
!= IFLA_INFO_KIND
)
427 if (type
!= IFA_LABEL
)
434 r
= add_rtattr(m
, type
, data
, strlen(data
) + 1);
441 int sd_rtnl_message_append_u8(sd_rtnl_message
*m
, unsigned short type
, uint8_t data
) {
445 assert_return(m
, -EINVAL
);
446 assert_return(!m
->sealed
, -EPERM
);
448 r
= sd_rtnl_message_get_type(m
, &rtm_type
);
471 r
= add_rtattr(m
, type
, &data
, sizeof(uint8_t));
479 int sd_rtnl_message_append_u16(sd_rtnl_message
*m
, unsigned short type
, uint16_t data
) {
483 assert_return(m
, -EINVAL
);
484 assert_return(!m
->sealed
, -EPERM
);
486 r
= sd_rtnl_message_get_type(m
, &rtm_type
);
490 /* check that the type is correct */
496 if (m
->n_containers
== 2 &&
497 GET_CONTAINER(m
, 0)->rta_type
== IFLA_LINKINFO
&&
498 GET_CONTAINER(m
, 1)->rta_type
== IFLA_INFO_DATA
&&
499 type
== IFLA_VLAN_ID
)
508 r
= add_rtattr(m
, type
, &data
, sizeof(uint16_t));
515 int sd_rtnl_message_append_u32(sd_rtnl_message
*m
, unsigned short type
, uint32_t data
) {
519 assert_return(m
, -EINVAL
);
520 assert_return(!m
->sealed
, -EPERM
);
522 r
= sd_rtnl_message_get_type(m
, &rtm_type
);
526 /* check that the type is correct */
540 case IFLA_NET_NS_PID
:
541 case IFLA_PROMISCUITY
:
542 case IFLA_NUM_TX_QUEUES
:
543 case IFLA_NUM_RX_QUEUES
:
544 case IFLA_MACVLAN_MODE
:
568 r
= add_rtattr(m
, type
, &data
, sizeof(uint32_t));
575 int sd_rtnl_message_append_in_addr(sd_rtnl_message
*m
, unsigned short type
, const struct in_addr
*data
) {
576 struct ifaddrmsg
*ifa
;
581 assert_return(m
, -EINVAL
);
582 assert_return(!m
->sealed
, -EPERM
);
583 assert_return(data
, -EINVAL
);
585 r
= sd_rtnl_message_get_type(m
, &rtm_type
);
589 /* check that the type is correct */
599 ifa
= NLMSG_DATA(m
->hdr
);
601 if (ifa
->ifa_family
!= AF_INET
)
616 rtm
= NLMSG_DATA(m
->hdr
);
618 if (rtm
->rtm_family
!= AF_INET
)
630 r
= add_rtattr(m
, type
, data
, sizeof(struct in_addr
));
637 int sd_rtnl_message_append_in6_addr(sd_rtnl_message
*m
, unsigned short type
, const struct in6_addr
*data
) {
638 struct ifaddrmsg
*ifa
;
643 assert_return(m
, -EINVAL
);
644 assert_return(!m
->sealed
, -EPERM
);
645 assert_return(data
, -EINVAL
);
647 r
= sd_rtnl_message_get_type(m
, &rtm_type
);
651 /* check that the type is correct */
661 ifa
= NLMSG_DATA(m
->hdr
);
663 if (ifa
->ifa_family
!= AF_INET6
)
678 rtm
= NLMSG_DATA(m
->hdr
);
680 if (rtm
->rtm_family
!= AF_INET6
)
691 r
= add_rtattr(m
, type
, data
, sizeof(struct in6_addr
));
698 int sd_rtnl_message_append_ether_addr(sd_rtnl_message
*m
, unsigned short type
, const struct ether_addr
*data
) {
702 assert_return(m
, -EINVAL
);
703 assert_return(!m
->sealed
, -EPERM
);
704 assert_return(data
, -EINVAL
);
706 sd_rtnl_message_get_type(m
, &rtm_type
);
725 r
= add_rtattr(m
, type
, data
, ETH_ALEN
);
732 int sd_rtnl_message_open_container(sd_rtnl_message
*m
, unsigned short type
) {
735 assert_return(m
, -EINVAL
);
736 assert_return(!m
->sealed
, -EPERM
);
738 sd_rtnl_message_get_type(m
, &rtm_type
);
740 if (rtnl_message_type_is_link(rtm_type
)) {
742 if ((type
== IFLA_LINKINFO
&& m
->n_containers
== 0) ||
743 (type
== IFLA_INFO_DATA
&& m
->n_containers
== 1 &&
744 GET_CONTAINER(m
, 0)->rta_type
== IFLA_LINKINFO
))
745 return add_rtattr(m
, type
, NULL
, 0);
746 else if (type
== VETH_INFO_PEER
&& m
->n_containers
== 2 &&
747 GET_CONTAINER(m
, 1)->rta_type
== IFLA_INFO_DATA
&&
748 GET_CONTAINER(m
, 0)->rta_type
== IFLA_LINKINFO
)
749 return add_rtattr(m
, type
, NULL
, sizeof(struct ifinfomsg
));
755 int sd_rtnl_message_close_container(sd_rtnl_message
*m
) {
756 assert_return(m
, -EINVAL
);
757 assert_return(!m
->sealed
, -EPERM
);
758 assert_return(m
->n_containers
> 0, -EINVAL
);
765 int sd_rtnl_message_read(sd_rtnl_message
*m
, unsigned short *type
, void **data
) {
766 size_t remaining_size
;
770 assert_return(m
, -EINVAL
);
771 assert_return(m
->sealed
, -EPERM
);
772 assert_return(m
->next_rta_offset
, -EINVAL
);
773 assert_return(type
, -EINVAL
);
774 assert_return(data
, -EINVAL
);
776 /* only read until the end of the current container */
778 remaining_size
= GET_CONTAINER(m
, m
->n_containers
- 1)->rta_len
-
779 (m
->next_rta_offset
-
780 m
->container_offsets
[m
->n_containers
- 1]);
782 remaining_size
= m
->hdr
->nlmsg_len
- m
->next_rta_offset
;
784 if (!RTA_OK(NEXT_RTA(m
), remaining_size
))
787 /* if we read a container, return its type, but do not enter it*/
788 r
= sd_rtnl_message_get_type(m
, &rtm_type
);
792 *type
= NEXT_RTA(m
)->rta_type
;
794 if (rtnl_message_type_is_link(rtm_type
) &&
795 ((m
->n_containers
== 0 &&
796 NEXT_RTA(m
)->rta_type
== IFLA_LINKINFO
) ||
797 (m
->n_containers
== 1 &&
798 GET_CONTAINER(m
, 0)->rta_type
== IFLA_LINKINFO
&&
799 NEXT_RTA(m
)->rta_type
== IFLA_INFO_DATA
)))
802 *data
= RTA_DATA(NEXT_RTA(m
));
804 UPDATE_RTA(m
, RTA_NEXT(NEXT_RTA(m
), remaining_size
));
809 int rtnl_message_read_internal(sd_rtnl_message
*m
, unsigned short type
, void **data
) {
810 assert_return(m
, -EINVAL
);
811 assert_return(m
->sealed
, -EPERM
);
812 assert_return(data
, -EINVAL
);
813 assert_return(m
->rta_offset_tb
, -EINVAL
);
814 assert_return(type
< m
->rta_tb_size
, -EINVAL
);
816 if(!m
->rta_offset_tb
[type
])
819 *data
= RTA_DATA((struct rtattr
*)((uint8_t *) m
->hdr
+ m
->rta_offset_tb
[type
]));
824 int sd_rtnl_message_read_string(sd_rtnl_message
*m
, unsigned short type
, char **data
) {
828 assert_return(data
, -EINVAL
);
830 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
834 *data
= (char *) attr_data
;
839 int sd_rtnl_message_read_u8(sd_rtnl_message
*m
, unsigned short type
, uint8_t *data
) {
843 assert_return(data
, -EINVAL
);
845 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
849 *data
= *(uint8_t *) attr_data
;
854 int sd_rtnl_message_read_u16(sd_rtnl_message
*m
, unsigned short type
, uint16_t *data
) {
858 assert_return(data
, -EINVAL
);
860 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
864 *data
= *(uint16_t *) attr_data
;
869 int sd_rtnl_message_read_u32(sd_rtnl_message
*m
, unsigned short type
, uint32_t *data
) {
873 assert_return(data
, -EINVAL
);
875 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
879 *data
= *(uint32_t *) attr_data
;
884 int sd_rtnl_message_read_ether_addr(sd_rtnl_message
*m
, unsigned short type
, struct ether_addr
*data
) {
888 assert_return(data
, -EINVAL
);
890 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
894 memcpy(data
, attr_data
, sizeof(struct ether_addr
));
899 int sd_rtnl_message_read_in_addr(sd_rtnl_message
*m
, unsigned short type
, struct in_addr
*data
) {
903 assert_return(data
, -EINVAL
);
905 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
909 memcpy(data
, attr_data
, sizeof(struct in_addr
));
914 int sd_rtnl_message_read_in6_addr(sd_rtnl_message
*m
, unsigned short type
, struct in6_addr
*data
) {
918 assert_return(data
, -EINVAL
);
920 r
= rtnl_message_read_internal(m
, type
, &attr_data
);
924 memcpy(data
, attr_data
, sizeof(struct in6_addr
));
929 int sd_rtnl_message_exit_container(sd_rtnl_message
*m
) {
930 assert_return(m
, -EINVAL
);
931 assert_return(m
->sealed
, -EINVAL
);
932 assert_return(m
->n_containers
> 0, -EINVAL
);
939 uint32_t rtnl_message_get_serial(sd_rtnl_message
*m
) {
943 return m
->hdr
->nlmsg_seq
;
946 int sd_rtnl_message_get_errno(sd_rtnl_message
*m
) {
947 struct nlmsgerr
*err
;
949 assert_return(m
, -EINVAL
);
950 assert_return(m
->hdr
, -EINVAL
);
952 if (m
->hdr
->nlmsg_type
!= NLMSG_ERROR
)
955 err
= NLMSG_DATA(m
->hdr
);
960 int rtnl_message_seal(sd_rtnl
*nl
, sd_rtnl_message
*m
) {
970 m
->hdr
->nlmsg_seq
= nl
->serial
++;
974 r
= sd_rtnl_message_rewind(m
);
981 static int message_receive_need(sd_rtnl
*rtnl
, size_t *need
) {
985 /* ioctl(rtnl->fd, FIONREAD, &need)
986 Does not appear to work on netlink sockets. libnl uses
987 MSG_PEEK instead. I don't know if that is worth the
990 For now we simply use the maximum message size the kernel
991 may use (NLMSG_GOODSIZE), and then realloc to the actual
992 size after reading the message (hence avoiding huge memory
993 usage in case many small messages are kept around) */
1001 int rtnl_message_parse(sd_rtnl_message
*m
,
1002 size_t **rta_offset_tb
,
1003 unsigned short *rta_tb_size
,
1006 unsigned int rt_len
) {
1010 tb
= (size_t *) new0(size_t *, max
);
1016 for (; RTA_OK(rta
, rt_len
); rta
= RTA_NEXT(rta
, rt_len
)) {
1017 type
= rta
->rta_type
;
1020 tb
[type
] = (uint8_t *) rta
- (uint8_t *) m
->hdr
;
1023 *rta_offset_tb
= tb
;
1028 /* returns the number of bytes sent, or a negative error code */
1029 int socket_write_message(sd_rtnl
*nl
, sd_rtnl_message
*m
) {
1032 struct sockaddr_nl nl
;
1034 .nl
.nl_family
= AF_NETLINK
,
1042 k
= sendto(nl
->fd
, m
->hdr
, m
->hdr
->nlmsg_len
,
1043 0, &addr
.sa
, sizeof(addr
));
1045 return (errno
== EAGAIN
) ? 0 : -errno
;
1050 /* On success, the number of bytes received is returned and *ret points to the received message
1051 * which has a valid header and the correct size.
1052 * If nothing useful was received 0 is returned.
1053 * On failure, a negative error code is returned.
1055 int socket_read_message(sd_rtnl
*nl
, sd_rtnl_message
**ret
) {
1059 struct sockaddr_nl nl
;
1069 r
= message_receive_need(nl
, &need
);
1073 r
= message_new(nl
, &m
, need
);
1077 /* don't allow sealing/appending to received messages */
1080 addr_len
= sizeof(addr
);
1082 k
= recvfrom(nl
->fd
, m
->hdr
, need
,
1083 0, &addr
.sa
, &addr_len
);
1085 k
= (errno
== EAGAIN
) ? 0 : -errno
; /* no data */
1087 k
= -ECONNRESET
; /* connection was closed by the kernel */
1088 else if (addr_len
!= sizeof(addr
.nl
) ||
1089 addr
.nl
.nl_family
!= AF_NETLINK
)
1090 k
= -EIO
; /* not a netlink message */
1091 else if (addr
.nl
.nl_pid
!= 0)
1092 k
= 0; /* not from the kernel */
1093 else if ((size_t) k
< sizeof(struct nlmsghdr
) ||
1094 (size_t) k
< m
->hdr
->nlmsg_len
)
1095 k
= -EIO
; /* too small (we do accept too big though) */
1096 else if (m
->hdr
->nlmsg_pid
&& m
->hdr
->nlmsg_pid
!= nl
->sockaddr
.nl
.nl_pid
)
1097 k
= 0; /* not broadcast and not for us */
1100 switch (m
->hdr
->nlmsg_type
) {
1101 /* check that the size matches the message type */
1103 if (m
->hdr
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
1110 if (m
->hdr
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct ifinfomsg
)))
1113 struct ifinfomsg
*ifi
;
1115 ifi
= NLMSG_DATA(m
->hdr
);
1116 UPDATE_RTA(m
, IFLA_RTA(ifi
));
1118 r
= rtnl_message_parse(m
,
1123 IFLA_PAYLOAD(m
->hdr
));
1130 if (m
->hdr
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct ifaddrmsg
)))
1133 struct ifaddrmsg
*ifa
;
1135 ifa
= NLMSG_DATA(m
->hdr
);
1136 UPDATE_RTA(m
, IFA_RTA(ifa
));
1138 r
= rtnl_message_parse(m
,
1143 IFA_PAYLOAD(m
->hdr
));
1149 if (m
->hdr
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct rtmsg
)))
1154 rtm
= NLMSG_DATA(m
->hdr
);
1155 UPDATE_RTA(m
, RTM_RTA(rtm
));
1157 r
= rtnl_message_parse(m
,
1162 RTM_PAYLOAD(m
->hdr
));
1169 k
= 0; /* ignoring message of unknown type */
1173 sd_rtnl_message_unref(m
);
1175 /* we probably allocated way too much memory, give it back */
1176 m
->hdr
= realloc(m
->hdr
, m
->hdr
->nlmsg_len
);
1183 int sd_rtnl_message_rewind(sd_rtnl_message
*m
) {
1184 struct ifinfomsg
*ifi
;
1185 struct ifaddrmsg
*ifa
;
1188 assert_return(m
, -EINVAL
);
1189 assert_return(m
->sealed
, -EPERM
);
1190 assert_return(m
->hdr
, -EINVAL
);
1192 switch(m
->hdr
->nlmsg_type
) {
1197 ifi
= NLMSG_DATA(m
->hdr
);
1198 UPDATE_RTA(m
, IFLA_RTA(ifi
));
1204 ifa
= NLMSG_DATA(m
->hdr
);
1205 UPDATE_RTA(m
, IFA_RTA(ifa
));
1211 rtm
= NLMSG_DATA(m
->hdr
);
1212 UPDATE_RTA(m
, RTM_RTA(rtm
));
1219 m
->n_containers
= 0;