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>
26 #include "sd-netlink.h"
28 #include "alloc-util.h"
29 #include "formats-util.h"
31 #include "netlink-internal.h"
32 #include "netlink-types.h"
33 #include "netlink-util.h"
35 #include "socket-util.h"
38 int socket_open(int family
) {
41 fd
= socket(PF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, family
);
48 static int broadcast_groups_get(sd_netlink
*nl
) {
49 _cleanup_free_
uint32_t *groups
= NULL
;
50 socklen_t len
= 0, old_len
;
57 r
= getsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_LIST_MEMBERSHIPS
, NULL
, &len
);
59 if (errno
== ENOPROTOOPT
) {
60 nl
->broadcast_group_dont_leave
= true;
69 groups
= new0(uint32_t, len
);
75 r
= getsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_LIST_MEMBERSHIPS
, groups
, &len
);
82 r
= hashmap_ensure_allocated(&nl
->broadcast_group_refs
, NULL
);
86 for (i
= 0; i
< len
; i
++) {
87 for (j
= 0; j
< sizeof(uint32_t) * 8; j
++) {
93 if (!(groups
[i
] & offset
))
96 group
= i
* sizeof(uint32_t) * 8 + j
+ 1;
98 r
= hashmap_put(nl
->broadcast_group_refs
, UINT_TO_PTR(group
), UINT_TO_PTR(1));
107 int socket_bind(sd_netlink
*nl
) {
111 r
= setsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_PKTINFO
, &one
, sizeof(one
));
115 addrlen
= sizeof(nl
->sockaddr
);
117 r
= bind(nl
->fd
, &nl
->sockaddr
.sa
, addrlen
);
118 /* ignore EINVAL to allow opening an already bound socket */
119 if (r
< 0 && errno
!= EINVAL
)
122 r
= getsockname(nl
->fd
, &nl
->sockaddr
.sa
, &addrlen
);
126 r
= broadcast_groups_get(nl
);
133 static unsigned broadcast_group_get_ref(sd_netlink
*nl
, unsigned group
) {
136 return PTR_TO_UINT(hashmap_get(nl
->broadcast_group_refs
, UINT_TO_PTR(group
)));
139 static int broadcast_group_set_ref(sd_netlink
*nl
, unsigned group
, unsigned n_ref
) {
144 r
= hashmap_replace(nl
->broadcast_group_refs
, UINT_TO_PTR(group
), UINT_TO_PTR(n_ref
));
151 static int broadcast_group_join(sd_netlink
*nl
, unsigned group
) {
158 r
= setsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
, &group
, sizeof(group
));
165 int socket_broadcast_group_ref(sd_netlink
*nl
, unsigned group
) {
171 n_ref
= broadcast_group_get_ref(nl
, group
);
175 r
= hashmap_ensure_allocated(&nl
->broadcast_group_refs
, NULL
);
179 r
= broadcast_group_set_ref(nl
, group
, n_ref
);
184 /* not yet in the group */
187 r
= broadcast_group_join(nl
, group
);
194 static int broadcast_group_leave(sd_netlink
*nl
, unsigned group
) {
201 if (nl
->broadcast_group_dont_leave
)
204 r
= setsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_DROP_MEMBERSHIP
, &group
, sizeof(group
));
211 int socket_broadcast_group_unref(sd_netlink
*nl
, unsigned group
) {
217 n_ref
= broadcast_group_get_ref(nl
, group
);
223 r
= broadcast_group_set_ref(nl
, group
, n_ref
);
228 /* still refs left */
231 r
= broadcast_group_leave(nl
, group
);
238 /* returns the number of bytes sent, or a negative error code */
239 int socket_write_message(sd_netlink
*nl
, sd_netlink_message
*m
) {
242 struct sockaddr_nl nl
;
244 .nl
.nl_family
= AF_NETLINK
,
252 k
= sendto(nl
->fd
, m
->hdr
, m
->hdr
->nlmsg_len
,
253 0, &addr
.sa
, sizeof(addr
));
260 static int socket_recv_message(int fd
, struct iovec
*iov
, uint32_t *_group
, bool peek
) {
261 union sockaddr_union sender
;
262 uint8_t cmsg_buffer
[CMSG_SPACE(sizeof(struct nl_pktinfo
))];
263 struct msghdr msg
= {
267 .msg_namelen
= sizeof(sender
),
268 .msg_control
= cmsg_buffer
,
269 .msg_controllen
= sizeof(cmsg_buffer
),
271 struct cmsghdr
*cmsg
;
278 r
= recvmsg(fd
, &msg
, MSG_TRUNC
| (peek
? MSG_PEEK
: 0));
281 if (errno
== ENOBUFS
)
282 log_debug("rtnl: kernel receive buffer overrun");
283 else if (errno
== EAGAIN
)
284 log_debug("rtnl: no data in socket");
286 return (errno
== EAGAIN
|| errno
== EINTR
) ? 0 : -errno
;
289 if (sender
.nl
.nl_pid
!= 0) {
290 /* not from the kernel, ignore */
291 log_debug("rtnl: ignoring message from portid %"PRIu32
, sender
.nl
.nl_pid
);
294 /* drop the message */
295 r
= recvmsg(fd
, &msg
, 0);
297 return (errno
== EAGAIN
|| errno
== EINTR
) ? 0 : -errno
;
303 CMSG_FOREACH(cmsg
, &msg
) {
304 if (cmsg
->cmsg_level
== SOL_NETLINK
&&
305 cmsg
->cmsg_type
== NETLINK_PKTINFO
&&
306 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct nl_pktinfo
))) {
307 struct nl_pktinfo
*pktinfo
= (void *)CMSG_DATA(cmsg
);
309 /* multi-cast group */
310 group
= pktinfo
->group
;
320 /* On success, the number of bytes received is returned and *ret points to the received message
321 * which has a valid header and the correct size.
322 * If nothing useful was received 0 is returned.
323 * On failure, a negative error code is returned.
325 int socket_read_message(sd_netlink
*rtnl
) {
326 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*first
= NULL
;
327 struct iovec iov
= {};
329 bool multi_part
= false, done
= false;
330 struct nlmsghdr
*new_msg
;
336 assert(rtnl
->rbuffer
);
337 assert(rtnl
->rbuffer_allocated
>= sizeof(struct nlmsghdr
));
339 /* read nothing, just get the pending message size */
340 r
= socket_recv_message(rtnl
->fd
, &iov
, NULL
, true);
346 /* make room for the pending message */
347 if (!greedy_realloc((void **)&rtnl
->rbuffer
,
348 &rtnl
->rbuffer_allocated
,
349 len
, sizeof(uint8_t)))
352 iov
.iov_base
= rtnl
->rbuffer
;
353 iov
.iov_len
= rtnl
->rbuffer_allocated
;
355 /* read the pending message */
356 r
= socket_recv_message(rtnl
->fd
, &iov
, &group
, false);
362 if (len
> rtnl
->rbuffer_allocated
)
363 /* message did not fit in read buffer */
366 if (NLMSG_OK(rtnl
->rbuffer
, len
) && rtnl
->rbuffer
->nlmsg_flags
& NLM_F_MULTI
) {
369 for (i
= 0; i
< rtnl
->rqueue_partial_size
; i
++) {
370 if (rtnl_message_get_serial(rtnl
->rqueue_partial
[i
]) ==
371 rtnl
->rbuffer
->nlmsg_seq
) {
372 first
= rtnl
->rqueue_partial
[i
];
378 for (new_msg
= rtnl
->rbuffer
; NLMSG_OK(new_msg
, len
) && !done
; new_msg
= NLMSG_NEXT(new_msg
, len
)) {
379 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
380 const NLType
*nl_type
;
382 if (!group
&& new_msg
->nlmsg_pid
!= rtnl
->sockaddr
.nl
.nl_pid
)
383 /* not broadcast and not for us */
386 if (new_msg
->nlmsg_type
== NLMSG_NOOP
)
387 /* silently drop noop messages */
390 if (new_msg
->nlmsg_type
== NLMSG_DONE
) {
391 /* finished reading multi-part message */
394 /* if first is not defined, put NLMSG_DONE into the receive queue. */
399 /* check that we support this message type */
400 r
= type_system_get_type(&type_system_root
, &nl_type
, new_msg
->nlmsg_type
);
402 if (r
== -EOPNOTSUPP
)
403 log_debug("sd-netlink: ignored message with unknown type: %i",
404 new_msg
->nlmsg_type
);
409 /* check that the size matches the message type */
410 if (new_msg
->nlmsg_len
< NLMSG_LENGTH(type_get_size(nl_type
))) {
411 log_debug("sd-netlink: message larger than expected, dropping");
415 r
= message_new_empty(rtnl
, &m
);
419 m
->broadcast
= !!group
;
421 m
->hdr
= memdup(new_msg
, new_msg
->nlmsg_len
);
425 /* seal and parse the top-level message */
426 r
= sd_netlink_message_rewind(m
);
430 /* push the message onto the multi-part message stack */
438 log_debug("sd-netlink: discarding %zu bytes of incoming message", len
);
443 if (!multi_part
|| done
) {
444 /* we got a complete message, push it on the read queue */
445 r
= rtnl_rqueue_make_room(rtnl
);
449 rtnl
->rqueue
[rtnl
->rqueue_size
++] = first
;
452 if (multi_part
&& (i
< rtnl
->rqueue_partial_size
)) {
453 /* remove the message form the partial read queue */
454 memmove(rtnl
->rqueue_partial
+ i
,rtnl
->rqueue_partial
+ i
+ 1,
455 sizeof(sd_netlink_message
*) * (rtnl
->rqueue_partial_size
- i
- 1));
456 rtnl
->rqueue_partial_size
--;
461 /* we only got a partial multi-part message, push it on the
462 partial read queue */
463 if (i
< rtnl
->rqueue_partial_size
) {
464 rtnl
->rqueue_partial
[i
] = first
;
466 r
= rtnl_rqueue_partial_make_room(rtnl
);
470 rtnl
->rqueue_partial
[rtnl
->rqueue_partial_size
++] = first
;