• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
nl_send_auto_complete(struct nl_sock * sk,struct nl_msg * msg)29 int 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 */
nl_recv(struct nl_sock * sk,struct sockaddr_nl * nla,unsigned char ** buf,struct ucred ** creds)57 int 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 
97 fail:
98 	return rc;
99 }
100 
101 /* Receive a set of messages from a netlink socket */
102 /* NOTE: Does not currently support callback replacements!!! */
nl_recvmsgs(struct nl_sock * sk,struct nl_cb * cb)103 int 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 
198 success:
199 fail:
200 	return	rc;
201 }
202 
203 /* Send raw data over netlink socket */
nl_send(struct nl_sock * sk,struct nl_msg * msg)204 int 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 */
nl_send_iovec(struct nl_sock * sk,struct nl_msg * msg,struct iovec * iov,unsigned iovlen)217 int 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 */
nl_sendmsg(struct nl_sock * sk,struct nl_msg * msg,struct msghdr * hdr)242 int 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 */
nl_connect(struct nl_sock * sk,int protocol)248 int 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