netlink.c revision d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7
1ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/*
2ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Copyright (C) 2011 The Android Open Source Project
3ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
4ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Licensed under the Apache License, Version 2.0 (the "License");
5ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * you may not use this file except in compliance with the License.
6ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * You may obtain a copy of the License at
7ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
8ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *	http://www.apache.org/licenses/LICENSE-2.0
9ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker *
10ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * Unless required by applicable law or agreed to in writing, software
11ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * distributed under the License is distributed on an "AS IS" BASIS,
12ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * See the License for the specific language governing permissions and
14ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * limitations under the License.
15ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker */
16ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
17ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* NOTICE: This is a clean room re-implementation of libnl */
18ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
19ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <errno.h>
20ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <string.h>
21ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <unistd.h>
22ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <fcntl.h>
23ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include <sys/socket.h>
24ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#include "netlink-types.h"
25ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
26ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker#define NL_BUFFER_SZ (32768U)
27ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
28ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Checks message for completeness and sends it out */
29ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
30ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
31ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct nlmsghdr *nlh = msg->nm_nlh;
32ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct timeval tv;
33ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
34ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (!nlh) {
35ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		int errsv = errno;
36ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		fprintf(stderr, "Netlink message header is NULL!\n");
37ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		return -errsv;
38ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	}
39ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
40ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Complete the nl_msg header */
41ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (gettimeofday(&tv, NULL))
42ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		nlh->nlmsg_seq = 1;
43ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	else
44ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		nlh->nlmsg_seq = (int) tv.tv_sec;
45ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlh->nlmsg_pid = sk->s_local.nl_pid;
46ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	nlh->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK;
47ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
48ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return nl_send(sk, msg);
49ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
50ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
51ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Receives a netlink message, allocates a buffer in *buf and stores
52ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * the message content. The peer's netlink address is stored in
53ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * *nla. The caller is responsible for freeing the buffer allocated in
54ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * *buf if a positive value is returned. Interrupted system calls are
55ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * handled by repeating the read. The input buffer size is determined
56ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker * by peeking before the actual read is done */
57ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, \
58ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	unsigned char **buf, struct ucred **creds)
59ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
60ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int rc = -1;
61ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int sk_flags;
62d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	int RECV_BUF_SIZE = getpagesize();
63ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int errsv;
64ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct iovec recvmsg_iov;
65ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct msghdr msg;
66ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
67ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Allocate buffer */
68ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	*buf = (unsigned char *) malloc(RECV_BUF_SIZE);
69d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	if (!(*buf)) {
70ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		rc = -ENOMEM;
71ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		goto fail;
72ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	}
73ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
74ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Prepare to receive message */
75ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	recvmsg_iov.iov_base = *buf;
76ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	recvmsg_iov.iov_len = RECV_BUF_SIZE;
77ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
78ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_name = (void *) &sk->s_peer;
79ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_namelen = sizeof(sk->s_peer);
80ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_iov = &recvmsg_iov;
81ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_iovlen = 1;
82ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_control = NULL;
83ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_controllen = 0;
84ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg.msg_flags = 0;
85ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
86ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Make non blocking and then restore previous setting */
87ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sk_flags = fcntl(sk->s_fd, F_GETFL, 0);
88ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	fcntl(sk->s_fd, F_SETFL, O_NONBLOCK);
89ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	rc = recvmsg(sk->s_fd, &msg, 0);
90ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	errsv = errno;
91ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	fcntl(sk->s_fd, F_SETFL, sk_flags);
92ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
93d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	if (rc < 0) {
94ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		rc = -errsv;
95d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt		free(*buf);
96d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt		*buf = NULL;
97d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	}
98ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
99ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerfail:
100ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return rc;
101ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
102ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
103ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Receive a set of messages from a netlink socket */
104ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* NOTE: Does not currently support callback replacements!!! */
105ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
106ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
107ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct sockaddr_nl nla;
108ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct ucred *creds;
109ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
110ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int rc, cb_rc = NL_OK, done = 0;
111ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
112ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	do {
113ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		unsigned char *buf;
114ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		int i, rem, flags;
115ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		struct nlmsghdr *nlh;
116ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		struct nlmsgerr *nlme;
117ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		struct nl_msg *msg;
118ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
119ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		done = 0;
120ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		rc = nl_recv(sk, &nla, &buf, &creds);
121ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		if (rc < 0)
122ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			break;
123ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
124ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) buf, rc, rem) {
125ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
126ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			if (rc <= 0 || cb_rc == NL_STOP)
127ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				break;
128ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
129ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			/* Check for callbacks */
130ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
131d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt			msg = (struct nl_msg *) malloc(sizeof(struct nl_msg));
132ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			memset(msg, 0, sizeof(*msg));
133ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			msg->nm_nlh = nlh;
134ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
135ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			/* Check netlink message type */
136ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
137ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			switch (msg->nm_nlh->nlmsg_type) {
138ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_ERROR:	  /* Used for ACK too */
139ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				/* Certainly we should be doing some
140ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				 * checking here to make sure this
141ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				 * message is intended for us */
142ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				nlme = nlmsg_data(msg->nm_nlh);
143ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				if (nlme->error == 0)
144ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					msg->nm_nlh->nlmsg_flags |= NLM_F_ACK;
145ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
146ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				rc = nlme->error;
147ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				cb_rc = cb->cb_err(&nla, nlme, cb->cb_err_arg);
148ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				nlme = NULL;
149ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				break;
150ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
151ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_DONE:
152ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				done = 1;
153ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
154ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_OVERRUN:
155ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			case NLMSG_NOOP:
156ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			default:
157ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				break;
158ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			};
159ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
160ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
161ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
162ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				if (cb->cb_set[i]) {
163ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					switch (i) {
164ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					case NL_CB_VALID:
165ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						if (rc > 0)
166ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
167ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						break;
168ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
169ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					case NL_CB_FINISH:
170ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						if ((msg->nm_nlh->nlmsg_flags & NLM_F_MULTI) &&
171ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker							(msg->nm_nlh->nlmsg_type & NLMSG_DONE))
172ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
173ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
174ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						break;
175ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
176ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					case NL_CB_ACK:
177ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						if (msg->nm_nlh->nlmsg_flags & NLM_F_ACK)
178ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
179ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
180ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						break;
181ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					default:
182ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker						break;
183ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker					}
184ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				}
185ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			}
186ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
187ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			free(msg);
188ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			if (done)
189ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker				break;
190ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		}
191ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		free(buf);
192ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		buf = NULL;
193ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
194ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		if (done)
195ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker			break;
196ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	} while (rc > 0 && cb_rc != NL_STOP);
197ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
198ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makersuccess:
199ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerfail:
200d99fe5ec960b5eae96585d5ceb59fe287fe0c5e7Dmitry Shmidt	return rc;
201ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
202ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
203ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Send raw data over netlink socket */
204ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_send(struct nl_sock *sk, struct nl_msg *msg)
205ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
206ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct nlmsghdr *nlh = nlmsg_hdr(msg);
207ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct iovec msg_iov;
208ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
209ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Create IO vector with Netlink message */
210ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg_iov.iov_base = nlh;
211ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	msg_iov.iov_len = nlh->nlmsg_len;
212ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
213ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return nl_send_iovec(sk, msg, &msg_iov, 1);
214ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
215ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
216ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Send netlink message */
217ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg,
218ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		   struct iovec *iov, unsigned iovlen)
219ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
220ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int rc;
221ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
222ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Socket message */
223ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct msghdr mh = {
224ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		.msg_name = (void *) &sk->s_peer,
225ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		.msg_namelen = sizeof(sk->s_peer),
226ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		.msg_iov = iov,
227ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		.msg_iovlen = iovlen,
228ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		.msg_control = NULL,
229ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		.msg_controllen = 0,
230ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		.msg_flags = 0
231ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	};
232ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
233ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Send message and verify sent */
234ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	rc = nl_sendmsg(sk, (struct nl_msg *) &mh, 0);
235ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (rc < 0)
236ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		fprintf(stderr, "Error sending netlink message: %d\n", errno);
237ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return rc;
238ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
239ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
240ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
241ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Send netlink message with control over sendmsg() message header */
242ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
243ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
244ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return sendmsg(sk->s_fd, (struct msghdr *) msg, (int) hdr);
245ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
246ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
247ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker/* Create and connect netlink socket */
248ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Makerint nl_connect(struct nl_sock *sk, int protocol)
249ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker{
250ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	struct sockaddr addr;
251ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	socklen_t addrlen;
252ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	int rc;
253ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
254ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Create RX socket */
255ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	sk->s_fd = socket(PF_NETLINK, SOCK_RAW, protocol);
256ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (sk->s_fd < 0)
257ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		return -errno;
258ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
259ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Set size of RX and TX buffers */
260ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (nl_socket_set_buffer_size(sk, NL_BUFFER_SZ, NL_BUFFER_SZ) < 0)
261ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		return -errno;
262ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
263ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	/* Bind RX socket */
264ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	rc = bind(sk->s_fd, (struct sockaddr *)&sk->s_local, \
265ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		sizeof(sk->s_local));
266ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	if (rc < 0)
267ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker		return -errno;
268ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	addrlen = sizeof(addr);
269ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	getsockname(sk->s_fd, &addr, &addrlen);
270ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
271ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker	return 0;
272ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker
273ed6b39cc7746fabdd0d01c96afcf60b9544913d3Frank Maker}
274