Cleanroom libnl_2 library

By overriding the netlink cache pointer, able to pass nl80211 family id.
Scan and connecting open access point work
Added legal stuff to headers

Change-Id: I1c60452f35fdd1f80edebc03fef33067722d0543
diff --git a/libnl_2/netlink.c b/libnl_2/netlink.c
new file mode 100644
index 0000000..cc2f88e
--- /dev/null
+++ b/libnl_2/netlink.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* NOTICE: This is a clean room re-implementation of libnl */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include "netlink-types.h"
+
+#define NL_BUFFER_SZ (32768U)
+
+/* Checks message for completeness and sends it out */
+int nl_send_auto_complete(struct nl_sock *sk, struct nl_msg *msg)
+{
+	struct nlmsghdr *nlh = msg->nm_nlh;
+	struct timeval tv;
+
+	if (!nlh) {
+		int errsv = errno;
+		fprintf(stderr, "Netlink message header is NULL!\n");
+		return -errsv;
+	}
+
+	/* Complete the nl_msg header */
+	if (gettimeofday(&tv, NULL))
+		nlh->nlmsg_seq = 1;
+	else
+		nlh->nlmsg_seq = (int) tv.tv_sec;
+	nlh->nlmsg_pid = sk->s_local.nl_pid;
+	nlh->nlmsg_flags |= NLM_F_REQUEST | NLM_F_ACK;
+
+	return nl_send(sk, msg);
+}
+
+/* Receives a netlink message, allocates a buffer in *buf and stores
+ * the message content. The peer's netlink address is stored in
+ * *nla. The caller is responsible for freeing the buffer allocated in
+ * *buf if a positive value is returned. Interrupted system calls are
+ * handled by repeating the read. The input buffer size is determined
+ * by peeking before the actual read is done */
+int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla, \
+	unsigned char **buf, struct ucred **creds)
+{
+	int rc = -1;
+	int sk_flags;
+	int RECV_BUF_SIZE;
+	int errsv;
+	struct iovec recvmsg_iov;
+	struct msghdr msg;
+
+	/* Allocate buffer */
+	RECV_BUF_SIZE = getpagesize();
+	*buf = (unsigned char *) malloc(RECV_BUF_SIZE);
+	if (!buf) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	/* Prepare to receive message */
+	recvmsg_iov.iov_base = *buf;
+	recvmsg_iov.iov_len = RECV_BUF_SIZE;
+
+	msg.msg_name = (void *) &sk->s_peer;
+	msg.msg_namelen = sizeof(sk->s_peer);
+	msg.msg_iov = &recvmsg_iov;
+	msg.msg_iovlen = 1;
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = 0;
+
+	/* Make non blocking and then restore previous setting */
+	sk_flags = fcntl(sk->s_fd, F_GETFL, 0);
+	fcntl(sk->s_fd, F_SETFL, O_NONBLOCK);
+	rc = recvmsg(sk->s_fd, &msg, 0);
+	errsv = errno;
+	fcntl(sk->s_fd, F_SETFL, sk_flags);
+
+	if (rc < 0)
+		rc = -errsv;
+
+fail:
+	return rc;
+}
+
+/* Receive a set of messages from a netlink socket */
+/* NOTE: Does not currently support callback replacements!!! */
+int nl_recvmsgs(struct nl_sock *sk, struct nl_cb *cb)
+{
+	struct sockaddr_nl nla;
+	struct ucred *creds;
+
+	int rc, cb_rc = NL_OK, done = 0;
+
+	do {
+
+		unsigned char *buf;
+		int i, rem, flags;
+		struct nlmsghdr *nlh;
+		struct nlmsgerr *nlme;
+		struct nl_msg *msg;
+
+		done = 0;
+		rc = nl_recv(sk, &nla, &buf, &creds);
+		if (rc < 0)
+			break;
+
+		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) buf, rc, rem) {
+
+			if (rc <= 0 || cb_rc == NL_STOP)
+				break;
+
+			/* Check for callbacks */
+
+			msg = (struct nl_msg *)malloc(sizeof(struct nl_msg));
+			memset(msg, 0, sizeof(*msg));
+			msg->nm_nlh = nlh;
+
+			/* Check netlink message type */
+
+			switch (msg->nm_nlh->nlmsg_type) {
+			case NLMSG_ERROR:	  /* Used for ACK too */
+				/* Certainly we should be doing some
+				 * checking here to make sure this
+				 * message is intended for us */
+				nlme = nlmsg_data(msg->nm_nlh);
+				if (nlme->error == 0)
+					msg->nm_nlh->nlmsg_flags |= NLM_F_ACK;
+
+				rc = nlme->error;
+				cb_rc = cb->cb_err(&nla, nlme, cb->cb_err_arg);
+				nlme = NULL;
+				break;
+
+			case NLMSG_DONE:
+				done = 1;
+
+			case NLMSG_OVERRUN:
+			case NLMSG_NOOP:
+			default:
+				break;
+			};
+
+			for (i = 0; i <= NL_CB_TYPE_MAX; i++) {
+
+				if (cb->cb_set[i]) {
+					switch (i) {
+					case NL_CB_VALID:
+						if (rc > 0)
+							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
+						break;
+
+					case NL_CB_FINISH:
+						if ((msg->nm_nlh->nlmsg_flags & NLM_F_MULTI) &&
+							(msg->nm_nlh->nlmsg_type & NLMSG_DONE))
+							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
+
+						break;
+
+					case NL_CB_ACK:
+						if (msg->nm_nlh->nlmsg_flags & NLM_F_ACK)
+							cb_rc = cb->cb_set[i](msg, cb->cb_args[i]);
+
+						break;
+					default:
+						break;
+					}
+				}
+			}
+
+			free(msg);
+			if (done)
+				break;
+		}
+
+		free(buf);
+		buf = NULL;
+
+		if (done)
+			break;
+	} while (rc > 0 && cb_rc != NL_STOP);
+
+success:
+fail:
+	return	rc;
+}
+
+/* Send raw data over netlink socket */
+int nl_send(struct nl_sock *sk, struct nl_msg *msg)
+{
+	struct nlmsghdr *nlh = nlmsg_hdr(msg);
+	struct iovec msg_iov;
+
+	/* Create IO vector with Netlink message */
+	msg_iov.iov_base = nlh;
+	msg_iov.iov_len = nlh->nlmsg_len;
+
+	return nl_send_iovec(sk, msg, &msg_iov, 1);
+}
+
+/* Send netlink message */
+int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg,
+		   struct iovec *iov, unsigned iovlen)
+{
+	int rc;
+
+	/* Socket message */
+	struct msghdr mh = {
+		.msg_name = (void *) &sk->s_peer,
+		.msg_namelen = sizeof(sk->s_peer),
+		.msg_iov = iov,
+		.msg_iovlen = iovlen,
+		.msg_control = NULL,
+		.msg_controllen = 0,
+		.msg_flags = 0
+	};
+
+	/* Send message and verify sent */
+	rc = nl_sendmsg(sk, (struct nl_msg *) &mh, 0);
+	if (rc < 0)
+		fprintf(stderr, "Error sending netlink message: %d\n", errno);
+	return rc;
+
+}
+
+/* Send netlink message with control over sendmsg() message header */
+int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
+{
+	return sendmsg(sk->s_fd, (struct msghdr *) msg, (int) hdr);
+}
+
+/* Create and connect netlink socket */
+int nl_connect(struct nl_sock *sk, int protocol)
+{
+	struct sockaddr addr;
+	socklen_t addrlen;
+	int rc;
+
+	/* Create RX socket */
+	sk->s_fd = socket(PF_NETLINK, SOCK_RAW, protocol);
+	if (sk->s_fd < 0)
+		return -errno;
+
+	/* Set size of RX and TX buffers */
+	if (nl_socket_set_buffer_size(sk, NL_BUFFER_SZ, NL_BUFFER_SZ) < 0)
+		return -errno;
+
+	/* Bind RX socket */
+	rc = bind(sk->s_fd, (struct sockaddr *)&sk->s_local, \
+		sizeof(sk->s_local));
+	if (rc < 0)
+		return -errno;
+	addrlen = sizeof(addr);
+	getsockname(sk->s_fd, &addr, &addrlen);
+
+	return 0;
+
+}