netlink-socket.c revision b5efdb8af40ea759a1ea584c1bc44ecc81dd00ce
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Tom Gundersen <teg@jklm.no>
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <stdbool.h>
#include <unistd.h>
#include "sd-netlink.h"
#include "alloc-util.h"
#include "formats-util.h"
#include "missing.h"
#include "netlink-internal.h"
#include "netlink-types.h"
#include "netlink-util.h"
#include "refcnt.h"
#include "socket-util.h"
#include "util.h"
int socket_open(int family) {
int fd;
if (fd < 0)
return -errno;
return fd;
}
unsigned i, j;
int r;
if (r < 0) {
if (errno == ENOPROTOOPT) {
nl->broadcast_group_dont_leave = true;
return 0;
} else
return -errno;
}
if (len == 0)
return 0;
if (!groups)
return -ENOMEM;
if (r < 0)
return -errno;
return -EIO;
if (r < 0)
return r;
for (i = 0; i < len; i++) {
for (j = 0; j < sizeof(uint32_t) * 8; j ++) {
unsigned group;
offset = 1U << j;
continue;
if (r < 0)
return r;
}
}
return 0;
}
int r, one = 1;
if (r < 0)
return -errno;
/* ignore EINVAL to allow opening an already bound socket */
return -errno;
if (r < 0)
return -errno;
r = broadcast_groups_get(nl);
if (r < 0)
return r;
return 0;
}
}
int r;
if (r < 0)
return r;
return 0;
}
int r;
if (r < 0)
return -errno;
return 0;
}
unsigned n_ref;
int r;
n_ref ++;
if (r < 0)
return r;
if (r < 0)
return r;
if (n_ref > 1)
/* not yet in the group */
return 0;
if (r < 0)
return r;
return 0;
}
int r;
if (nl->broadcast_group_dont_leave)
return 0;
if (r < 0)
return -errno;
return 0;
}
unsigned n_ref;
int r;
n_ref --;
if (r < 0)
return r;
if (n_ref > 0)
/* still refs left */
return 0;
if (r < 0)
return r;
return 0;
}
/* returns the number of bytes sent, or a negative error code */
union {
struct sockaddr_nl nl;
} addr = {
};
ssize_t k;
assert(m);
if (k < 0)
return -errno;
return k;
}
union sockaddr_union sender;
.msg_iovlen = 1,
.msg_namelen = sizeof(sender),
.msg_controllen = sizeof(cmsg_buffer),
};
int r;
if (r < 0) {
/* no data */
log_debug("rtnl: kernel receive buffer overrun");
log_debug("rtnl: no data in socket");
}
/* not from the kernel, ignore */
if (peek) {
/* drop the message */
if (r < 0)
}
return 0;
}
/* multi-cast group */
}
}
if (_group)
return r;
}
/* On success, the number of bytes received is returned and *ret points to the received message
* which has a valid header and the correct size.
* If nothing useful was received 0 is returned.
* On failure, a negative error code is returned.
*/
bool multi_part = false, done = false;
int r;
unsigned i = 0;
/* read nothing, just get the pending message size */
if (r <= 0)
return r;
else
/* make room for the pending message */
return -ENOMEM;
/* read the pending message */
if (r <= 0)
return r;
else
/* message did not fit in read buffer */
return -EIO;
multi_part = true;
for (i = 0; i < rtnl->rqueue_partial_size; i++) {
break;
}
}
}
for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
/* not broadcast and not for us */
continue;
/* silently drop noop messages */
continue;
/* finished reading multi-part message */
done = true;
/* if first is not defined, put NLMSG_DONE into the receive queue. */
if (first)
continue;
}
/* check that we support this message type */
if (r < 0) {
if (r == -EOPNOTSUPP)
log_debug("sd-netlink: ignored message with unknown type: %i",
continue;
}
/* check that the size matches the message type */
log_debug("sd-netlink: message larger than expected, dropping");
continue;
}
r = message_new_empty(rtnl, &m);
if (r < 0)
return r;
if (!m->hdr)
return -ENOMEM;
/* seal and parse the top-level message */
r = sd_netlink_message_rewind(m);
if (r < 0)
return r;
/* push the message onto the multi-part message stack */
if (first)
first = m;
m = NULL;
}
if (len)
if (!first)
return 0;
if (!multi_part || done) {
/* we got a complete message, push it on the read queue */
r = rtnl_rqueue_make_room(rtnl);
if (r < 0)
return r;
/* remove the message form the partial read queue */
rtnl->rqueue_partial_size --;
}
return 1;
} else {
/* we only got a partial multi-part message, push it on the
partial read queue */
if (i < rtnl->rqueue_partial_size) {
} else {
if (r < 0)
return r;
}
return 0;
}
}