89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen/***
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen This file is part of systemd.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen Copyright 2013 Tom Gundersen <teg@jklm.no>
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen systemd is free software; you can redistribute it and/or modify it
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen under the terms of the GNU Lesser General Public License as published by
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen (at your option) any later version.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen systemd is distributed in the hope that it will be useful, but
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen Lesser General Public License for more details.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen You should have received a copy of the GNU Lesser General Public License
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen***/
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include <netinet/in.h>
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include <stdbool.h>
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include <unistd.h>
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "sd-netlink.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include "alloc-util.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "formats-util.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "missing.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "netlink-internal.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "netlink-types.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "netlink-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "refcnt.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "socket-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "util.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersenint socket_open(int family) {
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen int fd;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, family);
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen if (fd < 0)
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return -errno;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return fd;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen}
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersenstatic int broadcast_groups_get(sd_netlink *nl) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen _cleanup_free_ uint32_t *groups = NULL;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen socklen_t len = 0, old_len;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen unsigned i, j;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen int r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(nl);
f78bc916a6ccafecec2c2526bbd65a3d61f7b413Daniel Mack assert(nl->fd >= 0);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (errno == ENOPROTOOPT) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen nl->broadcast_group_dont_leave = true;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen } else
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return -errno;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen }
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (len == 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen groups = new0(uint32_t, len);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (!groups)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return -ENOMEM;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen old_len = len;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return -errno;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (old_len != len)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return -EIO;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen for (i = 0; i < len; i++) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen for (j = 0; j < sizeof(uint32_t) * 8; j ++) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen uint32_t offset;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen unsigned group;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen offset = 1U << j;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (!(groups[i] & offset))
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen continue;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen group = i * sizeof(uint32_t) * 8 + j + 1;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1));
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen }
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen }
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen}
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersenint socket_bind(sd_netlink *nl) {
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen socklen_t addrlen;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen int r, one = 1;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen if (r < 0)
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return -errno;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen addrlen = sizeof(nl->sockaddr);
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen r = bind(nl->fd, &nl->sockaddr.sa, addrlen);
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen /* ignore EINVAL to allow opening an already bound socket */
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen if (r < 0 && errno != EINVAL)
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return -errno;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen r = getsockname(nl->fd, &nl->sockaddr.sa, &addrlen);
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen if (r < 0)
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return -errno;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = broadcast_groups_get(nl);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return 0;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen}
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersenstatic unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(nl);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return PTR_TO_UINT(hashmap_get(nl->broadcast_group_refs, UINT_TO_PTR(group)));
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen}
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersenstatic int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen int r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(nl);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref));
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen}
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersenstatic int broadcast_group_join(sd_netlink *nl, unsigned group) {
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen int r;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen assert(nl);
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen assert(nl->fd >= 0);
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen assert(group > 0);
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen if (r < 0)
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return -errno;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return 0;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen}
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersenint socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen unsigned n_ref;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen int r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(nl);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen n_ref = broadcast_group_get_ref(nl, group);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen n_ref ++;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = broadcast_group_set_ref(nl, group, n_ref);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (n_ref > 1)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen /* not yet in the group */
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = broadcast_group_join(nl, group);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen}
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersenstatic int broadcast_group_leave(sd_netlink *nl, unsigned group) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen int r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(nl);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(nl->fd >= 0);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(group > 0);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (nl->broadcast_group_dont_leave)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group));
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return -errno;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen}
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersenint socket_broadcast_group_unref(sd_netlink *nl, unsigned group) {
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen unsigned n_ref;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen int r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(nl);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen n_ref = broadcast_group_get_ref(nl, group);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen assert(n_ref > 0);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen n_ref --;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = broadcast_group_set_ref(nl, group, n_ref);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (n_ref > 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen /* still refs left */
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen r = broadcast_group_leave(nl, group);
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen if (r < 0)
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return r;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen return 0;
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen}
9c5a882b7fc256ddc0b227677fa06546f0e944a8Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen/* returns the number of bytes sent, or a negative error code */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersenint socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen union {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen struct sockaddr sa;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen struct sockaddr_nl nl;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen } addr = {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen .nl.nl_family = AF_NETLINK,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen };
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen ssize_t k;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen assert(nl);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen assert(m);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen assert(m->hdr);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen 0, &addr.sa, sizeof(addr));
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (k < 0)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return -errno;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return k;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen}
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersenstatic int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen union sockaddr_union sender;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen uint8_t cmsg_buffer[CMSG_SPACE(sizeof(struct nl_pktinfo))];
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen struct msghdr msg = {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen .msg_iov = iov,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen .msg_iovlen = 1,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen .msg_name = &sender,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen .msg_namelen = sizeof(sender),
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen .msg_control = cmsg_buffer,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen .msg_controllen = sizeof(cmsg_buffer),
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen };
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen struct cmsghdr *cmsg;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen uint32_t group = 0;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen int r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen assert(fd >= 0);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen assert(iov);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r < 0) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* no data */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (errno == ENOBUFS)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen log_debug("rtnl: kernel receive buffer overrun");
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen else if (errno == EAGAIN)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen log_debug("rtnl: no data in socket");
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (sender.nl.nl_pid != 0) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* not from the kernel, ignore */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen log_debug("rtnl: ignoring message from portid %"PRIu32, sender.nl.nl_pid);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (peek) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* drop the message */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = recvmsg(fd, &msg, 0);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r < 0)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return 0;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen CMSG_FOREACH(cmsg, &msg) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (cmsg->cmsg_level == SOL_NETLINK &&
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen cmsg->cmsg_type == NETLINK_PKTINFO &&
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* multi-cast group */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen group = pktinfo->group;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (_group)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen *_group = group;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen}
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen/* On success, the number of bytes received is returned and *ret points to the received message
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen * which has a valid header and the correct size.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen * If nothing useful was received 0 is returned.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen * On failure, a negative error code is returned.
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersenint socket_read_message(sd_netlink *rtnl) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen struct iovec iov = {};
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen uint32_t group = 0;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen bool multi_part = false, done = false;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen struct nlmsghdr *new_msg;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen size_t len;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen int r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen unsigned i = 0;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen assert(rtnl);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen assert(rtnl->rbuffer);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* read nothing, just get the pending message size */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = socket_recv_message(rtnl->fd, &iov, NULL, true);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r <= 0)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen else
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen len = (size_t)r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* make room for the pending message */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (!greedy_realloc((void **)&rtnl->rbuffer,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen &rtnl->rbuffer_allocated,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen len, sizeof(uint8_t)))
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return -ENOMEM;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen iov.iov_base = rtnl->rbuffer;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen iov.iov_len = rtnl->rbuffer_allocated;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* read the pending message */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = socket_recv_message(rtnl->fd, &iov, &group, false);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r <= 0)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen else
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen len = (size_t)r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (len > rtnl->rbuffer_allocated)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* message did not fit in read buffer */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return -EIO;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen multi_part = true;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen for (i = 0; i < rtnl->rqueue_partial_size; i++) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen rtnl->rbuffer->nlmsg_seq) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen first = rtnl->rqueue_partial[i];
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen break;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen const NLType *nl_type;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* not broadcast and not for us */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen continue;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (new_msg->nlmsg_type == NLMSG_NOOP)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* silently drop noop messages */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen continue;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (new_msg->nlmsg_type == NLMSG_DONE) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* finished reading multi-part message */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen done = true;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* if first is not defined, put NLMSG_DONE into the receive queue. */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (first)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen continue;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* check that we support this message type */
846a6b3d89aaf4ee2cece0f10148f675c4796841David Herrmann r = type_system_get_type(&type_system_root, &nl_type, new_msg->nlmsg_type);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r < 0) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r == -EOPNOTSUPP)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen log_debug("sd-netlink: ignored message with unknown type: %i",
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen new_msg->nlmsg_type);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen continue;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* check that the size matches the message type */
817d1cd824bedba8feeef24c9724ec8bd160a7b2David Herrmann if (new_msg->nlmsg_len < NLMSG_LENGTH(type_get_size(nl_type))) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen log_debug("sd-netlink: message larger than expected, dropping");
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen continue;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = message_new_empty(rtnl, &m);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r < 0)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen m->broadcast = !!group;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen m->hdr = memdup(new_msg, new_msg->nlmsg_len);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (!m->hdr)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return -ENOMEM;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* seal and parse the top-level message */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = sd_netlink_message_rewind(m);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r < 0)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* push the message onto the multi-part message stack */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (first)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen m->next = first;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen first = m;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen m = NULL;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (len)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen log_debug("sd-netlink: discarding %zu bytes of incoming message", len);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (!first)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return 0;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (!multi_part || done) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* we got a complete message, push it on the read queue */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = rtnl_rqueue_make_room(rtnl);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r < 0)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen rtnl->rqueue[rtnl->rqueue_size ++] = first;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen first = NULL;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (multi_part && (i < rtnl->rqueue_partial_size)) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* remove the message form the partial read queue */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1));
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen rtnl->rqueue_partial_size --;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return 1;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen } else {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen /* we only got a partial multi-part message, push it on the
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen partial read queue */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (i < rtnl->rqueue_partial_size) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen rtnl->rqueue_partial[i] = first;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen } else {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = rtnl_rqueue_partial_make_room(rtnl);
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (r < 0)
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return r;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen first = NULL;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen return 0;
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen }
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen}