1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <netinet/in.h>
8 #include "sd-netlink.h"
10 #include "alloc-util.h"
12 #include "format-util.h"
14 #include "netlink-internal.h"
15 #include "netlink-types.h"
16 #include "socket-util.h"
18 static int broadcast_groups_get(sd_netlink
*nl
) {
19 _cleanup_free_
uint32_t *groups
= NULL
;
20 socklen_t len
= 0, old_len
;
26 if (getsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_LIST_MEMBERSHIPS
, NULL
, &len
) < 0) {
27 if (errno
!= ENOPROTOOPT
)
30 nl
->broadcast_group_dont_leave
= true;
37 groups
= new0(uint32_t, len
);
43 if (getsockopt(nl
->fd
, SOL_NETLINK
, NETLINK_LIST_MEMBERSHIPS
, groups
, &len
) < 0)
49 for (unsigned i
= 0; i
< len
; i
++)
50 for (unsigned j
= 0; j
< sizeof(uint32_t) * 8; j
++)
51 if (groups
[i
] & (1U << j
)) {
52 unsigned group
= i
* sizeof(uint32_t) * 8 + j
+ 1;
54 r
= hashmap_ensure_put(&nl
->broadcast_group_refs
, NULL
, UINT_TO_PTR(group
), UINT_TO_PTR(1));
62 int socket_bind(sd_netlink
*nl
) {
66 r
= setsockopt_int(nl
->fd
, SOL_NETLINK
, NETLINK_PKTINFO
, true);
70 addrlen
= sizeof(nl
->sockaddr
);
72 /* ignore EINVAL to allow binding an already bound socket */
73 if (bind(nl
->fd
, &nl
->sockaddr
.sa
, addrlen
) < 0 && errno
!= EINVAL
)
76 if (getsockname(nl
->fd
, &nl
->sockaddr
.sa
, &addrlen
) < 0)
79 return broadcast_groups_get(nl
);
82 static unsigned broadcast_group_get_ref(sd_netlink
*nl
, unsigned group
) {
85 return PTR_TO_UINT(hashmap_get(nl
->broadcast_group_refs
, UINT_TO_PTR(group
)));
88 static int broadcast_group_set_ref(sd_netlink
*nl
, unsigned group
, unsigned n_ref
) {
93 r
= hashmap_ensure_allocated(&nl
->broadcast_group_refs
, NULL
);
97 return hashmap_replace(nl
->broadcast_group_refs
, UINT_TO_PTR(group
), UINT_TO_PTR(n_ref
));
100 static int broadcast_group_join(sd_netlink
*nl
, unsigned group
) {
105 /* group is "unsigned", but netlink(7) says the argument for NETLINK_ADD_MEMBERSHIP is "int" */
106 return setsockopt_int(nl
->fd
, SOL_NETLINK
, NETLINK_ADD_MEMBERSHIP
, group
);
109 int socket_broadcast_group_ref(sd_netlink
*nl
, unsigned group
) {
115 n_ref
= broadcast_group_get_ref(nl
, group
);
119 r
= broadcast_group_set_ref(nl
, group
, n_ref
);
124 /* already in the group */
127 return broadcast_group_join(nl
, group
);
130 static int broadcast_group_leave(sd_netlink
*nl
, unsigned group
) {
135 if (nl
->broadcast_group_dont_leave
)
138 /* group is "unsigned", but netlink(7) says the argument for NETLINK_DROP_MEMBERSHIP is "int" */
139 return setsockopt_int(nl
->fd
, SOL_NETLINK
, NETLINK_DROP_MEMBERSHIP
, group
);
142 int socket_broadcast_group_unref(sd_netlink
*nl
, unsigned group
) {
148 n_ref
= broadcast_group_get_ref(nl
, group
);
154 r
= broadcast_group_set_ref(nl
, group
, n_ref
);
159 /* still refs left */
162 return broadcast_group_leave(nl
, group
);
165 /* returns the number of bytes sent, or a negative error code */
166 int socket_write_message(sd_netlink
*nl
, sd_netlink_message
*m
) {
167 union sockaddr_union addr
= {
168 .nl
.nl_family
= AF_NETLINK
,
176 k
= sendto(nl
->fd
, m
->hdr
, m
->hdr
->nlmsg_len
, 0, &addr
.sa
, sizeof(addr
));
183 static int socket_recv_message(int fd
, struct iovec
*iov
, uint32_t *ret_mcast_group
, bool peek
) {
184 union sockaddr_union sender
;
185 CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo
))) control
;
186 struct msghdr msg
= {
190 .msg_namelen
= sizeof(sender
),
191 .msg_control
= &control
,
192 .msg_controllen
= sizeof(control
),
199 n
= recvmsg_safe(fd
, &msg
, MSG_TRUNC
| (peek
? MSG_PEEK
: 0));
202 return log_debug_errno(n
, "sd-netlink: kernel receive buffer overrun");
203 if (ERRNO_IS_TRANSIENT(n
))
208 if (sender
.nl
.nl_pid
!= 0) {
209 /* not from the kernel, ignore */
210 log_debug("sd-netlink: ignoring message from PID %"PRIu32
, sender
.nl
.nl_pid
);
213 /* drop the message */
214 n
= recvmsg_safe(fd
, &msg
, 0);
222 if (ret_mcast_group
) {
223 struct nl_pktinfo
*pi
;
225 pi
= CMSG_FIND_DATA(&msg
, SOL_NETLINK
, NETLINK_PKTINFO
, struct nl_pktinfo
);
227 *ret_mcast_group
= pi
->group
;
229 *ret_mcast_group
= 0;
235 /* On success, the number of bytes received is returned and *ret points to the received message
236 * which has a valid header and the correct size.
237 * If nothing useful was received 0 is returned.
238 * On failure, a negative error code is returned.
240 int socket_read_message(sd_netlink
*nl
) {
241 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*first
= NULL
;
242 bool multi_part
= false, done
= false;
243 size_t len
, allocated
;
244 struct iovec iov
= {};
252 /* read nothing, just get the pending message size */
253 r
= socket_recv_message(nl
->fd
, &iov
, NULL
, true);
259 /* make room for the pending message */
260 if (!greedy_realloc((void**) &nl
->rbuffer
, len
, sizeof(uint8_t)))
263 allocated
= MALLOC_SIZEOF_SAFE(nl
->rbuffer
);
264 iov
= IOVEC_MAKE(nl
->rbuffer
, allocated
);
266 /* read the pending message */
267 r
= socket_recv_message(nl
->fd
, &iov
, &group
, false);
274 /* message did not fit in read buffer */
277 if (NLMSG_OK(nl
->rbuffer
, len
) && nl
->rbuffer
->nlmsg_flags
& NLM_F_MULTI
) {
280 for (i
= 0; i
< nl
->rqueue_partial_size
; i
++)
281 if (message_get_serial(nl
->rqueue_partial
[i
]) ==
282 nl
->rbuffer
->nlmsg_seq
) {
283 first
= nl
->rqueue_partial
[i
];
288 for (struct nlmsghdr
*new_msg
= nl
->rbuffer
; NLMSG_OK(new_msg
, len
) && !done
; new_msg
= NLMSG_NEXT(new_msg
, len
)) {
289 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
292 if (group
== 0 && new_msg
->nlmsg_pid
!= nl
->sockaddr
.nl
.nl_pid
)
293 /* not broadcast and not for us */
296 if (new_msg
->nlmsg_type
== NLMSG_NOOP
)
297 /* silently drop noop messages */
300 if (new_msg
->nlmsg_type
== NLMSG_DONE
) {
301 /* finished reading multi-part message */
304 /* if first is not defined, put NLMSG_DONE into the receive queue. */
309 /* check that we support this message type */
310 r
= netlink_get_policy_set_and_header_size(nl
, new_msg
->nlmsg_type
, NULL
, &size
);
312 if (r
== -EOPNOTSUPP
)
313 log_debug("sd-netlink: ignored message with unknown type: %i",
314 new_msg
->nlmsg_type
);
319 /* check that the size matches the message type */
320 if (new_msg
->nlmsg_len
< NLMSG_LENGTH(size
)) {
321 log_debug("sd-netlink: message is shorter than expected, dropping");
325 r
= message_new_empty(nl
, &m
);
329 m
->multicast_group
= group
;
330 m
->hdr
= memdup(new_msg
, new_msg
->nlmsg_len
);
334 /* seal and parse the top-level message */
335 r
= sd_netlink_message_rewind(m
, nl
);
339 /* push the message onto the multi-part message stack */
346 log_debug("sd-netlink: discarding %zu bytes of incoming message", len
);
351 if (!multi_part
|| done
) {
352 /* we got a complete message, push it on the read queue */
353 r
= netlink_rqueue_make_room(nl
);
357 nl
->rqueue
[nl
->rqueue_size
++] = TAKE_PTR(first
);
359 if (multi_part
&& (i
< nl
->rqueue_partial_size
)) {
360 /* remove the message form the partial read queue */
361 memmove(nl
->rqueue_partial
+ i
, nl
->rqueue_partial
+ i
+ 1,
362 sizeof(sd_netlink_message
*) * (nl
->rqueue_partial_size
- i
- 1));
363 nl
->rqueue_partial_size
--;
368 /* we only got a partial multi-part message, push it on the
369 partial read queue */
370 if (i
< nl
->rqueue_partial_size
)
371 nl
->rqueue_partial
[i
] = TAKE_PTR(first
);
373 r
= netlink_rqueue_partial_make_room(nl
);
377 nl
->rqueue_partial
[nl
->rqueue_partial_size
++] = TAKE_PTR(first
);