netlink-socket.c revision b95cc756de7a27f7546e42dd9acf6da0669da402
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
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
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "util.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "socket-util.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "formats-util.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "refcnt.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "missing.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "sd-netlink.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "netlink-util.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "netlink-internal.h"
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen#include "netlink-types.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
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
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen return 0;
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen}
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersen
b95cc756de7a27f7546e42dd9acf6da0669da402Tom Gundersenint socket_join_broadcast_group(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
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) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen _cleanup_netlink_message_unref_ 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)) {
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen _cleanup_netlink_message_unref_ 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 */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen r = type_system_get_type(NULL, &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 */
89489ef7d451d61e176764deb608a84e29b1fd38Tom Gundersen if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
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}