144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/nl.c		Core Netlink Interface
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
98a3efffa5b3fde252675239914118664d36a2c24Thomas Graf * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
136782b6f709d03877a5661a4c8d8f8bd1b461f43fThomas Graf * @defgroup core Core
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
154fd5f7cb6627a22bd9f228b4259d5106ae39d535Thomas Graf * @details
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 1) Connecting the socket
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Bind and connect the socket to a protocol, NETLINK_ROUTE in this example.
191155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_connect(sk, NETLINK_ROUTE);
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf *
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 2) Sending data
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * // The most rudimentary method is to use nl_sendto() simply pushing
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // a piece of data to the other netlink peer. This method is not
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // recommended.
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf * const char buf[] = { 0x01, 0x02, 0x03, 0x04 };
281155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_sendto(sk, buf, sizeof(buf));
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // A more comfortable interface is nl_send() taking a pointer to
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // a netlink message.
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct nl_msg *msg = my_msg_builder();
331155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_send(sk, nlmsg_hdr(msg));
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // nl_sendmsg() provides additional control over the sendmsg() message
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // header in order to allow more specific addressing of multiple peers etc.
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct msghdr hdr = { ... };
381155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_sendmsg(sk, nlmsg_hdr(msg), &hdr);
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // You're probably too lazy to fill out the netlink pid, sequence number
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // and message flags all the time. nl_send_auto_complete() automatically
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // extends your message header as needed with an appropriate sequence
431155370f520cb64657e25153255cf7dc1424317fThomas Graf * // number, the netlink pid stored in the netlink socket and the message
442bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf * // flags NLM_F_REQUEST and NLM_F_ACK (if not disabled in the socket)
451155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_send_auto_complete(sk, nlmsg_hdr(msg));
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Simple protocols don't require the complex message construction interface
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf * // and may favour nl_send_simple() to easly send a bunch of payload
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf * // encapsulated in a netlink message header.
501155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_send_simple(sk, MY_MSG_TYPE, 0, buf, sizeof(buf));
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 3) Receiving data
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf * // nl_recv() receives a single message allocating a buffer for the message
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // content and gives back the pointer to you.
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf * struct sockaddr_nl peer;
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf * unsigned char *msg;
591155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_recv(sk, &peer, &msg);
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // nl_recvmsgs() receives a bunch of messages until the callback system
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf * // orders it to state, usually after receving a compolete multi part
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf * // message series.
641155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_recvmsgs(sk, my_callback_configuration);
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf * // nl_recvmsgs_default() acts just like nl_recvmsg() but uses the callback
671155370f520cb64657e25153255cf7dc1424317fThomas Graf * // configuration stored in the socket.
681155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_recvmsgs_default(sk);
6944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf * // In case you want to wait for the ACK to be recieved that you requested
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf * // with your latest message, you can call nl_wait_for_ack()
721155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_wait_for_ack(sk);
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par 4) Closing
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf * // Close the socket first to release kernel memory
781155370f520cb64657e25153255cf7dc1424317fThomas Graf * nl_close(sk);
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf */
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/handlers.h>
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/msg.h>
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/attr.h>
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Connection Management
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
9544d362409d5469aed47d19e7908d19bd194493aThomas Graf
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Create and connect netlink socket.
981155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg protocol	Netlink protocol to use.
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Creates a netlink socket using the specified protocol, binds the socket
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf * and issues a connection attempt.
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code.
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1061155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_connect(struct nl_sock *sk, int protocol)
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf	socklen_t addrlen;
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf
1111155370f520cb64657e25153255cf7dc1424317fThomas Graf	sk->s_fd = socket(AF_NETLINK, SOCK_RAW, protocol);
1121155370f520cb64657e25153255cf7dc1424317fThomas Graf	if (sk->s_fd < 0) {
1138a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -nl_syserr2nlerr(errno);
11491c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf		goto errout;
11591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf	}
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf
1171155370f520cb64657e25153255cf7dc1424317fThomas Graf	if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) {
118664e1deaeb59ad9db0b2eeec613cf8a93551f567Thomas Graf		err = nl_socket_set_buffer_size(sk, 0, 0);
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (err < 0)
12091c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf			goto errout;
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf
1231155370f520cb64657e25153255cf7dc1424317fThomas Graf	err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
1241155370f520cb64657e25153255cf7dc1424317fThomas Graf		   sizeof(sk->s_local));
12591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf	if (err < 0) {
1268a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -nl_syserr2nlerr(errno);
12791c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf		goto errout;
12891c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf	}
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf
1301155370f520cb64657e25153255cf7dc1424317fThomas Graf	addrlen = sizeof(sk->s_local);
1311155370f520cb64657e25153255cf7dc1424317fThomas Graf	err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local,
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf			  &addrlen);
13391c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf	if (err < 0) {
1348a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -nl_syserr2nlerr(errno);
13591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf		goto errout;
13691c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf	}
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf
1381155370f520cb64657e25153255cf7dc1424317fThomas Graf	if (addrlen != sizeof(sk->s_local)) {
1398a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -NLE_NOADDR;
14091c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf		goto errout;
14191c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf	}
14244d362409d5469aed47d19e7908d19bd194493aThomas Graf
1431155370f520cb64657e25153255cf7dc1424317fThomas Graf	if (sk->s_local.nl_family != AF_NETLINK) {
1448a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -NLE_AF_NOSUPPORT;
14591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf		goto errout;
14691c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf	}
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf
1481155370f520cb64657e25153255cf7dc1424317fThomas Graf	sk->s_proto = protocol;
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
15191c330aae51cd6cd44ad730e10dc82724998c810Thomas Graferrout:
1521155370f520cb64657e25153255cf7dc1424317fThomas Graf	close(sk->s_fd);
1531155370f520cb64657e25153255cf7dc1424317fThomas Graf	sk->s_fd = -1;
15491c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf
15591c330aae51cd6cd44ad730e10dc82724998c810Thomas Graf	return err;
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Close/Disconnect netlink socket.
1601155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1621155370f520cb64657e25153255cf7dc1424317fThomas Grafvoid nl_close(struct nl_sock *sk)
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
1641155370f520cb64657e25153255cf7dc1424317fThomas Graf	if (sk->s_fd >= 0) {
1651155370f520cb64657e25153255cf7dc1424317fThomas Graf		close(sk->s_fd);
1661155370f520cb64657e25153255cf7dc1424317fThomas Graf		sk->s_fd = -1;
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf
1691155370f520cb64657e25153255cf7dc1424317fThomas Graf	sk->s_proto = 0;
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Send
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf */
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf * Send raw data over netlink socket.
1811155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf		Data buffer.
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg size		Size of data buffer.
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of characters written on success or a negative error code.
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1861155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_sendto(struct nl_sock *sk, void *buf, size_t size)
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int ret;
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf
1901155370f520cb64657e25153255cf7dc1424317fThomas Graf	ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *)
1911155370f520cb64657e25153255cf7dc1424317fThomas Graf		     &sk->s_peer, sizeof(sk->s_peer));
19244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (ret < 0)
1938a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -nl_syserr2nlerr(errno);
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return ret;
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Send netlink message with control over sendmsg() message header.
2001155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg msg		Netlink message to be sent.
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg hdr		Sendmsg() message header.
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of characters sent on sucess or a negative error code.
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
2051155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cb *cb;
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int ret;
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf
2101155370f520cb64657e25153255cf7dc1424317fThomas Graf	nlmsg_set_src(msg, &sk->s_local);
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf
2121155370f520cb64657e25153255cf7dc1424317fThomas Graf	cb = sk->s_cb;
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cb->cb_set[NL_CB_MSG_OUT])
21444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (nl_cb_call(cb, NL_CB_MSG_OUT, msg) != NL_OK)
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf			return 0;
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf
2171155370f520cb64657e25153255cf7dc1424317fThomas Graf	ret = sendmsg(sk->s_fd, hdr, 0);
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (ret < 0)
2198a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -nl_syserr2nlerr(errno);
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf
22127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto	NL_DBG(4, "sent %d bytes\n", ret);
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return ret;
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Send netlink message.
2281155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg msg		Netlink message to be sent.
23027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @arg iov		iovec to be sent.
23127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @arg iovlen		number of struct iovec to be sent.
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf * @see nl_sendmsg()
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of characters sent on success or a negative error code.
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
235256d7e723c0ff402422d3501866e9301b3f64c0fThomas Grafint nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen)
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct sockaddr_nl *dst;
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct ucred *creds;
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct msghdr hdr = {
2401155370f520cb64657e25153255cf7dc1424317fThomas Graf		.msg_name = (void *) &sk->s_peer,
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf		.msg_namelen = sizeof(struct sockaddr_nl),
24227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto		.msg_iov = iov,
24327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto		.msg_iovlen = iovlen,
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf	};
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf	/* Overwrite destination if specified in the message itself, defaults
2471155370f520cb64657e25153255cf7dc1424317fThomas Graf	 * to the peer address of the socket.
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf	 */
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf	dst = nlmsg_get_dst(msg);
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (dst->nl_family == AF_NETLINK)
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf		hdr.msg_name = dst;
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf	/* Add credentials if present. */
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf	creds = nlmsg_get_creds(msg);
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (creds != NULL) {
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf		char buf[CMSG_SPACE(sizeof(struct ucred))];
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct cmsghdr *cmsg;
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf		hdr.msg_control = buf;
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf		hdr.msg_controllen = sizeof(buf);
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf		cmsg = CMSG_FIRSTHDR(&hdr);
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf		cmsg->cmsg_level = SOL_SOCKET;
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf		cmsg->cmsg_type = SCM_CREDENTIALS;
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf		cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf		memcpy(CMSG_DATA(cmsg), creds, sizeof(struct ucred));
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf
2691155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nl_sendmsg(sk, msg, &hdr);
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf
27227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto
27327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
27527c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* Send netlink message.
27627c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* @arg sk		Netlink socket.
27727c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* @arg msg		Netlink message to be sent.
27827c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* @see nl_sendmsg()
27927c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto* @return Number of characters sent on success or a negative error code.
28027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto*/
28127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramotoint nl_send(struct nl_sock *sk, struct nl_msg *msg)
28227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto{
28327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto	struct iovec iov = {
28427c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto		.iov_base = (void *) nlmsg_hdr(msg),
28527c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto		.iov_len = nlmsg_hdr(msg)->nlmsg_len,
28627c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto	};
28727c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto
28827c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto	return nl_send_iovec(sk, msg, &iov, 1);
28927c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto}
29027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto
29127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramotovoid nl_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlmsghdr *nlh;
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlh = nlmsg_hdr(msg);
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (nlh->nlmsg_pid == 0)
2971155370f520cb64657e25153255cf7dc1424317fThomas Graf		nlh->nlmsg_pid = sk->s_local.nl_pid;
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (nlh->nlmsg_seq == 0)
3001155370f520cb64657e25153255cf7dc1424317fThomas Graf		nlh->nlmsg_seq = sk->s_seq_next++;
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (msg->nm_protocol == -1)
3031155370f520cb64657e25153255cf7dc1424317fThomas Graf		msg->nm_protocol = sk->s_proto;
30427c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto
3052bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf	nlh->nlmsg_flags |= NLM_F_REQUEST;
3062bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf
3072bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf	if (!(sk->s_flags & NL_NO_AUTO_ACK))
3082bdee95a765457fe4206b89d51974ae56e75c588Thomas Graf		nlh->nlmsg_flags |= NLM_F_ACK;
30927c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto}
31027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto
31127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto/**
31227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * Send netlink message and check & extend header values as needed.
31327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @arg sk		Netlink socket.
31427c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @arg msg		Netlink message to be sent.
31527c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto *
31627c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * Checks the netlink message \c nlh for completness and extends it
31727c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * as required before sending it out. Checked fields include pid,
31827c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * sequence nr, and flags.
31927c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto *
32027c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @see nl_send()
32127c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto * @return Number of characters sent or a negative error code.
32227c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto */
32327c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramotoint nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
32427c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto{
32527c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto	struct nl_cb *cb = sk->s_cb;
32627c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto
32727c505eb89f7a689416f822e26c0ccea0b351ba3Karl Hiramoto	nl_auto_complete(sk, msg);
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cb->cb_send_ow)
3301155370f520cb64657e25153255cf7dc1424317fThomas Graf		return cb->cb_send_ow(sk, msg);
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
3321155370f520cb64657e25153255cf7dc1424317fThomas Graf		return nl_send(sk, msg);
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf * Send simple netlink message using nl_send_auto_complete()
3371155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg type		Netlink message type.
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg flags		Netlink message flags.
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf		Data buffer.
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg size		Size of data buffer.
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf * Builds a netlink message with the specified type and flags and
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf * appends the specified data as payload to the message.
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @see nl_send_auto_complete()
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of characters sent on success or a negative error code.
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
3491155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_send_simple(struct nl_sock *sk, int type, int flags, void *buf,
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf		   size_t size)
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg;
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = nlmsg_alloc_simple(type, flags);
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!msg)
3578a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf
3596de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf	if (buf && size) {
3606de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf		err = nlmsg_append(msg, buf, size, NLMSG_ALIGNTO);
3616de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf		if (err < 0)
3626de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf			goto errout;
3636de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf	}
3646de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graf
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf
3661155370f520cb64657e25153255cf7dc1424317fThomas Graf	err = nl_send_auto_complete(sk, msg);
3676de17f3308cfd53ad922d144a1b28ddd962d6678Thomas Graferrout:
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlmsg_free(msg);
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Receive
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Receive data from netlink socket
3821155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg nla		Destination pointer for peer's netlink address.
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg buf		Destination pointer for message content.
38544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg creds		Destination pointer for credentials.
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Receives a netlink message, allocates a buffer in \c *buf and
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf * stores the message content. The peer's netlink address is stored
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf * in \c *nla. The caller is responsible for freeing the buffer allocated
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf * in \c *buf if a positive value is returned.  Interruped system calls
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf * are handled by repeating the read. The input buffer size is determined
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf * by peeking before the actual read is done.
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf * A non-blocking sockets causes the function to return immediately with
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf * a return value of 0 if no data is available.
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf *
39744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return Number of octets read, 0 on EOF or a negative error code.
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
3991155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla,
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf	    unsigned char **buf, struct ucred **creds)
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf	int n;
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf	int flags = 0;
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf	static int page_size = 0;
40544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct iovec iov;
40644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct msghdr msg = {
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf		.msg_name = (void *) nla,
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf		.msg_namelen = sizeof(struct sockaddr_nl),
40944d362409d5469aed47d19e7908d19bd194493aThomas Graf		.msg_iov = &iov,
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf		.msg_iovlen = 1,
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf		.msg_control = NULL,
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf		.msg_controllen = 0,
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf		.msg_flags = 0,
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf	};
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct cmsghdr *cmsg;
41644d362409d5469aed47d19e7908d19bd194493aThomas Graf
4171155370f520cb64657e25153255cf7dc1424317fThomas Graf	if (sk->s_flags & NL_MSG_PEEK)
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf		flags |= MSG_PEEK;
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf
42044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (page_size == 0)
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf		page_size = getpagesize();
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf	iov.iov_len = page_size;
424b7c5bf98c4079304f78242d8b3c65451efc12b77Thomas Graf	iov.iov_base = *buf = malloc(iov.iov_len);
42544d362409d5469aed47d19e7908d19bd194493aThomas Graf
4261155370f520cb64657e25153255cf7dc1424317fThomas Graf	if (sk->s_flags & NL_SOCK_PASSCRED) {
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf		msg.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf		msg.msg_control = calloc(1, msg.msg_controllen);
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
43044d362409d5469aed47d19e7908d19bd194493aThomas Grafretry:
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf
4321155370f520cb64657e25153255cf7dc1424317fThomas Graf	n = recvmsg(sk->s_fd, &msg, flags);
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!n)
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto abort;
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else if (n < 0) {
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (errno == EINTR) {
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf			NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto retry;
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf		} else if (errno == EAGAIN) {
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf			NL_DBG(3, "recvmsg() returned EAGAIN, aborting\n");
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto abort;
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf		} else {
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf			free(msg.msg_control);
44444d362409d5469aed47d19e7908d19bd194493aThomas Graf			free(*buf);
4458a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -nl_syserr2nlerr(errno);
44644d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (iov.iov_len < n ||
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf	    msg.msg_flags & MSG_TRUNC) {
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Provided buffer is not long enough, enlarge it
45244d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * and try again. */
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf		iov.iov_len *= 2;
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf		iov.iov_base = *buf = realloc(*buf, iov.iov_len);
45544d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto retry;
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else if (msg.msg_flags & MSG_CTRUNC) {
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf		msg.msg_controllen *= 2;
45844d362409d5469aed47d19e7908d19bd194493aThomas Graf		msg.msg_control = realloc(msg.msg_control, msg.msg_controllen);
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto retry;
46044d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else if (flags != 0) {
46144d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Buffer is big enough, do the actual reading */
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf		flags = 0;
46344d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto retry;
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
46544d362409d5469aed47d19e7908d19bd194493aThomas Graf
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
46744d362409d5469aed47d19e7908d19bd194493aThomas Graf		free(msg.msg_control);
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf		free(*buf);
4698a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOADDR;
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (cmsg->cmsg_level == SOL_SOCKET &&
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf		    cmsg->cmsg_type == SCM_CREDENTIALS) {
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf			*creds = calloc(1, sizeof(struct ucred));
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf			memcpy(*creds, CMSG_DATA(cmsg), sizeof(struct ucred));
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf			break;
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(msg.msg_control);
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return n;
48344d362409d5469aed47d19e7908d19bd194493aThomas Graf
48444d362409d5469aed47d19e7908d19bd194493aThomas Grafabort:
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(msg.msg_control);
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(*buf);
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define NL_CB_CALL(cb, type, msg) \
49144d362409d5469aed47d19e7908d19bd194493aThomas Grafdo { \
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = nl_cb_call(cb, type, msg); \
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf	switch (err) { \
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf	case NL_OK: \
49544d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = 0; \
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf		break; \
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf	case NL_SKIP: \
49844d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto skip; \
49944d362409d5469aed47d19e7908d19bd194493aThomas Graf	case NL_STOP: \
50044d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto stop; \
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf	default: \
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto out; \
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf	} \
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf} while (0)
50544d362409d5469aed47d19e7908d19bd194493aThomas Graf
5061155370f520cb64657e25153255cf7dc1424317fThomas Grafstatic int recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf	int n, err = 0, multipart = 0;
50923ee46ef7115c2e311c36e43a833e6c3deada18aThomas Graf	unsigned char *buf = NULL;
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nlmsghdr *hdr;
51144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct sockaddr_nl nla = {0};
51244d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_msg *msg = NULL;
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct ucred *creds = NULL;
51444d362409d5469aed47d19e7908d19bd194493aThomas Graf
51544d362409d5469aed47d19e7908d19bd194493aThomas Grafcontinue_reading:
5161155370f520cb64657e25153255cf7dc1424317fThomas Graf	NL_DBG(3, "Attempting to read from %p\n", sk);
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cb->cb_recv_ow)
5181155370f520cb64657e25153255cf7dc1424317fThomas Graf		n = cb->cb_recv_ow(sk, &nla, &buf, &creds);
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
5201155370f520cb64657e25153255cf7dc1424317fThomas Graf		n = nl_recv(sk, &nla, &buf, &creds);
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (n <= 0)
52344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return n;
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf
5251155370f520cb64657e25153255cf7dc1424317fThomas Graf	NL_DBG(3, "recvmsgs(%p): Read %d bytes\n", sk, n);
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf	hdr = (struct nlmsghdr *) buf;
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf	while (nlmsg_ok(hdr, n)) {
5291155370f520cb64657e25153255cf7dc1424317fThomas Graf		NL_DBG(3, "recgmsgs(%p): Processing valid message...\n", sk);
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf
53123ee46ef7115c2e311c36e43a833e6c3deada18aThomas Graf		nlmsg_free(msg);
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf		msg = nlmsg_convert(hdr);
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!msg) {
5348a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			err = -NLE_NOMEM;
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto out;
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf
5381155370f520cb64657e25153255cf7dc1424317fThomas Graf		nlmsg_set_proto(msg, sk->s_proto);
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nlmsg_set_src(msg, &nla);
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (creds)
54144d362409d5469aed47d19e7908d19bd194493aThomas Graf			nlmsg_set_creds(msg, creds);
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Raw callback is the first, it gives the most control
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * to the user and he can do his very own parsing. */
54544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (cb->cb_set[NL_CB_MSG_IN])
54644d362409d5469aed47d19e7908d19bd194493aThomas Graf			NL_CB_CALL(cb, NL_CB_MSG_IN, msg);
54744d362409d5469aed47d19e7908d19bd194493aThomas Graf
54844d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Sequence number checking. The check may be done by
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * the user, otherwise a very simple check is applied
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * enforcing strict ordering */
55144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (cb->cb_set[NL_CB_SEQ_CHECK])
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf			NL_CB_CALL(cb, NL_CB_SEQ_CHECK, msg);
5531155370f520cb64657e25153255cf7dc1424317fThomas Graf		else if (hdr->nlmsg_seq != sk->s_seq_expect) {
55444d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (cb->cb_set[NL_CB_INVALID])
55544d362409d5469aed47d19e7908d19bd194493aThomas Graf				NL_CB_CALL(cb, NL_CB_INVALID, msg);
55644d362409d5469aed47d19e7908d19bd194493aThomas Graf			else {
5578a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				err = -NLE_SEQ_MISMATCH;
55844d362409d5469aed47d19e7908d19bd194493aThomas Graf				goto out;
55944d362409d5469aed47d19e7908d19bd194493aThomas Graf			}
56044d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf
56244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (hdr->nlmsg_type == NLMSG_DONE ||
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf		    hdr->nlmsg_type == NLMSG_ERROR ||
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf		    hdr->nlmsg_type == NLMSG_NOOP ||
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf		    hdr->nlmsg_type == NLMSG_OVERRUN) {
56644d362409d5469aed47d19e7908d19bd194493aThomas Graf			/* We can't check for !NLM_F_MULTI since some netlink
56744d362409d5469aed47d19e7908d19bd194493aThomas Graf			 * users in the kernel are broken. */
5681155370f520cb64657e25153255cf7dc1424317fThomas Graf			sk->s_seq_expect++;
56944d362409d5469aed47d19e7908d19bd194493aThomas Graf			NL_DBG(3, "recvmsgs(%p): Increased expected " \
57044d362409d5469aed47d19e7908d19bd194493aThomas Graf			       "sequence number to %d\n",
5711155370f520cb64657e25153255cf7dc1424317fThomas Graf			       sk, sk->s_seq_expect);
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf
57444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (hdr->nlmsg_flags & NLM_F_MULTI)
57544d362409d5469aed47d19e7908d19bd194493aThomas Graf			multipart = 1;
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Other side wishes to see an ack for this message */
57844d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (hdr->nlmsg_flags & NLM_F_ACK) {
57944d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (cb->cb_set[NL_CB_SEND_ACK])
58044d362409d5469aed47d19e7908d19bd194493aThomas Graf				NL_CB_CALL(cb, NL_CB_SEND_ACK, msg);
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf			else {
58244d362409d5469aed47d19e7908d19bd194493aThomas Graf				/* FIXME: implement */
58344d362409d5469aed47d19e7908d19bd194493aThomas Graf			}
58444d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
58544d362409d5469aed47d19e7908d19bd194493aThomas Graf
58644d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* messages terminates a multpart message, this is
58744d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * usually the end of a message and therefore we slip
58844d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * out of the loop by default. the user may overrule
58944d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * this action by skipping this packet. */
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (hdr->nlmsg_type == NLMSG_DONE) {
59144d362409d5469aed47d19e7908d19bd194493aThomas Graf			multipart = 0;
59244d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (cb->cb_set[NL_CB_FINISH])
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf				NL_CB_CALL(cb, NL_CB_FINISH, msg);
59444d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf
59644d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Message to be ignored, the default action is to
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * skip this message if no callback is specified. The
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * user may overrule this action by returning
59944d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * NL_PROCEED. */
60044d362409d5469aed47d19e7908d19bd194493aThomas Graf		else if (hdr->nlmsg_type == NLMSG_NOOP) {
60144d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (cb->cb_set[NL_CB_SKIPPED])
60244d362409d5469aed47d19e7908d19bd194493aThomas Graf				NL_CB_CALL(cb, NL_CB_SKIPPED, msg);
60344d362409d5469aed47d19e7908d19bd194493aThomas Graf			else
60444d362409d5469aed47d19e7908d19bd194493aThomas Graf				goto skip;
60544d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
60644d362409d5469aed47d19e7908d19bd194493aThomas Graf
60744d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Data got lost, report back to user. The default action is to
60844d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * quit parsing. The user may overrule this action by retuning
60944d362409d5469aed47d19e7908d19bd194493aThomas Graf		 * NL_SKIP or NL_PROCEED (dangerous) */
61044d362409d5469aed47d19e7908d19bd194493aThomas Graf		else if (hdr->nlmsg_type == NLMSG_OVERRUN) {
61144d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (cb->cb_set[NL_CB_OVERRUN])
61244d362409d5469aed47d19e7908d19bd194493aThomas Graf				NL_CB_CALL(cb, NL_CB_OVERRUN, msg);
61344d362409d5469aed47d19e7908d19bd194493aThomas Graf			else {
6148a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				err = -NLE_MSG_OVERFLOW;
61544d362409d5469aed47d19e7908d19bd194493aThomas Graf				goto out;
61644d362409d5469aed47d19e7908d19bd194493aThomas Graf			}
61744d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
61844d362409d5469aed47d19e7908d19bd194493aThomas Graf
61944d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Message carries a nlmsgerr */
62044d362409d5469aed47d19e7908d19bd194493aThomas Graf		else if (hdr->nlmsg_type == NLMSG_ERROR) {
62144d362409d5469aed47d19e7908d19bd194493aThomas Graf			struct nlmsgerr *e = nlmsg_data(hdr);
62244d362409d5469aed47d19e7908d19bd194493aThomas Graf
62344d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (hdr->nlmsg_len < nlmsg_msg_size(sizeof(*e))) {
62444d362409d5469aed47d19e7908d19bd194493aThomas Graf				/* Truncated error message, the default action
62544d362409d5469aed47d19e7908d19bd194493aThomas Graf				 * is to stop parsing. The user may overrule
62644d362409d5469aed47d19e7908d19bd194493aThomas Graf				 * this action by returning NL_SKIP or
62744d362409d5469aed47d19e7908d19bd194493aThomas Graf				 * NL_PROCEED (dangerous) */
62844d362409d5469aed47d19e7908d19bd194493aThomas Graf				if (cb->cb_set[NL_CB_INVALID])
62944d362409d5469aed47d19e7908d19bd194493aThomas Graf					NL_CB_CALL(cb, NL_CB_INVALID, msg);
63044d362409d5469aed47d19e7908d19bd194493aThomas Graf				else {
6318a3efffa5b3fde252675239914118664d36a2c24Thomas Graf					err = -NLE_MSG_TRUNC;
63244d362409d5469aed47d19e7908d19bd194493aThomas Graf					goto out;
63344d362409d5469aed47d19e7908d19bd194493aThomas Graf				}
63444d362409d5469aed47d19e7908d19bd194493aThomas Graf			} else if (e->error) {
63544d362409d5469aed47d19e7908d19bd194493aThomas Graf				/* Error message reported back from kernel. */
63644d362409d5469aed47d19e7908d19bd194493aThomas Graf				if (cb->cb_err) {
63744d362409d5469aed47d19e7908d19bd194493aThomas Graf					err = cb->cb_err(&nla, e,
63844d362409d5469aed47d19e7908d19bd194493aThomas Graf							   cb->cb_err_arg);
63944d362409d5469aed47d19e7908d19bd194493aThomas Graf					if (err < 0)
64044d362409d5469aed47d19e7908d19bd194493aThomas Graf						goto out;
64144d362409d5469aed47d19e7908d19bd194493aThomas Graf					else if (err == NL_SKIP)
64244d362409d5469aed47d19e7908d19bd194493aThomas Graf						goto skip;
64344d362409d5469aed47d19e7908d19bd194493aThomas Graf					else if (err == NL_STOP) {
6448a3efffa5b3fde252675239914118664d36a2c24Thomas Graf						err = -nl_syserr2nlerr(e->error);
64544d362409d5469aed47d19e7908d19bd194493aThomas Graf						goto out;
64644d362409d5469aed47d19e7908d19bd194493aThomas Graf					}
64744d362409d5469aed47d19e7908d19bd194493aThomas Graf				} else {
6488a3efffa5b3fde252675239914118664d36a2c24Thomas Graf					err = -nl_syserr2nlerr(e->error);
64944d362409d5469aed47d19e7908d19bd194493aThomas Graf					goto out;
65044d362409d5469aed47d19e7908d19bd194493aThomas Graf				}
65144d362409d5469aed47d19e7908d19bd194493aThomas Graf			} else if (cb->cb_set[NL_CB_ACK])
65244d362409d5469aed47d19e7908d19bd194493aThomas Graf				NL_CB_CALL(cb, NL_CB_ACK, msg);
65344d362409d5469aed47d19e7908d19bd194493aThomas Graf		} else {
65444d362409d5469aed47d19e7908d19bd194493aThomas Graf			/* Valid message (not checking for MULTIPART bit to
65544d362409d5469aed47d19e7908d19bd194493aThomas Graf			 * get along with broken kernels. NL_SKIP has no
65644d362409d5469aed47d19e7908d19bd194493aThomas Graf			 * effect on this.  */
65744d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (cb->cb_set[NL_CB_VALID])
65844d362409d5469aed47d19e7908d19bd194493aThomas Graf				NL_CB_CALL(cb, NL_CB_VALID, msg);
65944d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
66044d362409d5469aed47d19e7908d19bd194493aThomas Grafskip:
66144d362409d5469aed47d19e7908d19bd194493aThomas Graf		err = 0;
66244d362409d5469aed47d19e7908d19bd194493aThomas Graf		hdr = nlmsg_next(hdr, &n);
66344d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
66444d362409d5469aed47d19e7908d19bd194493aThomas Graf
66523ee46ef7115c2e311c36e43a833e6c3deada18aThomas Graf	nlmsg_free(msg);
66644d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(buf);
66744d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(creds);
66844d362409d5469aed47d19e7908d19bd194493aThomas Graf	buf = NULL;
66944d362409d5469aed47d19e7908d19bd194493aThomas Graf	msg = NULL;
67044d362409d5469aed47d19e7908d19bd194493aThomas Graf	creds = NULL;
67144d362409d5469aed47d19e7908d19bd194493aThomas Graf
67244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (multipart) {
67344d362409d5469aed47d19e7908d19bd194493aThomas Graf		/* Multipart message not yet complete, continue reading */
67444d362409d5469aed47d19e7908d19bd194493aThomas Graf		goto continue_reading;
67544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
67644d362409d5469aed47d19e7908d19bd194493aThomas Grafstop:
67744d362409d5469aed47d19e7908d19bd194493aThomas Graf	err = 0;
67844d362409d5469aed47d19e7908d19bd194493aThomas Grafout:
67944d362409d5469aed47d19e7908d19bd194493aThomas Graf	nlmsg_free(msg);
68044d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(buf);
68144d362409d5469aed47d19e7908d19bd194493aThomas Graf	free(creds);
68244d362409d5469aed47d19e7908d19bd194493aThomas Graf
68344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
68444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
68544d362409d5469aed47d19e7908d19bd194493aThomas Graf
68644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
68744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Receive a set of messages from a netlink socket.
6881155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
68944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @arg cb		set of callbacks to control behaviour.
69044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
69144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Repeatedly calls nl_recv() or the respective replacement if provided
69244d362409d5469aed47d19e7908d19bd194493aThomas Graf * by the application (see nl_cb_overwrite_recv()) and parses the
69344d362409d5469aed47d19e7908d19bd194493aThomas Graf * received data as netlink messages. Stops reading if one of the
69444d362409d5469aed47d19e7908d19bd194493aThomas Graf * callbacks returns NL_STOP or nl_recv returns either 0 or a negative error code.
69544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
69644d362409d5469aed47d19e7908d19bd194493aThomas Graf * A non-blocking sockets causes the function to return immediately if
69744d362409d5469aed47d19e7908d19bd194493aThomas Graf * no data is available.
69844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
69944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @return 0 on success or a negative error code from nl_recv().
70044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
7011155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
70244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
70344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cb->cb_recvmsgs_ow)
7041155370f520cb64657e25153255cf7dc1424317fThomas Graf		return cb->cb_recvmsgs_ow(sk, cb);
70544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
7061155370f520cb64657e25153255cf7dc1424317fThomas Graf		return recvmsgs(sk, cb);
70744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
70844d362409d5469aed47d19e7908d19bd194493aThomas Graf
70944d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
7101155370f520cb64657e25153255cf7dc1424317fThomas Graf * Receive a set of message from a netlink socket using handlers in nl_sock.
7111155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
71244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
7131155370f520cb64657e25153255cf7dc1424317fThomas Graf * Calls nl_recvmsgs() with the handlers configured in the netlink socket.
71444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
7151155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_recvmsgs_default(struct nl_sock *sk)
71644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
7171155370f520cb64657e25153255cf7dc1424317fThomas Graf	return nl_recvmsgs(sk, sk->s_cb);
71844d362409d5469aed47d19e7908d19bd194493aThomas Graf
71944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
72044d362409d5469aed47d19e7908d19bd194493aThomas Graf
72144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int ack_wait_handler(struct nl_msg *msg, void *arg)
72244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
72344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return NL_STOP;
72444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
72544d362409d5469aed47d19e7908d19bd194493aThomas Graf
72644d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
72744d362409d5469aed47d19e7908d19bd194493aThomas Graf * Wait for ACK.
7281155370f520cb64657e25153255cf7dc1424317fThomas Graf * @arg sk		Netlink socket.
72944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @pre The netlink socket must be in blocking state.
73044d362409d5469aed47d19e7908d19bd194493aThomas Graf *
73144d362409d5469aed47d19e7908d19bd194493aThomas Graf * Waits until an ACK is received for the latest not yet acknowledged
73244d362409d5469aed47d19e7908d19bd194493aThomas Graf * netlink message.
73344d362409d5469aed47d19e7908d19bd194493aThomas Graf */
7341155370f520cb64657e25153255cf7dc1424317fThomas Grafint nl_wait_for_ack(struct nl_sock *sk)
73544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
73644d362409d5469aed47d19e7908d19bd194493aThomas Graf	int err;
73744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cb *cb;
73844d362409d5469aed47d19e7908d19bd194493aThomas Graf
7391155370f520cb64657e25153255cf7dc1424317fThomas Graf	cb = nl_cb_clone(sk->s_cb);
74044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (cb == NULL)
7418a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_NOMEM;
74244d362409d5469aed47d19e7908d19bd194493aThomas Graf
74344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_wait_handler, NULL);
7441155370f520cb64657e25153255cf7dc1424317fThomas Graf	err = nl_recvmsgs(sk, cb);
74544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_cb_put(cb);
74644d362409d5469aed47d19e7908d19bd194493aThomas Graf
74744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return err;
74844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
74944d362409d5469aed47d19e7908d19bd194493aThomas Graf
75044d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
75144d362409d5469aed47d19e7908d19bd194493aThomas Graf
75244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
753