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