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>
27 #include "socket-util.h"
28 #include "formats-util.h"
32 #include "sd-netlink.h"
33 #include "netlink-util.h"
34 #include "netlink-internal.h"
35 #include "netlink-types.h"
37 int socket_open(int family
) {
40 fd
= socket(PF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, family
);
47 static int broadcast_groups_get(sd_netlink
*nl
) {
48 _cleanup_free_
uint32_t *groups
= NULL
;
49 socklen_t len
= 0, old_len
;
56 r
= getsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_LIST_MEMBERSHIPS
, NULL
, &len
);
58 if (errno
== ENOPROTOOPT
) {
59 nl
->broadcast_group_dont_leave
= true;
68 groups
= new0(uint32_t, len
);
74 r
= getsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_LIST_MEMBERSHIPS
, groups
, &len
);
81 r
= hashmap_ensure_allocated(&nl
->broadcast_group_refs
, NULL
);
85 for (i
= 0; i
< len
; i
++) {
86 for (j
= 0; j
< sizeof(uint32_t) * 8; j
++) {
92 if (!(groups
[i
] & offset
))
95 group
= i
* sizeof(uint32_t) * 8 + j
+ 1;
97 r
= hashmap_put(nl
->broadcast_group_refs
, UINT_TO_PTR(group
), UINT_TO_PTR(1));
106 int socket_bind(sd_netlink
*nl
) {
110 r
= setsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_PKTINFO
, &one
, sizeof(one
));
114 addrlen
= sizeof(nl
->sockaddr
);
116 r
= bind(nl
->fd
, &nl
->sockaddr
.sa
, addrlen
);
117 /* ignore EINVAL to allow opening an already bound socket */
118 if (r
< 0 && errno
!= EINVAL
)
121 r
= getsockname(nl
->fd
, &nl
->sockaddr
.sa
, &addrlen
);
125 r
= broadcast_groups_get(nl
);
132 static unsigned broadcast_group_get_ref(sd_netlink
*nl
, unsigned group
) {
135 return PTR_TO_UINT(hashmap_get(nl
->broadcast_group_refs
, UINT_TO_PTR(group
)));
138 static int broadcast_group_set_ref(sd_netlink
*nl
, unsigned group
, unsigned n_ref
) {
143 r
= hashmap_replace(nl
->broadcast_group_refs
, UINT_TO_PTR(group
), UINT_TO_PTR(n_ref
));
150 static int broadcast_group_join(sd_netlink
*nl
, unsigned group
) {
157 r
= setsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
, &group
, sizeof(group
));
164 int socket_broadcast_group_ref(sd_netlink
*nl
, unsigned group
) {
170 n_ref
= broadcast_group_get_ref(nl
, group
);
174 r
= hashmap_ensure_allocated(&nl
->broadcast_group_refs
, NULL
);
178 r
= broadcast_group_set_ref(nl
, group
, n_ref
);
183 /* not yet in the group */
186 r
= broadcast_group_join(nl
, group
);
193 static int broadcast_group_leave(sd_netlink
*nl
, unsigned group
) {
200 if (nl
->broadcast_group_dont_leave
)
203 r
= setsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_DROP_MEMBERSHIP
, &group
, sizeof(group
));
210 int socket_broadcast_group_unref(sd_netlink
*nl
, unsigned group
) {
216 n_ref
= broadcast_group_get_ref(nl
, group
);
222 r
= broadcast_group_set_ref(nl
, group
, n_ref
);
227 /* still refs left */
230 r
= broadcast_group_leave(nl
, group
);
237 /* returns the number of bytes sent, or a negative error code */
238 int socket_write_message(sd_netlink
*nl
, sd_netlink_message
*m
) {
241 struct sockaddr_nl nl
;
243 .nl
.nl_family
= AF_NETLINK
,
251 k
= sendto(nl
->fd
, m
->hdr
, m
->hdr
->nlmsg_len
,
252 0, &addr
.sa
, sizeof(addr
));
259 static int socket_recv_message(int fd
, struct iovec
*iov
, uint32_t *_group
, bool peek
) {
260 union sockaddr_union sender
;
261 uint8_t cmsg_buffer
[CMSG_SPACE(sizeof(struct nl_pktinfo
))];
262 struct msghdr msg
= {
266 .msg_namelen
= sizeof(sender
),
267 .msg_control
= cmsg_buffer
,
268 .msg_controllen
= sizeof(cmsg_buffer
),
270 struct cmsghdr
*cmsg
;
277 r
= recvmsg(fd
, &msg
, MSG_TRUNC
| (peek
? MSG_PEEK
: 0));
280 if (errno
== ENOBUFS
)
281 log_debug("rtnl: kernel receive buffer overrun");
282 else if (errno
== EAGAIN
)
283 log_debug("rtnl: no data in socket");
285 return (errno
== EAGAIN
|| errno
== EINTR
) ? 0 : -errno
;
288 if (sender
.nl
.nl_pid
!= 0) {
289 /* not from the kernel, ignore */
290 log_debug("rtnl: ignoring message from portid %"PRIu32
, sender
.nl
.nl_pid
);
293 /* drop the message */
294 r
= recvmsg(fd
, &msg
, 0);
296 return (errno
== EAGAIN
|| errno
== EINTR
) ? 0 : -errno
;
302 CMSG_FOREACH(cmsg
, &msg
) {
303 if (cmsg
->cmsg_level
== SOL_NETLINK
&&
304 cmsg
->cmsg_type
== NETLINK_PKTINFO
&&
305 cmsg
->cmsg_len
== CMSG_LEN(sizeof(struct nl_pktinfo
))) {
306 struct nl_pktinfo
*pktinfo
= (void *)CMSG_DATA(cmsg
);
308 /* multi-cast group */
309 group
= pktinfo
->group
;
319 /* On success, the number of bytes received is returned and *ret points to the received message
320 * which has a valid header and the correct size.
321 * If nothing useful was received 0 is returned.
322 * On failure, a negative error code is returned.
324 int socket_read_message(sd_netlink
*rtnl
) {
325 _cleanup_netlink_message_unref_ sd_netlink_message
*first
= NULL
;
326 struct iovec iov
= {};
328 bool multi_part
= false, done
= false;
329 struct nlmsghdr
*new_msg
;
335 assert(rtnl
->rbuffer
);
336 assert(rtnl
->rbuffer_allocated
>= sizeof(struct nlmsghdr
));
338 /* read nothing, just get the pending message size */
339 r
= socket_recv_message(rtnl
->fd
, &iov
, NULL
, true);
345 /* make room for the pending message */
346 if (!greedy_realloc((void **)&rtnl
->rbuffer
,
347 &rtnl
->rbuffer_allocated
,
348 len
, sizeof(uint8_t)))
351 iov
.iov_base
= rtnl
->rbuffer
;
352 iov
.iov_len
= rtnl
->rbuffer_allocated
;
354 /* read the pending message */
355 r
= socket_recv_message(rtnl
->fd
, &iov
, &group
, false);
361 if (len
> rtnl
->rbuffer_allocated
)
362 /* message did not fit in read buffer */
365 if (NLMSG_OK(rtnl
->rbuffer
, len
) && rtnl
->rbuffer
->nlmsg_flags
& NLM_F_MULTI
) {
368 for (i
= 0; i
< rtnl
->rqueue_partial_size
; i
++) {
369 if (rtnl_message_get_serial(rtnl
->rqueue_partial
[i
]) ==
370 rtnl
->rbuffer
->nlmsg_seq
) {
371 first
= rtnl
->rqueue_partial
[i
];
377 for (new_msg
= rtnl
->rbuffer
; NLMSG_OK(new_msg
, len
) && !done
; new_msg
= NLMSG_NEXT(new_msg
, len
)) {
378 _cleanup_netlink_message_unref_ sd_netlink_message
*m
= NULL
;
379 const NLType
*nl_type
;
381 if (!group
&& new_msg
->nlmsg_pid
!= rtnl
->sockaddr
.nl
.nl_pid
)
382 /* not broadcast and not for us */
385 if (new_msg
->nlmsg_type
== NLMSG_NOOP
)
386 /* silently drop noop messages */
389 if (new_msg
->nlmsg_type
== NLMSG_DONE
) {
390 /* finished reading multi-part message */
393 /* if first is not defined, put NLMSG_DONE into the receive queue. */
398 /* check that we support this message type */
399 r
= type_system_get_type(&type_system_root
, &nl_type
, new_msg
->nlmsg_type
);
401 if (r
== -EOPNOTSUPP
)
402 log_debug("sd-netlink: ignored message with unknown type: %i",
403 new_msg
->nlmsg_type
);
408 /* check that the size matches the message type */
409 if (new_msg
->nlmsg_len
< NLMSG_LENGTH(type_get_size(nl_type
))) {
410 log_debug("sd-netlink: message larger than expected, dropping");
414 r
= message_new_empty(rtnl
, &m
);
418 m
->broadcast
= !!group
;
420 m
->hdr
= memdup(new_msg
, new_msg
->nlmsg_len
);
424 /* seal and parse the top-level message */
425 r
= sd_netlink_message_rewind(m
);
429 /* push the message onto the multi-part message stack */
437 log_debug("sd-netlink: discarding %zu bytes of incoming message", len
);
442 if (!multi_part
|| done
) {
443 /* we got a complete message, push it on the read queue */
444 r
= rtnl_rqueue_make_room(rtnl
);
448 rtnl
->rqueue
[rtnl
->rqueue_size
++] = first
;
451 if (multi_part
&& (i
< rtnl
->rqueue_partial_size
)) {
452 /* remove the message form the partial read queue */
453 memmove(rtnl
->rqueue_partial
+ i
,rtnl
->rqueue_partial
+ i
+ 1,
454 sizeof(sd_netlink_message
*) * (rtnl
->rqueue_partial_size
- i
- 1));
455 rtnl
->rqueue_partial_size
--;
460 /* we only got a partial multi-part message, push it on the
461 partial read queue */
462 if (i
< rtnl
->rqueue_partial_size
) {
463 rtnl
->rqueue_partial
[i
] = first
;
465 r
= rtnl_rqueue_partial_make_room(rtnl
);
469 rtnl
->rqueue_partial
[rtnl
->rqueue_partial_size
++] = first
;