DO NOT MERGE: Revert "delete libnl_2"

This reverts commit 7097f052d946bc9fbe298c7a88e1d943f54f684e.

libnl_2 needs to stay in AOSP for now for compatibility with
GPL test builds.
diff --git a/libnl_2/.gitignore b/libnl_2/.gitignore
new file mode 100644
index 0000000..d4ca744
--- /dev/null
+++ b/libnl_2/.gitignore
@@ -0,0 +1,2 @@
+include/netlink/version.h.in
+cscope.*
diff --git a/libnl_2/Android.mk b/libnl_2/Android.mk
new file mode 100644
index 0000000..3721fc6
--- /dev/null
+++ b/libnl_2/Android.mk
@@ -0,0 +1,39 @@
+#######################################
+# * Netlink cache not implemented
+# * Library is not thread safe
+#######################################
+
+LOCAL_PATH := $(call my-dir)
+
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+        attr.c \
+        cache.c \
+        genl/genl.c \
+        genl/family.c \
+        handlers.c \
+        msg.c \
+        netlink.c \
+        object.c \
+        socket.c \
+        dbg.c
+
+LOCAL_C_INCLUDES += \
+        external/libnl-headers
+
+# Static Library
+LOCAL_MODULE := libnl_2
+LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES :=
+LOCAL_WHOLE_STATIC_LIBRARIES:= libnl_2
+LOCAL_SHARED_LIBRARIES:= liblog
+LOCAL_MODULE := libnl_2
+LOCAL_MODULE_TAGS := optional
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libnl_2/README b/libnl_2/README
new file mode 100644
index 0000000..14db6db
--- /dev/null
+++ b/libnl_2/README
@@ -0,0 +1,88 @@
+Netlink Protocol Library
+
+This library is a clean room re-implementation of libnl 2.0 and
+re-licensed under Apache 2.0. It was developed primarily to support
+wpa_supplicant. However, with additional development can be extended
+to support other netlink applications.
+
+Netlink Protocol Format (RFC3549)
+
++-----------------+-+-------------------+-+
+|Netlink Message  |P| Generic Netlink   |P|
+|    Header       |A|  Message Header   |A|
+|(struct nlmsghdr)|D|(struct genlmsghdr)|D|
++-----------------+-+-------------------+-+-------------+
+|len:4|type:2|flags:2|seq:4 pid:4|cmd:1|ver:1|reserved:2|
++--------------------------------+----------------------+
++-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
+|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|Netlink Attribute|P|...|
+|    #0 Header    |A|   #0 Payload    |A|   #1 Header     |A|   #1 Payload    |A|   |
+| (struct nlattr) |D|     (void)      |D| (struct nlattr) |D|     (void)      |D|   |
++-----------------+-+-----------------+-+-----------------+-+-----------------+-+---+
+|len:2(==4+payload)|type:2|payload|pad|
++-------------------------+-------+---+
+
+NETLINK OVERVIEW
+
+* Each netlink message consists of a bitstream with a netlink header.
+* After this header a second header *can* be used specific to the netlink
+  family in use. This library was tested using the generic netlink
+  protocol defined by struct genlmsghdr to support nl80211.
+* After the header(s) netlink attributes can be appended to the message
+  which hold can hold basic types such as unsigned integers and strings.
+* Attributes can also be nested. This is accomplished by calling "nla_nest_start"
+  which creates an empty attribute with nest attributes as its payload. Then to
+  close the nest, "nla_nest_end" is called.
+* All data structures in this implementation are byte-aligned (Currently 4 bytes).
+* Acknowledgements (ACKs) are sent as NLMSG_ERROR netlink message types (0x2) and
+  have an error value of 0.
+
+KNOWN ISSUES
+
+  GENERAL
+  * Not tested for thread safety
+
+  Android.mk
+  * No dynamic library because of netlink cache not implemented and
+    not tested for thread safety
+
+  attr.c
+  * nla_parse - does not use nla_policy argument
+
+  cache.c
+  * netlink cache not implemented and only supports one netlink family id
+    which is stored in the nl_cache pointer instead of an actual cache
+
+  netlink.c
+  * nl_recvmsgs - does not support nl_cb_overwrite_recv()
+  * nl_recv - sets/unsets asynchronous socket flag
+
+SOURCE FILES
+
+* Android.mk - Android makefile
+* README - This file
+* attr.c - Netlink attributes
+* cache.c - Netlink cache
+* genl/family.c - Generic netlink family id
+* genl/genl.c - Generic netlink
+* handlers.c - Netlink callbacks
+* msg.c - Netlink messages construction
+* netlink.c - Netlink socket communication
+* object.c - libnl object wrapper
+* socket.c - Netlink kernel socket utils
+
+IMPORTANT HEADER FILES - NOTE: These are based on the the origin GPL libnl headers
+
+* netlink-types.h - Contains many important structs for libnl
+  to represent netlink objects
+* netlink/netlink-kernel.h - Netlink kernel headers and field constants.
+* netlink/msg.h - macros for iterating over netlink messages
+* netlink/attr.h - netlink attribute constants, iteration macros and setters
+
+REFERENCES
+
+* nl80211.h
+* netlink_types.h
+* $LINUX_KERNEL/net/wireless/nl80211.c
+* http://www.infradead.org/~tgr/libnl/doc-3.0/index.html
+* http://www.netfilter.org/projects/libmnl/doxygen/index.html
diff --git a/libnl_2/attr.c b/libnl_2/attr.c
new file mode 100644
index 0000000..2ef7590
--- /dev/null
+++ b/libnl_2/attr.c
@@ -0,0 +1,239 @@
+/*
+ * 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 "netlink/netlink.h"
+#include "netlink/msg.h"
+#include "netlink/attr.h"
+#include "netlink-types.h"
+
+/* Return payload of string attribute. */
+char *nla_get_string(struct nlattr *nla)
+{
+	return (char *) nla_data(nla);
+}
+
+/* Return payload of 16 bit integer attribute. */
+uint16_t nla_get_u16(struct nlattr *nla)
+{
+	return *((uint16_t *) nla_data(nla));
+}
+
+/* Return payload of 32 bit integer attribute. */
+uint32_t nla_get_u32(struct nlattr *nla)
+{
+	return *((uint32_t *) nla_data(nla));
+}
+
+/* Return value of 8 bit integer attribute. */
+uint8_t nla_get_u8(struct nlattr *nla)
+{
+	return *((uint8_t *) nla_data(nla));
+}
+
+/* Return payload of uint64_t attribute. */
+uint64_t nla_get_u64(struct nlattr *nla)
+{
+	uint64_t tmp;
+	nla_memcpy(&tmp, nla, sizeof(tmp));
+	return tmp;
+}
+
+/* Head of payload */
+void *nla_data(const struct nlattr *nla)
+{
+	return (void *) ((char *) nla + NLA_HDRLEN);
+}
+
+/* Return length of the payload . */
+int nla_len(const struct nlattr *nla)
+{
+	return nla->nla_len - NLA_HDRLEN;
+}
+
+int nla_padlen(int payload)
+{
+	return NLA_ALIGN(payload) - payload;
+}
+
+/* Start a new level of nested attributes. */
+struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
+{
+	struct nlattr *start = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
+	int rc;
+
+	rc = nla_put(msg, attrtype, 0, NULL);
+	if (rc < 0)
+		return NULL;
+
+	return start;
+}
+
+/* Finalize nesting of attributes. */
+int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
+{
+	/* Set attribute size */
+	start->nla_len = (unsigned char *)nlmsg_tail(nlmsg_hdr(msg)) -
+				(unsigned char *)start;
+	return 0;
+}
+
+/* Return next attribute in a stream of attributes. */
+struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
+{
+	struct nlattr *next_nla = NULL;
+	if (nla->nla_len >= sizeof(struct nlattr) &&
+	   nla->nla_len <= *remaining){
+		next_nla = (struct nlattr *) \
+			((char *) nla + NLA_ALIGN(nla->nla_len));
+		*remaining = *remaining - NLA_ALIGN(nla->nla_len);
+	}
+
+	return next_nla;
+
+}
+
+/* Check if the attribute header and payload can be accessed safely. */
+int nla_ok(const struct nlattr *nla, int remaining)
+{
+	return remaining > 0 &&
+		nla->nla_len >= sizeof(struct nlattr) &&
+		sizeof(struct nlattr) <= (unsigned int) remaining &&
+		nla->nla_len <= remaining;
+}
+
+/* Create attribute index based on a stream of attributes. */
+/* NOTE: Policy not used ! */
+int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head,
+	int len, struct nla_policy *policy)
+{
+	struct nlattr *pos;
+	int rem;
+
+	/* First clear table */
+	memset(tb, 0, (maxtype + 1) * sizeof(struct nlattr *));
+
+	nla_for_each_attr(pos, head, len, rem) {
+		int type = nla_type(pos);
+
+		if ((type <= maxtype) && (type != 0))
+			tb[type] = pos;
+	}
+
+	return 0;
+}
+
+
+/* Create attribute index based on nested attribute. */
+int nla_parse_nested(struct nlattr *tb[], int maxtype,
+		struct nlattr *nla, struct nla_policy *policy)
+{
+	return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
+}
+
+
+/* Add a unspecific attribute to netlink message. */
+int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
+{
+	struct nlattr *nla;
+
+	/* Reserve space and init nla header */
+	nla = nla_reserve(msg, attrtype, datalen);
+	if (nla) {
+		memcpy(nla_data(nla), data, datalen);
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/* Add 8 bit integer attribute to netlink message. */
+int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint8_t), &value);
+}
+
+/* Add 16 bit integer attribute to netlink message. */
+int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint16_t), &value);
+}
+
+/* Add 32 bit integer attribute to netlink message. */
+int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint32_t), &value);
+}
+
+/* Add 64 bit integer attribute to netlink message. */
+int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
+{
+	return nla_put(msg, attrtype, sizeof(uint64_t), &value);
+}
+
+/* Add nested attributes to netlink message. */
+/* Takes the attributes found in the nested message and appends them
+ * to the message msg nested in a container of the type attrtype. The
+ * nested message may not have a family specific header */
+int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
+{
+	int rc;
+
+	rc = nla_put(msg, attrtype, nlmsg_attrlen(nlmsg_hdr(nested), 0),
+			nlmsg_attrdata(nlmsg_hdr(nested), 0));
+	return rc;
+
+}
+
+/* Return type of the attribute. */
+int nla_type(const struct nlattr *nla)
+{
+	return (int)nla->nla_type & NLA_TYPE_MASK;
+}
+
+/* Reserves room for an attribute in specified netlink message and fills
+ * in the attribute header (type,length). Return NULL if insufficient space */
+struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int data_len)
+{
+
+	struct nlattr *nla;
+	const unsigned int NEW_SIZE = NLMSG_ALIGN(msg->nm_nlh->nlmsg_len) +
+					NLA_ALIGN(NLA_HDRLEN + data_len);
+
+	/* Check enough space for attribute */
+	if (NEW_SIZE > msg->nm_size)
+		return NULL;
+
+	nla = (struct nlattr *)nlmsg_tail(msg->nm_nlh);
+	nla->nla_type = attrtype;
+	nla->nla_len = NLA_HDRLEN + data_len;
+	memset((unsigned char *)nla + nla->nla_len, 0, nla_padlen(data_len));
+	msg->nm_nlh->nlmsg_len = NEW_SIZE;
+	return nla;
+}
+
+/* Copy attribute payload to another memory area. */
+int nla_memcpy(void *dest, struct nlattr *src, int count)
+{
+	if (!src || !dest)
+		return 0;
+	if (count > nla_len(src))
+		count = nla_len(src);
+	memcpy(dest, nla_data(src), count);
+	return count;
+}
diff --git a/libnl_2/cache.c b/libnl_2/cache.c
new file mode 100644
index 0000000..c21974d
--- /dev/null
+++ b/libnl_2/cache.c
@@ -0,0 +1,37 @@
+/*
+ * 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 "netlink/cache.h"
+#include "netlink/object.h"
+
+void nl_cache_free(struct nl_cache *cache)
+{
+
+}
+
+void nl_cache_clear(struct nl_cache *cache)
+{
+
+}
+
+void nl_cache_remove(struct nl_object *obj)
+{
+
+}
+
+
diff --git a/libnl_2/dbg.c b/libnl_2/dbg.c
new file mode 100644
index 0000000..9764de6
--- /dev/null
+++ b/libnl_2/dbg.c
@@ -0,0 +1,12 @@
+#include "netlink/netlink.h"
+#include <android/log.h>
+
+void libnl_printf(int level, char *format, ...)
+{
+	va_list ap;
+
+	level = ANDROID_LOG_ERROR;
+	va_start(ap, format);
+	__android_log_vprint(level, "libnl_2", format, ap);
+	va_end(ap);
+}
diff --git a/libnl_2/genl/family.c b/libnl_2/genl/family.c
new file mode 100644
index 0000000..1beee6e
--- /dev/null
+++ b/libnl_2/genl/family.c
@@ -0,0 +1,44 @@
+/*
+ * 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 "netlink-types.h"
+
+static struct genl_family *genl_family_find_byname(const char *name)
+{
+	return NULL;
+}
+
+/* Release reference and none outstanding  */
+void genl_family_put(struct genl_family *family)
+{
+	family->ce_refcnt--;
+	if (family->ce_refcnt <= 0)
+		free(family);
+}
+
+unsigned int genl_family_get_id(struct genl_family *family)
+{
+	const int NO_FAMILY_ID = 0;
+
+	if (!family)
+		return NO_FAMILY_ID;
+	else
+		return family->gf_id;
+
+}
+
diff --git a/libnl_2/genl/genl.c b/libnl_2/genl/genl.c
new file mode 100644
index 0000000..1a39c6a
--- /dev/null
+++ b/libnl_2/genl/genl.c
@@ -0,0 +1,302 @@
+/*
+ * 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 <unistd.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/genl/family.h>
+#include "netlink-types.h"
+
+/* Get head of attribute data. */
+struct nlattr *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen)
+{
+	return (struct nlattr *) \
+		((char *) gnlh + GENL_HDRLEN + NLMSG_ALIGN(hdrlen));
+
+}
+
+/* Get length of attribute data. */
+int genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen)
+{
+	struct nlattr *nla;
+	struct nlmsghdr *nlh;
+
+	nla = genlmsg_attrdata(gnlh, hdrlen);
+	nlh = (struct nlmsghdr *) ((char *) gnlh - NLMSG_HDRLEN);
+	return (char *) nlmsg_tail(nlh) - (char *) nla;
+}
+
+/* Add generic netlink header to netlink message. */
+void *genlmsg_put(struct nl_msg *msg, uint32_t pid, uint32_t seq, int family,
+		int hdrlen, int flags, uint8_t cmd, uint8_t version)
+{
+	int new_size;
+	struct nlmsghdr *nlh;
+	struct timeval tv;
+	struct genlmsghdr *gmh;
+
+	/* Make sure nl_msg has enough space */
+	new_size = NLMSG_HDRLEN + GENL_HDRLEN + hdrlen;
+	if ((sizeof(struct nl_msg) + new_size) > msg->nm_size)
+		goto fail;
+
+	/* Fill in netlink header */
+	nlh = msg->nm_nlh;
+	nlh->nlmsg_len = new_size;
+	nlh->nlmsg_type = family;
+	nlh->nlmsg_pid = getpid();
+	nlh->nlmsg_flags = flags | NLM_F_REQUEST | NLM_F_ACK;
+
+	/* Get current time for sequence number */
+	if (gettimeofday(&tv, NULL))
+		nlh->nlmsg_seq = 1;
+	else
+		nlh->nlmsg_seq = (int) tv.tv_sec;
+
+	/* Setup genlmsghdr in new message */
+	gmh = (struct genlmsghdr *) ((char *)nlh + NLMSG_HDRLEN);
+	gmh->cmd = (__u8) cmd;
+	gmh->version = version;
+
+	return gmh;
+fail:
+	return NULL;
+
+}
+
+/* Socket has already been alloced to connect it to kernel? */
+int genl_connect(struct nl_sock *sk)
+{
+	return nl_connect(sk, NETLINK_GENERIC);
+
+}
+
+int genl_ctrl_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
+{
+	int rc = -1;
+	int nl80211_genl_id = -1;
+	char sendbuf[sizeof(struct nlmsghdr)+sizeof(struct genlmsghdr)];
+	struct nlmsghdr nlmhdr;
+	struct genlmsghdr gmhhdr;
+	struct iovec sendmsg_iov;
+	struct msghdr msg;
+	int num_char;
+	const int RECV_BUF_SIZE = getpagesize();
+	char *recvbuf;
+	struct iovec recvmsg_iov;
+	int nl80211_flag = 0, nlm_f_multi = 0, nlmsg_done = 0;
+	struct nlmsghdr *nlh;
+
+	/* REQUEST GENERIC NETLINK FAMILY ID */
+	/* Message buffer */
+	nlmhdr.nlmsg_len = sizeof(sendbuf);
+	nlmhdr.nlmsg_type = NETLINK_GENERIC;
+	nlmhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
+	nlmhdr.nlmsg_seq = sock->s_seq_next;
+	nlmhdr.nlmsg_pid = sock->s_local.nl_pid;
+
+	/* Generic netlink header */
+	memset(&gmhhdr, 0, sizeof(gmhhdr));
+	gmhhdr.cmd = CTRL_CMD_GETFAMILY;
+	gmhhdr.version = CTRL_ATTR_FAMILY_ID;
+
+	/* Combine netlink and generic netlink headers */
+	memcpy(&sendbuf[0], &nlmhdr, sizeof(nlmhdr));
+	memcpy(&sendbuf[0]+sizeof(nlmhdr), &gmhhdr, sizeof(gmhhdr));
+
+	/* Create IO vector with Netlink message */
+	sendmsg_iov.iov_base = &sendbuf;
+	sendmsg_iov.iov_len = sizeof(sendbuf);
+
+	/* Socket message */
+	msg.msg_name = (void *) &sock->s_peer;
+	msg.msg_namelen = sizeof(sock->s_peer);
+	msg.msg_iov = &sendmsg_iov;
+	msg.msg_iovlen = 1; /* Only sending one iov */
+	msg.msg_control = NULL;
+	msg.msg_controllen = 0;
+	msg.msg_flags = 0;
+
+	/* Send message and verify sent */
+	num_char = sendmsg(sock->s_fd, &msg, 0);
+	if (num_char == -1)
+		return -errno;
+
+	/* RECEIVE GENL CMD RESPONSE */
+
+	/* Create receive iov buffer */
+	recvbuf = (char *) malloc(RECV_BUF_SIZE);
+
+	/* Attach to iov */
+	recvmsg_iov.iov_base = recvbuf;
+	recvmsg_iov.iov_len = RECV_BUF_SIZE;
+
+	msg.msg_iov = &recvmsg_iov;
+	msg.msg_iovlen = 1;
+
+	/***************************************************************/
+	/* Receive message. If multipart message, keep receiving until */
+	/* message type is NLMSG_DONE				       */
+	/***************************************************************/
+
+	do {
+
+		int recvmsg_len, nlmsg_rem;
+
+		/* Receive message */
+		memset(recvbuf, 0, RECV_BUF_SIZE);
+		recvmsg_len = recvmsg(sock->s_fd, &msg, 0);
+
+		/* Make sure receive successful */
+		if (recvmsg_len < 0) {
+			rc = -errno;
+			goto error_recvbuf;
+		}
+
+		/* Parse nlmsghdr */
+		nlmsg_for_each_msg(nlh, (struct nlmsghdr *) recvbuf, \
+				recvmsg_len, nlmsg_rem) {
+			struct nlattr *nla;
+			int nla_rem;
+
+			/* Check type */
+			switch (nlh->nlmsg_type) {
+			case NLMSG_DONE:
+				goto return_genl_id;
+				break;
+			case NLMSG_ERROR:
+
+				/* Should check nlmsgerr struct received */
+				fprintf(stderr, "Receive message error\n");
+				goto error_recvbuf;
+			case NLMSG_OVERRUN:
+				fprintf(stderr, "Receive data partly lost\n");
+				goto error_recvbuf;
+			case NLMSG_MIN_TYPE:
+			case NLMSG_NOOP:
+				break;
+			default:
+				break;
+			}
+
+
+
+			/* Check flags */
+			if (nlh->nlmsg_flags & NLM_F_MULTI)
+				nlm_f_multi = 1;
+			else
+				nlm_f_multi = 0;
+
+			if (nlh->nlmsg_type & NLMSG_DONE)
+				nlmsg_done = 1;
+			else
+				nlmsg_done = 0;
+
+			/* Iteratve over attributes */
+			nla_for_each_attr(nla,
+					nlmsg_attrdata(nlh, GENL_HDRLEN),
+					nlmsg_attrlen(nlh, GENL_HDRLEN),
+					nla_rem){
+
+				/* If this family is nl80211 */
+				if (nla->nla_type == CTRL_ATTR_FAMILY_NAME &&
+					!strcmp((char *)nla_data(nla),
+						"nl80211"))
+					nl80211_flag = 1;
+
+				/* Save the family id */
+				else if (nl80211_flag &&
+					nla->nla_type == CTRL_ATTR_FAMILY_ID) {
+					nl80211_genl_id =
+						*((int *)nla_data(nla));
+					nl80211_flag = 0;
+				}
+
+			}
+
+		}
+
+	} while (nlm_f_multi && !nlmsg_done);
+
+return_genl_id:
+	/* Return family id as cache pointer */
+	*result = (struct nl_cache *) nl80211_genl_id;
+	rc = 0;
+error_recvbuf:
+	free(recvbuf);
+error:
+	return rc;
+}
+
+/* Checks the netlink cache to find family reference by name string */
+/* NOTE: Caller needs to call genl_family_put() when done with *
+ * returned object */
+struct genl_family *genl_ctrl_search_by_name(struct nl_cache *cache, \
+					const char *name)
+{
+	struct genl_family *gf = (struct genl_family *) \
+		malloc(sizeof(struct genl_family));
+	if (!gf)
+		goto fail;
+	memset(gf, 0, sizeof(*gf));
+
+	/* Add ref */
+	gf->ce_refcnt++;
+
+	/* Overriding cache pointer as family id for now */
+	gf->gf_id = (uint16_t) ((uint32_t) cache);
+	strncpy(gf->gf_name, name, GENL_NAMSIZ);
+
+	return gf;
+fail:
+	return NULL;
+
+}
+
+int genl_ctrl_resolve(struct nl_sock *sk, const char *name)
+{
+	struct nl_cache *cache = NULL;
+	struct genl_family *gf = NULL;
+	int id = -1;
+
+	/* Hack to support wpa_supplicant */
+	if (strcmp(name, "nlctrl") == 0)
+		return NETLINK_GENERIC;
+
+	if (strcmp(name, "nl80211") != 0) {
+		fprintf(stderr, "%s is not supported\n", name);
+		return id;
+	}
+
+	if (!genl_ctrl_alloc_cache(sk, &cache)) {
+		gf = genl_ctrl_search_by_name(cache, name);
+		if (gf)
+			id = genl_family_get_id(gf);
+	}
+
+	if (gf)
+		genl_family_put(gf);
+	if (cache)
+		nl_cache_free(cache);
+
+	return id;
+}
diff --git a/libnl_2/handlers.c b/libnl_2/handlers.c
new file mode 100644
index 0000000..48dcab4
--- /dev/null
+++ b/libnl_2/handlers.c
@@ -0,0 +1,90 @@
+/*
+ * 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 <malloc.h>
+#include "netlink-types.h"
+#include "netlink/handlers.h"
+
+/* Allocate a new callback handle. */
+struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
+{
+	struct nl_cb *cb;
+
+	cb = (struct nl_cb *) malloc(sizeof(struct nl_cb));
+	if (cb == NULL)
+		goto fail;
+	memset(cb, 0, sizeof(*cb));
+
+	return nl_cb_get(cb);
+fail:
+	return NULL;
+}
+
+/* Clone an existing callback handle */
+struct nl_cb *nl_cb_clone(struct nl_cb *orig)
+{
+	struct nl_cb *new_cb;
+
+	new_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (new_cb == NULL)
+		goto fail;
+
+	/* Copy original and set refcount to 1 */
+	memcpy(new_cb, orig, sizeof(*orig));
+	new_cb->cb_refcnt = 1;
+
+	return new_cb;
+fail:
+	return NULL;
+}
+
+/* Set up a callback. */
+int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, \
+	nl_recvmsg_msg_cb_t func, void *arg)
+{
+	cb->cb_set[type] = func;
+	cb->cb_args[type] = arg;
+	return 0;
+}
+
+
+
+/* Set up an error callback. */
+int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, \
+	nl_recvmsg_err_cb_t func, void *arg)
+{
+	cb->cb_err = func;
+	cb->cb_err_arg = arg;
+	return 0;
+
+}
+
+struct nl_cb *nl_cb_get(struct nl_cb *cb)
+{
+	cb->cb_refcnt++;
+	return cb;
+}
+
+void nl_cb_put(struct nl_cb *cb)
+{
+	if (!cb)
+		return;
+	cb->cb_refcnt--;
+	if (cb->cb_refcnt <= 0)
+		free(cb);
+}
diff --git a/libnl_2/msg.c b/libnl_2/msg.c
new file mode 100644
index 0000000..1303e8a
--- /dev/null
+++ b/libnl_2/msg.c
@@ -0,0 +1,150 @@
+/*
+ * 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 <malloc.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include "netlink-types.h"
+
+/* Allocate a new netlink message with the default maximum payload size. */
+struct nl_msg *nlmsg_alloc(void)
+{
+	/* Whole page will store nl_msg + nlmsghdr + genlmsghdr + payload */
+	const int page_sz = getpagesize();
+	struct nl_msg *nm;
+	struct nlmsghdr *nlh;
+
+	/* Netlink message */
+	nm = (struct nl_msg *) malloc(page_sz);
+	if (!nm)
+		goto fail;
+
+	/* Netlink message header pointer */
+	nlh = (struct nlmsghdr *) ((char *) nm + sizeof(struct nl_msg));
+
+	/* Initialize */
+	memset(nm, 0, page_sz);
+	nm->nm_size = page_sz;
+
+	nm->nm_src.nl_family = AF_NETLINK;
+	nm->nm_src.nl_pid = getpid();
+
+	nm->nm_dst.nl_family = AF_NETLINK;
+	nm->nm_dst.nl_pid = 0; /* Kernel */
+
+	/* Initialize and add to netlink message */
+	nlh->nlmsg_len = NLMSG_HDRLEN;
+	nm->nm_nlh = nlh;
+
+	/* Add to reference count and return nl_msg */
+	nlmsg_get(nm);
+	return nm;
+fail:
+	return NULL;
+}
+
+/* Return pointer to message payload. */
+void *nlmsg_data(const struct nlmsghdr *nlh)
+{
+	return (char *) nlh + NLMSG_HDRLEN;
+}
+
+/* Add reference count to nl_msg */
+void nlmsg_get(struct nl_msg *nm)
+{
+	nm->nm_refcnt++;
+}
+
+/* Release a reference from an netlink message. */
+void nlmsg_free(struct nl_msg *nm)
+{
+	if (nm) {
+		nm->nm_refcnt--;
+		if (nm->nm_refcnt <= 0)
+			free(nm);
+	}
+
+}
+
+/* Return actual netlink message. */
+struct nlmsghdr *nlmsg_hdr(struct nl_msg *n)
+{
+	return n->nm_nlh;
+}
+
+/* Return head of attributes data / payload section */
+struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, int hdrlen)
+{
+	unsigned char *data = nlmsg_data(nlh);
+	return (struct nlattr *)(data + NLMSG_ALIGN(hdrlen));
+}
+
+/* Returns pointer to end of netlink message */
+void *nlmsg_tail(const struct nlmsghdr *nlh)
+{
+	return (void *)((char *)nlh + NLMSG_ALIGN(nlh->nlmsg_len));
+}
+
+/* Next netlink message in message stream */
+struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
+{
+	struct nlmsghdr *next_nlh = NULL;
+	int len = nlmsg_len(nlh);
+
+	len = NLMSG_ALIGN(len);
+	if (*remaining > 0 &&
+	    len <= *remaining &&
+	    len >= (int) sizeof(struct nlmsghdr)) {
+		next_nlh = (struct nlmsghdr *)((char *)nlh + len);
+		*remaining -= len;
+	}
+
+	return next_nlh;
+}
+
+int nlmsg_datalen(const struct nlmsghdr *nlh)
+{
+	return nlh->nlmsg_len - NLMSG_HDRLEN;
+}
+
+/* Length of attributes data */
+int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen)
+{
+	return nlmsg_datalen(nlh) - NLMSG_ALIGN(hdrlen);
+}
+
+/* Length of netlink message */
+int nlmsg_len(const struct nlmsghdr *nlh)
+{
+	return nlh->nlmsg_len;
+}
+
+/* Check if the netlink message fits into the remaining bytes */
+int nlmsg_ok(const struct nlmsghdr *nlh, int rem)
+{
+	return rem >= (int)sizeof(struct nlmsghdr) &&
+		rem >= nlmsg_len(nlh) &&
+		nlmsg_len(nlh) >= (int) sizeof(struct nlmsghdr) &&
+		nlmsg_len(nlh) <= (rem);
+}
+
+int nlmsg_padlen(int payload)
+{
+	return NLMSG_ALIGN(payload) - payload;
+}
diff --git a/libnl_2/netlink.c b/libnl_2/netlink.c
new file mode 100644
index 0000000..ee3d600
--- /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 = getpagesize();
+	int errsv;
+	struct iovec recvmsg_iov;
+	struct msghdr msg;
+
+	/* Allocate buffer */
+	*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;
+		free(*buf);
+		*buf = NULL;
+	}
+
+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;
+
+}
diff --git a/libnl_2/object.c b/libnl_2/object.c
new file mode 100644
index 0000000..c53accf
--- /dev/null
+++ b/libnl_2/object.c
@@ -0,0 +1,33 @@
+/*
+ * 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 "netlink-types.h"
+
+void nl_object_put(struct nl_object *obj)
+{
+	obj->ce_refcnt--;
+	if (!obj->ce_refcnt)
+		nl_object_free(obj);
+}
+
+void nl_object_free(struct nl_object *obj)
+{
+	nl_cache_remove(obj);
+}
+
+
diff --git a/libnl_2/socket.c b/libnl_2/socket.c
new file mode 100644
index 0000000..e94eb9e
--- /dev/null
+++ b/libnl_2/socket.c
@@ -0,0 +1,141 @@
+/*
+ * 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 <unistd.h>
+#include <malloc.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include "netlink-types.h"
+
+/* Join group */
+int nl_socket_add_membership(struct nl_sock *sk, int group)
+{
+	return setsockopt(sk->s_fd, SOL_NETLINK,
+			NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
+}
+
+/* Allocate new netlink socket. */
+static struct nl_sock *_nl_socket_alloc(void)
+{
+	struct nl_sock *sk;
+	struct timeval tv;
+	struct nl_cb *cb;
+
+	sk = (struct nl_sock *) malloc(sizeof(struct nl_sock));
+	if (!sk)
+		return NULL;
+	memset(sk, 0, sizeof(*sk));
+
+	/* Get current time */
+
+	if (gettimeofday(&tv, NULL))
+		goto fail;
+	else
+		sk->s_seq_next = (int) tv.tv_sec;
+
+	/* Create local socket */
+	sk->s_local.nl_family = AF_NETLINK;
+	sk->s_local.nl_pid = 0; /* Kernel fills in pid */
+	sk->s_local.nl_groups = 0; /* No groups */
+
+	/* Create peer socket */
+	sk->s_peer.nl_family = AF_NETLINK;
+	sk->s_peer.nl_pid = 0; /* Kernel */
+	sk->s_peer.nl_groups = 0; /* No groups */
+
+	return sk;
+fail:
+	free(sk);
+	return NULL;
+}
+
+/* Allocate new netlink socket. */
+struct nl_sock *nl_socket_alloc(void)
+{
+	struct nl_sock *sk = _nl_socket_alloc();
+	struct nl_cb *cb;
+
+	if (!sk)
+		return NULL;
+
+	cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!cb)
+		goto cb_fail;
+	sk->s_cb = cb;
+	return sk;
+cb_fail:
+	free(sk);
+	return NULL;
+}
+
+/* Allocate new socket with custom callbacks. */
+struct nl_sock *nl_socket_alloc_cb(struct nl_cb *cb)
+{
+	struct nl_sock *sk = _nl_socket_alloc();
+
+	if (!sk)
+		return NULL;
+
+	sk->s_cb = cb;
+	nl_cb_get(cb);
+
+	return sk;
+}
+
+/* Free a netlink socket. */
+void nl_socket_free(struct nl_sock *sk)
+{
+	nl_cb_put(sk->s_cb);
+	close(sk->s_fd);
+	free(sk);
+}
+
+/* Sets socket buffer size of netlink socket */
+int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
+{
+	if (setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF, \
+			&rxbuf, (socklen_t) sizeof(rxbuf)))
+		goto error;
+
+	if (setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF, \
+			&txbuf, (socklen_t) sizeof(txbuf)))
+		goto error;
+
+	return 0;
+error:
+	return -errno;
+
+}
+
+int nl_socket_get_fd(struct nl_sock *sk)
+{
+	return sk->s_fd;
+}
+
+void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
+{
+	nl_cb_put(sk->s_cb);
+	sk->s_cb = cb;
+	nl_cb_get(cb);
+}
+
+struct nl_cb *nl_socket_get_cb(struct nl_sock *sk)
+{
+	return nl_cb_get(sk->s_cb);
+}